200 lines
6.2 KiB
Java
200 lines
6.2 KiB
Java
package dev.kske.chess.board;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import dev.kske.chess.board.Piece.Color;
|
|
|
|
/**
|
|
* Project: <strong>Chess</strong><br>
|
|
* File: <strong>Log.java</strong><br>
|
|
* Created: <strong>09.07.2019</strong><br>
|
|
* Author: <strong>Kai S. K. Engelbart</strong>
|
|
*/
|
|
public class Log {
|
|
|
|
private MoveNode root, current;
|
|
|
|
private Position enPassant;
|
|
private Color activeColor;
|
|
private int fullmoveCounter, halfmoveClock;
|
|
|
|
public Log() {
|
|
reset();
|
|
}
|
|
|
|
/**
|
|
* 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 copyVariations If set to {@code true}, subsequent variations of the
|
|
* current {@link MoveNode} are copied with the
|
|
* {@link Log}
|
|
*/
|
|
public Log(Log other, boolean copyVariations) {
|
|
enPassant = other.enPassant;
|
|
activeColor = other.activeColor;
|
|
fullmoveCounter = other.fullmoveCounter;
|
|
halfmoveClock = other.halfmoveClock;
|
|
|
|
// The new root is the current node of the copied instance
|
|
if (!other.isEmpty()) {
|
|
root = new MoveNode(other.current, copyVariations);
|
|
root.parent = null;
|
|
current = root;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a move to the move history and adjusts the log to the new position.
|
|
*
|
|
* @param move The move to log
|
|
* @param capturedPiece The piece captured with the move
|
|
* @param pawnMove {@code true} if the move was made by a pawn
|
|
*/
|
|
public void add(Move move, Piece capturedPiece, boolean pawnMove) {
|
|
enPassant = pawnMove && move.yDist == 2 ? new Position(move.pos.x, move.pos.y + move.ySign) : null;
|
|
if (activeColor == Color.BLACK) ++fullmoveCounter;
|
|
if (pawnMove || capturedPiece != null) halfmoveClock = 0;
|
|
else++halfmoveClock;
|
|
activeColor = activeColor.opposite();
|
|
final MoveNode leaf = new MoveNode(move, capturedPiece, enPassant, activeColor, fullmoveCounter, halfmoveClock);
|
|
|
|
if (isEmpty()) {
|
|
root = leaf;
|
|
current = leaf;
|
|
} else {
|
|
current.addVariation(leaf);
|
|
current = leaf;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removed the last move from the log and adjusts its state to the previous
|
|
* move.
|
|
*/
|
|
public void removeLast() {
|
|
if (!isEmpty() && current.parent != null) {
|
|
current.parent.variations.remove(current);
|
|
current = current.parent;
|
|
activeColor = current.activeColor;
|
|
enPassant = current.enPassant;
|
|
fullmoveCounter = current.fullmoveCounter;
|
|
halfmoveClock = current.halfmoveClock;
|
|
} else reset();
|
|
}
|
|
|
|
public boolean isEmpty() { return root == null; }
|
|
|
|
/**
|
|
* Reverts the log to its initial state corresponding to the default board
|
|
* position.
|
|
*/
|
|
public void reset() {
|
|
root = null;
|
|
current = null;
|
|
enPassant = null;
|
|
activeColor = Color.WHITE;
|
|
fullmoveCounter = 1;
|
|
halfmoveClock = 0;
|
|
}
|
|
|
|
/**
|
|
* @return The first logged move, or {@code null} if there is none
|
|
*/
|
|
public MoveNode getRoot() { return root; }
|
|
|
|
/**
|
|
* @return the last logged move, or {@code null} if there is none
|
|
*/
|
|
public MoveNode getLast() { return current; }
|
|
|
|
public Position getEnPassant() { return enPassant; }
|
|
|
|
public void setEnPassant(Position enPassant) { this.enPassant = enPassant; }
|
|
|
|
public Color getActiveColor() { return activeColor; }
|
|
|
|
public void setActiveColor(Color activeColor) { this.activeColor = activeColor; }
|
|
|
|
public int getFullmoveCounter() { return fullmoveCounter; }
|
|
|
|
public void setFullmoveCounter(int fullmoveCounter) { this.fullmoveCounter = fullmoveCounter; }
|
|
|
|
public int getHalfmoveClock() { return halfmoveClock; }
|
|
|
|
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
|
|
|
|
public static class MoveNode {
|
|
|
|
public final Move move;
|
|
public final Piece capturedPiece;
|
|
public final Position enPassant;
|
|
public final Color activeColor;
|
|
public final int fullmoveCounter, halfmoveClock;
|
|
|
|
private MoveNode parent;
|
|
private List<MoveNode> variations;
|
|
|
|
/**
|
|
* Creates a new {@link MoveNode}.
|
|
*
|
|
* @param move The logged {@link Move}
|
|
* @param capturedPiece The {@link Piece} captures by the logged {@link Move}
|
|
* @param enPassant The en passant {@link Position} valid after the logged
|
|
* {@link Move}, or {@code null} if there is none
|
|
* @param activeColor The {@link Color} active after the logged {@link Move}
|
|
* @param fullmoveCounter
|
|
* @param halfmoveClock
|
|
*/
|
|
public MoveNode(Move move, Piece capturedPiece, Position enPassant, Color activeColor, int fullmoveCounter,
|
|
int halfmoveClock) {
|
|
this.move = move;
|
|
this.capturedPiece = capturedPiece;
|
|
this.enPassant = enPassant;
|
|
this.activeColor = activeColor;
|
|
this.fullmoveCounter = fullmoveCounter;
|
|
this.halfmoveClock = halfmoveClock;
|
|
}
|
|
|
|
/**
|
|
* Creates a (deep) copy of another {@link MoveNode}.
|
|
*
|
|
* @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, boolean copyVariations) {
|
|
this(other.move, other.capturedPiece, other.enPassant, other.activeColor, other.fullmoveCounter,
|
|
other.halfmoveClock);
|
|
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);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds another {@link MoveNode} as a child node.
|
|
*
|
|
* @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; }
|
|
}
|
|
} |