228 lines
6.0 KiB
Java
228 lines
6.0 KiB
Java
package dev.kske.chess.board;
|
|
|
|
import java.util.*;
|
|
|
|
import dev.kske.chess.board.Piece.Color;
|
|
|
|
/**
|
|
* Project: <strong>Chess</strong><br>
|
|
* File: <strong>MoveNode.java</strong><br>
|
|
* Created: <strong>02.10.2019</strong><br>
|
|
*
|
|
* @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<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 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<MoveNode> 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);
|
|
}
|
|
}
|