package dev.kske.chess.board; import java.util.*; import dev.kske.chess.board.Piece.Color; /** * Project: Chess
* File: MoveNode.java
* Created: 02.10.2019
* * @since Chess v0.5-alpha * @author Kai S. K. Engelbart */ public class MoveNode { /** * The index of the white kingside casting in a casting rights array. */ public static final int WHITE_KINGSIDE = 0; /** * The index of the white queenside castling in a castling rights array. */ public static final int WHITE_QUEENSIDE = 1; /** * The index of the white kingside casting in a casting rights array. */ public static final int BLACK_KINGSIDE = 2; /** * The index of the white queenside castling in a castling rights array. */ public static final int BLACK_QUEENSIDE = 3; /** * The move on the board associated with this move node. */ public final Move move; /** * The piece captured by the move. */ public final Piece capturedPiece; /** * The castling rights present during the move. */ public final boolean[] castlingRights; /** * The en passant target position or {@code null} if the move is not an en * passant move. */ public final Position enPassant; /** * The color active during the move. */ public final Color activeColor; /** * The number of moves performed since the beginning of the game. */ public final int fullmoveCounter; /** * The halfmoves performed since the last capture move or pawn move. */ public final int halfmoveClock; private MoveNode parent; private List variations; /** * Creates a new {@link MoveNode}. * * @param move the logged {@link Move} * @param capturedPiece the {@link Piece} captures by the logged * {@link Move} * @param castlingRights the castling rights present during the 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 the number of moves made until the current move * @param halfmoveClock the number of halfmoves since the last capture * move or * pawn move */ public MoveNode( Move move, Piece capturedPiece, boolean castlingRights[], Position enPassant, Color activeColor, int fullmoveCounter, int halfmoveClock ) { this.move = move; this.capturedPiece = capturedPiece; this.castlingRights = castlingRights; 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.castlingRights.clone(), other.enPassant, other.activeColor, other.fullmoveCounter, other.halfmoveClock ); if (copyVariations && other.variations != null) { if (variations == null) variations = new ArrayList<>(); for (MoveNode variation : other.variations) { 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 getVariations() { return variations; } /** * @return {@code true} if this move node has any variations */ public boolean hasVariations() { return variations != null && variations.size() > 0; } /** * @return the parent node of this move node */ public MoveNode getParent() { return parent; } /** * Sets the parent node of this move node * * @param parent the parent node to set */ public void setParent(MoveNode parent) { this.parent = parent; } /** * @return {@code true} if this move node has a parent */ public boolean hasParent() { return parent != null; } @Override public String toString() { return String.format( "MoveNode[move=%s,capturedPiece=%s,castlingRights=%s,enPassant=%s,activeColor=%s,fullmoveCounter=%d,halfmoveClock=%d]", move, capturedPiece, Arrays.toString(castlingRights), enPassant, activeColor, fullmoveCounter, halfmoveClock ); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(castlingRights); result = prime * result + Objects.hash( activeColor, capturedPiece, enPassant, fullmoveCounter, halfmoveClock, move ); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; MoveNode other = (MoveNode) obj; return activeColor == other.activeColor && Objects.equals(capturedPiece, other.capturedPiece) && Arrays.equals(castlingRights, other.castlingRights) && Objects.equals(enPassant, other.enPassant) && fullmoveCounter == other.fullmoveCounter && halfmoveClock == other.halfmoveClock && Objects.equals(move, other.move); } }