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>
|
* Created: <strong>01.07.2019</strong><br>
|
||||||
* Author: <strong>Kai S. K. Engelbart</strong>
|
* Author: <strong>Kai S. K. Engelbart</strong>
|
||||||
*/
|
*/
|
||||||
public class Board implements Cloneable {
|
public class Board {
|
||||||
|
|
||||||
private Piece[][] boardArr = new Piece[8][8];
|
private Piece[][] boardArr = new Piece[8][8];
|
||||||
private Map<Color, Position> kingPos = new HashMap<>();
|
private Map<Color, Position> kingPos = new HashMap<>();
|
||||||
@ -75,6 +75,30 @@ public class Board implements Cloneable {
|
|||||||
initFromFEN(fen);
|
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.
|
* Moves a piece across the board if the move is legal.
|
||||||
*
|
*
|
||||||
@ -523,33 +547,6 @@ public class Board implements Cloneable {
|
|||||||
return sb.toString();
|
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
|
* @param pos The position from which to return a piece
|
||||||
* @return The piece at the position
|
* @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
|
* Creates a (partially deep) copy of another {@link Log} instance which begins
|
||||||
* the current node.
|
* 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;
|
enPassant = other.enPassant;
|
||||||
activeColor = other.activeColor;
|
activeColor = other.activeColor;
|
||||||
fullmoveCounter = other.fullmoveCounter;
|
fullmoveCounter = other.fullmoveCounter;
|
||||||
@ -37,7 +40,7 @@ public class Log {
|
|||||||
|
|
||||||
// The new root is the current node of the copied instance
|
// The new root is the current node of the copied instance
|
||||||
if (!other.isEmpty()) {
|
if (!other.isEmpty()) {
|
||||||
root = new MoveNode(other.current);
|
root = new MoveNode(other.current, copyVariations);
|
||||||
root.parent = null;
|
root.parent = null;
|
||||||
current = root;
|
current = root;
|
||||||
}
|
}
|
||||||
@ -73,6 +76,7 @@ public class Log {
|
|||||||
*/
|
*/
|
||||||
public void removeLast() {
|
public void removeLast() {
|
||||||
if (!isEmpty() && current.parent != null) {
|
if (!isEmpty() && current.parent != null) {
|
||||||
|
current.parent.variations.remove(current);
|
||||||
current = current.parent;
|
current = current.parent;
|
||||||
activeColor = current.activeColor;
|
activeColor = current.activeColor;
|
||||||
enPassant = current.enPassant;
|
enPassant = current.enPassant;
|
||||||
@ -131,10 +135,10 @@ public class Log {
|
|||||||
public final int fullmoveCounter, halfmoveClock;
|
public final int fullmoveCounter, halfmoveClock;
|
||||||
|
|
||||||
private MoveNode parent;
|
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 move The logged {@link Move}
|
||||||
* @param capturedPiece The {@link Piece} captures by the logged {@link Move}
|
* @param capturedPiece The {@link Piece} captures by the logged {@link Move}
|
||||||
@ -155,19 +159,25 @@ 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,
|
this(other.move, other.capturedPiece, other.enPassant, other.activeColor, other.fullmoveCounter,
|
||||||
other.halfmoveClock);
|
other.halfmoveClock);
|
||||||
|
if (copyVariations && other.variations != null) {
|
||||||
|
if (variations == null) variations = new ArrayList<>();
|
||||||
other.variations.forEach(variation -> {
|
other.variations.forEach(variation -> {
|
||||||
MoveNode copy = new MoveNode(variation);
|
MoveNode copy = new MoveNode(variation, true);
|
||||||
copy.parent = this;
|
copy.parent = this;
|
||||||
variations.add(copy);
|
variations.add(copy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds another {@link MoveNode} as a child node.
|
* Adds another {@link MoveNode} as a child node.
|
||||||
@ -175,10 +185,16 @@ public class Log {
|
|||||||
* @param variation The {@link MoveNode} to append to this {@link MoveNode}
|
* @param variation The {@link MoveNode} to append to this {@link MoveNode}
|
||||||
*/
|
*/
|
||||||
public void addVariation(MoveNode variation) {
|
public void addVariation(MoveNode variation) {
|
||||||
|
if (variations == null) variations = new ArrayList<>();
|
||||||
if (!variations.contains(variation)) {
|
if (!variations.contains(variation)) {
|
||||||
variations.add(variation);
|
variations.add(variation);
|
||||||
variation.parent = this;
|
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();
|
boardComponent.repaint();
|
||||||
overlayComponent.displayArrow(move);
|
overlayComponent.displayArrow(move);
|
||||||
|
|
||||||
|
// Run garbage collection
|
||||||
|
System.gc();
|
||||||
|
|
||||||
System.out.printf("%s: %s%n", player.color, move);
|
System.out.printf("%s: %s%n", player.color, move);
|
||||||
System.out.println("FEN: " + board.toFEN());
|
System.out.println("FEN: " + board.toFEN());
|
||||||
EventBus.getInstance().dispatch(new MoveEvent(move));
|
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(),
|
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(),
|
||||||
evt.getPoint().y / 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) {
|
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
||||||
List<Position> positions = board.getMoves(pos)
|
List<Position> positions = board.getMoves(pos)
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -50,7 +50,7 @@ public class AIPlayer extends Player {
|
|||||||
/*
|
/*
|
||||||
* Get a copy of the board and the available moves.
|
* 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);
|
List<Move> moves = board.getMoves(color);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -64,7 +64,7 @@ public class AIPlayer extends Player {
|
|||||||
for (int i = 0; i < numThreads; i++) {
|
for (int i = 0; i < numThreads; i++) {
|
||||||
if (rem-- > 0) ++endIndex;
|
if (rem-- > 0) ++endIndex;
|
||||||
endIndex += step;
|
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));
|
maxDepth, alphaBetaThreshold));
|
||||||
beginIndex = endIndex;
|
beginIndex = endIndex;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,7 @@ import static org.junit.Assert.assertNotSame;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
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.Piece.Color;
|
||||||
import dev.kske.chess.board.Queen;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -34,7 +31,7 @@ class BoardTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testClone() {
|
void testClone() {
|
||||||
Board clone = (Board) board.clone();
|
Board clone = new Board(board);
|
||||||
assertNotSame(clone, board);
|
assertNotSame(clone, board);
|
||||||
assertNotSame(clone.getBoardArr(), board.getBoardArr());
|
assertNotSame(clone.getBoardArr(), board.getBoardArr());
|
||||||
|
|
||||||
|
@ -39,10 +39,16 @@ class LogTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testClone() {
|
void testClone() {
|
||||||
Log other = new Log(log);
|
Log other = new Log(log, false);
|
||||||
log.setActiveColor(Color.WHITE);
|
log.setActiveColor(Color.WHITE);
|
||||||
other.setActiveColor(Color.BLACK);
|
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