Fixed memory leak, improved copy constructors
This commit is contained in:
parent
06ab01f585
commit
69261303c5
@ -15,7 +15,7 @@ import dev.kske.chess.board.Piece.Type;
|
||||
* Created: <strong>01.07.2019</strong><br>
|
||||
* Author: <strong>Kai S. K. Engelbart</strong>
|
||||
*/
|
||||
public class Board implements Cloneable {
|
||||
public class Board {
|
||||
|
||||
private Piece[][] boardArr = new Piece[8][8];
|
||||
private Map<Color, Position> kingPos = new HashMap<>();
|
||||
@ -75,6 +75,30 @@ public class Board implements Cloneable {
|
||||
initFromFEN(fen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of another {@link Board} instance.<br>
|
||||
* The created object is a deep copy, but does not contain any move history
|
||||
* apart from the current {@link MoveNode}.
|
||||
*
|
||||
* @param other The {@link Board} instance to copy
|
||||
*/
|
||||
public Board(Board other) {
|
||||
boardArr = new Piece[8][8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (other.boardArr[i][j] == null) continue;
|
||||
boardArr[i][j] = (Piece) other.boardArr[i][j].clone();
|
||||
boardArr[i][j].board = this;
|
||||
}
|
||||
|
||||
kingPos.putAll(other.kingPos);
|
||||
Map<Type, Boolean> whiteCastling = new HashMap<>(other.castlingRights.get(Color.WHITE)),
|
||||
blackCastling = new HashMap<>(other.castlingRights.get(Color.BLACK));
|
||||
castlingRights.put(Color.WHITE, whiteCastling);
|
||||
castlingRights.put(Color.BLACK, blackCastling);
|
||||
log = new Log(other.log, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a piece across the board if the move is legal.
|
||||
*
|
||||
@ -523,33 +547,6 @@ public class Board implements Cloneable {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A new instance of this class with a shallow copy of both
|
||||
* {@code kingPos} and {code boardArr}
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
Board board = null;
|
||||
try {
|
||||
board = (Board) super.clone();
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
board.boardArr = new Piece[8][8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (boardArr[i][j] == null) continue;
|
||||
board.boardArr[i][j] = (Piece) boardArr[i][j].clone();
|
||||
board.boardArr[i][j].board = board;
|
||||
}
|
||||
|
||||
board.kingPos = new HashMap<>();
|
||||
board.kingPos.putAll(kingPos);
|
||||
board.log = new Log(log);
|
||||
|
||||
return board;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pos The position from which to return a piece
|
||||
* @return The piece at the position
|
||||
|
@ -24,12 +24,15 @@ public class Log {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a partial deep copy of another {@link Log} instance which begins with
|
||||
* the current node.
|
||||
* Creates a (partially deep) copy of another {@link Log} instance which begins
|
||||
* with the current {@link MoveNode}.
|
||||
*
|
||||
* @param other The {@link Log} instance to copy
|
||||
* @param other The {@link Log} instance to copy
|
||||
* @param copyVariations If set to {@code true}, subsequent variations of the
|
||||
* current {@link MoveNode} are copied with the
|
||||
* {@link Log}
|
||||
*/
|
||||
public Log(Log other) {
|
||||
public Log(Log other, boolean copyVariations) {
|
||||
enPassant = other.enPassant;
|
||||
activeColor = other.activeColor;
|
||||
fullmoveCounter = other.fullmoveCounter;
|
||||
@ -37,7 +40,7 @@ public class Log {
|
||||
|
||||
// The new root is the current node of the copied instance
|
||||
if (!other.isEmpty()) {
|
||||
root = new MoveNode(other.current);
|
||||
root = new MoveNode(other.current, copyVariations);
|
||||
root.parent = null;
|
||||
current = root;
|
||||
}
|
||||
@ -73,6 +76,7 @@ public class Log {
|
||||
*/
|
||||
public void removeLast() {
|
||||
if (!isEmpty() && current.parent != null) {
|
||||
current.parent.variations.remove(current);
|
||||
current = current.parent;
|
||||
activeColor = current.activeColor;
|
||||
enPassant = current.enPassant;
|
||||
@ -131,10 +135,10 @@ public class Log {
|
||||
public final int fullmoveCounter, halfmoveClock;
|
||||
|
||||
private MoveNode parent;
|
||||
private List<MoveNode> variations = new ArrayList<>();
|
||||
private List<MoveNode> variations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MoveNode}
|
||||
* Creates a new {@link MoveNode}.
|
||||
*
|
||||
* @param move The logged {@link Move}
|
||||
* @param capturedPiece The {@link Piece} captures by the logged {@link Move}
|
||||
@ -155,18 +159,24 @@ public class Log {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deep copy of another {@link MoveNode}.
|
||||
* Creates a (deep) copy of another {@link MoveNode}.
|
||||
*
|
||||
* @param other The {@link MoveNode} to copy
|
||||
* @param other The {@link MoveNode} to copy
|
||||
* @param copyVariations When this is set to {@code true} a deep copy is
|
||||
* created, which
|
||||
* considers subsequent variations
|
||||
*/
|
||||
public MoveNode(MoveNode other) {
|
||||
public MoveNode(MoveNode other, boolean copyVariations) {
|
||||
this(other.move, other.capturedPiece, other.enPassant, other.activeColor, other.fullmoveCounter,
|
||||
other.halfmoveClock);
|
||||
other.variations.forEach(variation -> {
|
||||
MoveNode copy = new MoveNode(variation);
|
||||
copy.parent = this;
|
||||
variations.add(copy);
|
||||
});
|
||||
if (copyVariations && other.variations != null) {
|
||||
if (variations == null) variations = new ArrayList<>();
|
||||
other.variations.forEach(variation -> {
|
||||
MoveNode copy = new MoveNode(variation, true);
|
||||
copy.parent = this;
|
||||
variations.add(copy);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,10 +185,16 @@ public class Log {
|
||||
* @param variation The {@link MoveNode} to append to this {@link MoveNode}
|
||||
*/
|
||||
public void addVariation(MoveNode variation) {
|
||||
if (variations == null) variations = new ArrayList<>();
|
||||
if (!variations.contains(variation)) {
|
||||
variations.add(variation);
|
||||
variation.parent = this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of all variations associated with this {@link MoveNode}
|
||||
*/
|
||||
public List<MoveNode> getVariations() { return variations; }
|
||||
}
|
||||
}
|
@ -77,6 +77,9 @@ public class Game {
|
||||
boardComponent.repaint();
|
||||
overlayComponent.displayArrow(move);
|
||||
|
||||
// Run garbage collection
|
||||
System.gc();
|
||||
|
||||
System.out.printf("%s: %s%n", player.color, move);
|
||||
System.out.println("FEN: " + board.toFEN());
|
||||
EventBus.getInstance().dispatch(new MoveEvent(move));
|
||||
|
@ -56,7 +56,7 @@ public class NaturalPlayer extends Player implements MouseListener {
|
||||
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(),
|
||||
evt.getPoint().y / overlayComponent.getTileSize());
|
||||
|
||||
Board board = (Board) NaturalPlayer.this.board.clone();
|
||||
Board board = new Board(this.board);
|
||||
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
||||
List<Position> positions = board.getMoves(pos)
|
||||
.stream()
|
||||
|
@ -50,7 +50,7 @@ public class AIPlayer extends Player {
|
||||
/*
|
||||
* Get a copy of the board and the available moves.
|
||||
*/
|
||||
Board board = (Board) AIPlayer.this.board.clone();
|
||||
Board board = new Board(this.board);
|
||||
List<Move> moves = board.getMoves(color);
|
||||
|
||||
/*
|
||||
@ -64,7 +64,7 @@ public class AIPlayer extends Player {
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
if (rem-- > 0) ++endIndex;
|
||||
endIndex += step;
|
||||
processors.add(new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color,
|
||||
processors.add(new MoveProcessor(new Board(board), moves.subList(beginIndex, endIndex), color,
|
||||
maxDepth, alphaBetaThreshold));
|
||||
beginIndex = endIndex;
|
||||
}
|
||||
|
@ -6,10 +6,7 @@ import static org.junit.Assert.assertNotSame;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import dev.kske.chess.board.Board;
|
||||
import dev.kske.chess.board.Move;
|
||||
import dev.kske.chess.board.Piece.Color;
|
||||
import dev.kske.chess.board.Queen;
|
||||
|
||||
/**
|
||||
* Project: <strong>Chess</strong><br>
|
||||
@ -34,7 +31,7 @@ class BoardTest {
|
||||
*/
|
||||
@Test
|
||||
void testClone() {
|
||||
Board clone = (Board) board.clone();
|
||||
Board clone = new Board(board);
|
||||
assertNotSame(clone, board);
|
||||
assertNotSame(clone.getBoardArr(), board.getBoardArr());
|
||||
|
||||
|
@ -39,10 +39,16 @@ class LogTest {
|
||||
*/
|
||||
@Test
|
||||
void testClone() {
|
||||
Log other = new Log(log);
|
||||
Log other = new Log(log, false);
|
||||
log.setActiveColor(Color.WHITE);
|
||||
other.setActiveColor(Color.BLACK);
|
||||
assertNotEquals(other.getActiveColor(), log.getActiveColor());
|
||||
assertNotEquals(log.getActiveColor(), other.getActiveColor());
|
||||
log.add(Move.fromSAN("a2a4"), null, true);
|
||||
log.add(Move.fromSAN("a4a5"), null, true);
|
||||
other.add(Move.fromSAN("a2a4"), null, true);
|
||||
other.add(Move.fromSAN("a4a5"), null, true);
|
||||
assertNotEquals(log.getRoot(), other.getRoot());
|
||||
assertNotEquals(log.getRoot().getVariations(), other.getRoot().getVariations());
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user