Refined IO functionality, fixed FEN string serialization and deserialization #7
@ -22,7 +22,6 @@ 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<>();
|
||||||
private Map<Color, Map<Type, Boolean>> castlingRights = new HashMap<>();
|
|
||||||
private Log log = new Log();
|
private Log log = new Log();
|
||||||
|
|
||||||
private static final Map<Type, int[][]> positionScores;
|
private static final Map<Type, int[][]> positionScores;
|
||||||
@ -30,53 +29,46 @@ public class Board {
|
|||||||
static {
|
static {
|
||||||
positionScores = new HashMap<>();
|
positionScores = new HashMap<>();
|
||||||
positionScores.put(Type.KING,
|
positionScores.put(Type.KING,
|
||||||
new int[][] { new int[] { -3, -4, -4, -5, -5, -4, -4, -3 },
|
new int[][] { new int[] { -3, -4, -4, -5, -5, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 },
|
||||||
new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 },
|
new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 },
|
||||||
new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -2, -3, -3, -2, -2, -2, -2, -1 },
|
new int[] { -2, -3, -3, -2, -2, -2, -2, -1 }, new int[] { -1, -2, -2, -2, -2, -2, -2, -1 },
|
||||||
new int[] { -1, -2, -2, -2, -2, -2, -2, -1 }, new int[] { 2, 2, 0, 0, 0, 0, 2, 2 },
|
new int[] { 2, 2, 0, 0, 0, 0, 2, 2 }, new int[] { 2, 3, 1, 0, 0, 1, 3, 2 } });
|
||||||
new int[] { 2, 3, 1, 0, 0, 1, 3, 2 } });
|
|
||||||
positionScores.put(Type.QUEEN,
|
positionScores.put(Type.QUEEN,
|
||||||
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, -2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, -2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
||||||
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 },
|
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { 0, 0, 1, 1, 1, 1, 0, -1 },
|
||||||
new int[] { 0, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 0, -1 },
|
new int[] { -1, 1, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 0, 0, 0, 0, -1 },
|
||||||
new int[] { -1, 0, 1, 0, 0, 0, 0, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
|
new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
|
||||||
positionScores.put(Type.ROOK,
|
positionScores.put(Type.ROOK,
|
||||||
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 },
|
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
||||||
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
||||||
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
|
||||||
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { 0, 0, 0, 1, 1, 0, 0, 0 } });
|
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { 0, 0, 0, 1, 1, 0, 0, 0 } });
|
||||||
positionScores.put(Type.KNIGHT,
|
positionScores.put(Type.KNIGHT,
|
||||||
new int[][] { new int[] { -5, -4, -3, -3, -3, -3, -4, -5 }, new int[] { -4, -2, 0, 0, 0, 0, -2, -4 },
|
new int[][] { new int[] { -5, -4, -3, -3, -3, -3, -4, -5 }, new int[] { -4, -2, 0, 0, 0, 0, -2, -4 },
|
||||||
new int[] { -3, 0, 1, 2, 2, 1, 0, -3 }, new int[] { -3, 1, 2, 2, 2, 2, 1, -3 },
|
new int[] { -3, 0, 1, 2, 2, 1, 0, -3 }, new int[] { -3, 1, 2, 2, 2, 2, 1, -3 }, new int[] { -3, 0, 2, 2, 2, 2, 0, -1 },
|
||||||
new int[] { -3, 0, 2, 2, 2, 2, 0, -1 }, new int[] { -3, 1, 1, 2, 2, 1, 1, -3 },
|
new int[] { -3, 1, 1, 2, 2, 1, 1, -3 }, new int[] { -4, -2, 0, 1, 1, 0, -2, -4 },
|
||||||
new int[] { -4, -2, 0, 1, 1, 0, -2, -4 }, new int[] { -5, -4, -3, -3, -3, -3, -4, -5 } });
|
new int[] { -5, -4, -3, -3, -3, -3, -4, -5 } });
|
||||||
positionScores.put(Type.BISHOP,
|
positionScores.put(Type.BISHOP,
|
||||||
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, 2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, 2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
|
||||||
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 },
|
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 },
|
||||||
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 },
|
new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 1, 0, 0, 0, 0, 1, -1 },
|
||||||
new int[] { -1, 1, 0, 0, 0, 0, 1, -1 }, new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
|
new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
|
||||||
positionScores.put(Type.PAWN,
|
positionScores.put(Type.PAWN,
|
||||||
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 5, 5, 5, 5, 5, 5, 5, 5 },
|
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 5, 5, 5, 5, 5, 5, 5, 5 }, new int[] { 1, 1, 2, 3, 3, 2, 1, 1 },
|
||||||
new int[] { 1, 1, 2, 3, 3, 2, 1, 1 }, new int[] { 0, 0, 1, 3, 3, 1, 0, 0 },
|
new int[] { 0, 0, 1, 3, 3, 1, 0, 0 }, new int[] { 0, 0, 0, 2, 2, 0, 0, 0 }, new int[] { 0, 0, -1, 0, 0, -1, 0, 0 },
|
||||||
new int[] { 0, 0, 0, 2, 2, 0, 0, 0 }, new int[] { 0, 0, -1, 0, 0, -1, 0, 0 },
|
|
||||||
new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } });
|
new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the board with the default chess starting position.
|
* Initializes the board with the default chess starting position.
|
||||||
*/
|
*/
|
||||||
public Board() {
|
public Board() { initDefaultPositions(); }
|
||||||
initDefaultPositions();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the board with data from a FEN-string.
|
* Initializes the board with data from a FEN-string.
|
||||||
*
|
*
|
||||||
* @param fen The FEN-string to initialize the board from
|
* @param fen The FEN-string to initialize the board from
|
||||||
*/
|
*/
|
||||||
public Board(String fen) {
|
public Board(String fen) { initFromFEN(fen); }
|
||||||
initFromFEN(fen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a copy of another {@link Board} instance.<br>
|
* Creates a copy of another {@link Board} instance.<br>
|
||||||
@ -95,10 +87,6 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kingPos.putAll(other.kingPos);
|
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);
|
log = new Log(other.log, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,8 +146,6 @@ public class Board {
|
|||||||
: new Move(0, move.pos.y, 3, move.pos.y); // Queenside
|
: new Move(0, move.pos.y, 3, move.pos.y); // Queenside
|
||||||
setDest(rookMove, getPos(rookMove));
|
setDest(rookMove, getPos(rookMove));
|
||||||
setPos(rookMove, null);
|
setPos(rookMove, null);
|
||||||
|
|
||||||
getDest(rookMove).incMoveCounter();
|
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
System.err.printf("Move of unknown type %s found!%n", move);
|
System.err.printf("Move of unknown type %s found!%n", move);
|
||||||
@ -171,17 +157,11 @@ public class Board {
|
|||||||
System.err.printf("Move %s of unimplemented type found!%n", move);
|
System.err.printf("Move %s of unimplemented type found!%n", move);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment move counter
|
// Update the king's position if the moved piece is the king
|
||||||
getDest(move).incMoveCounter();
|
|
||||||
|
|
||||||
// Update the king's position if the moved piece is the king and castling
|
|
||||||
// availability
|
|
||||||
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest);
|
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest);
|
||||||
|
|
||||||
// Update log
|
// Update log
|
||||||
log.add(move, capturePiece, piece.getType() == Type.PAWN);
|
log.add(move, piece, capturePiece);
|
||||||
|
|
||||||
updateCastlingRights();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,9 +175,7 @@ public class Board {
|
|||||||
Pattern.compile(
|
Pattern.compile(
|
||||||
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
||||||
patterns.put("pawnCapture",
|
patterns.put("pawnCapture",
|
||||||
Pattern
|
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)?$"));
|
||||||
.compile(
|
|
||||||
"^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)?$"));
|
|
||||||
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)$"));
|
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)$"));
|
||||||
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
||||||
|
|
||||||
@ -228,8 +206,7 @@ public class Board {
|
|||||||
case "pawnCapture":
|
case "pawnCapture":
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
char file = m.group("fromFile").charAt(0);
|
char file = m.group("fromFile").charAt(0);
|
||||||
int rank = m.group("fromRank") == null ? get(Type.PAWN, file)
|
int rank = m.group("fromRank") == null ? get(Type.PAWN, file) : Integer.parseInt(m.group("fromRank"));
|
||||||
: Integer.parseInt(m.group("fromRank"));
|
|
||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
break;
|
break;
|
||||||
case "pawnPush":
|
case "pawnPush":
|
||||||
@ -282,8 +259,6 @@ public class Board {
|
|||||||
: new Move(3, move.pos.y, 0, move.pos.y); // Queenside
|
: new Move(3, move.pos.y, 0, move.pos.y); // Queenside
|
||||||
setDest(rookMove, getPos(rookMove));
|
setDest(rookMove, getPos(rookMove));
|
||||||
setPos(rookMove, null);
|
setPos(rookMove, null);
|
||||||
|
|
||||||
getDest(rookMove).decMoveCounter();
|
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
System.err.printf("Move of unknown type %s found!%n", move);
|
System.err.printf("Move of unknown type %s found!%n", move);
|
||||||
@ -295,38 +270,11 @@ public class Board {
|
|||||||
System.err.printf("Move %s of unimplemented type found!%n", move);
|
System.err.printf("Move %s of unimplemented type found!%n", move);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement move counter
|
|
||||||
getPos(move).decMoveCounter();
|
|
||||||
|
|
||||||
// Update the king's position if the moved piece is the king
|
// Update the king's position if the moved piece is the king
|
||||||
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos);
|
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos);
|
||||||
|
|
||||||
// Update log
|
// Update log
|
||||||
log.removeLast();
|
log.removeLast();
|
||||||
|
|
||||||
updateCastlingRights();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCastlingRights() {
|
|
||||||
// White
|
|
||||||
if (new Position(4, 7).equals(kingPos.get(Color.WHITE))) {
|
|
||||||
final King king = (King) get(kingPos.get(Color.WHITE));
|
|
||||||
castlingRights.get(Color.WHITE).put(Type.KING, king.canCastleKingside());
|
|
||||||
castlingRights.get(Color.WHITE).put(Type.QUEEN, king.canCastleQueenside());
|
|
||||||
} else {
|
|
||||||
castlingRights.get(Color.WHITE).put(Type.KING, false);
|
|
||||||
castlingRights.get(Color.WHITE).put(Type.QUEEN, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Black
|
|
||||||
if (new Position(4, 0).equals(kingPos.get(Color.BLACK))) {
|
|
||||||
final King king = (King) get(kingPos.get(Color.BLACK));
|
|
||||||
castlingRights.get(Color.BLACK).put(Type.KING, king.canCastleKingside());
|
|
||||||
castlingRights.get(Color.BLACK).put(Type.QUEEN, king.canCastleQueenside());
|
|
||||||
} else {
|
|
||||||
castlingRights.get(Color.BLACK).put(Type.KING, false);
|
|
||||||
castlingRights.get(Color.BLACK).put(Type.QUEEN, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,14 +287,11 @@ public class Board {
|
|||||||
List<Move> moves = new ArrayList<>();
|
List<Move> moves = new ArrayList<>();
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
for (int j = 0; j < 8; j++)
|
for (int j = 0; j < 8; j++)
|
||||||
if (boardArr[i][j] != null && boardArr[i][j].getColor() == color)
|
if (boardArr[i][j] != null && boardArr[i][j].getColor() == color) moves.addAll(boardArr[i][j].getMoves(new Position(i, j)));
|
||||||
moves.addAll(boardArr[i][j].getMoves(new Position(i, j)));
|
|
||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Move> getMoves(Position pos) {
|
public List<Move> getMoves(Position pos) { return get(pos).getMoves(pos); }
|
||||||
return get(pos).getMoves(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks, if the king is in check.
|
* Checks, if the king is in check.
|
||||||
@ -358,9 +303,7 @@ public class Board {
|
|||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
Position pos = new Position(i, j);
|
Position pos = new Position(i, j);
|
||||||
if (get(pos) != null && get(pos).getColor() != color
|
if (get(pos) != null && get(pos).getColor() != color && get(pos).isValidMove(new Move(pos, kingPos.get(color)))) return true;
|
||||||
&& get(pos).isValidMove(new Move(pos, kingPos.get(color))))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -388,8 +331,7 @@ public class Board {
|
|||||||
|
|
||||||
public GameState getGameEventType(Color color) {
|
public GameState getGameEventType(Color color) {
|
||||||
return checkCheck(color) ? checkCheckmate(color) ? GameState.CHECKMATE : GameState.CHECK
|
return checkCheck(color) ? checkCheckmate(color) ? GameState.CHECKMATE : GameState.CHECK
|
||||||
: getMoves(color).isEmpty() || log.getLast().halfmoveClock >= 50 ? GameState.STALEMATE
|
: getMoves(color).isEmpty() || log.getLast().halfmoveClock >= 50 ? GameState.STALEMATE : GameState.NORMAL;
|
||||||
: GameState.NORMAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -471,15 +413,6 @@ public class Board {
|
|||||||
for (int j = 2; j < 6; j++)
|
for (int j = 2; j < 6; j++)
|
||||||
boardArr[i][j] = null;
|
boardArr[i][j] = null;
|
||||||
|
|
||||||
// Initialize castling rights
|
|
||||||
Map<Type, Boolean> whiteCastling = new HashMap<>(), blackCastling = new HashMap<>();
|
|
||||||
whiteCastling.put(Type.KING, true);
|
|
||||||
whiteCastling.put(Type.QUEEN, true);
|
|
||||||
blackCastling.put(Type.KING, true);
|
|
||||||
blackCastling.put(Type.QUEEN, true);
|
|
||||||
castlingRights.put(Color.WHITE, whiteCastling);
|
|
||||||
castlingRights.put(Color.BLACK, blackCastling);
|
|
||||||
|
|
||||||
log.reset();
|
log.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,9 +457,7 @@ public class Board {
|
|||||||
boardArr[j][i] = new Pawn(color, this);
|
boardArr[j][i] = new Pawn(color, this);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.printf("Unknown character '%c' in board declaration of FEN string '%s'%n",
|
System.err.printf("Unknown character '%c' in board declaration of FEN string '%s'%n", places[k], fen);
|
||||||
places[k],
|
|
||||||
fen);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,11 +481,10 @@ public class Board {
|
|||||||
case '-':
|
case '-':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err
|
System.err.printf("Unknown character '%c' in castling rights declaration of FEN string '%s'", c, fen);
|
||||||
.printf("Unknown character '%c' in castling rights declaration of FEN string '%s'", c, fen);
|
|
||||||
}
|
}
|
||||||
castlingRights.put(Color.WHITE, whiteCastling);
|
// castlingRights.put(Color.WHITE, whiteCastling);
|
||||||
castlingRights.put(Color.BLACK, blackCastling);
|
// castlingRights.put(Color.BLACK, blackCastling);
|
||||||
|
|
||||||
// En passant availability
|
// En passant availability
|
||||||
if (!parts[3].equals("-")) log.setEnPassant(Position.fromLAN(parts[3]));
|
if (!parts[3].equals("-")) log.setEnPassant(Position.fromLAN(parts[3]));
|
||||||
@ -597,10 +527,10 @@ public class Board {
|
|||||||
// Castling Rights
|
// Castling Rights
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
StringBuilder castlingSb = new StringBuilder();
|
StringBuilder castlingSb = new StringBuilder();
|
||||||
if (castlingRights.get(Color.WHITE).get(Type.KING)) castlingSb.append('K');
|
// if (castlingRights.get(Color.WHITE).get(Type.KING)) castlingSb.append('K');
|
||||||
if (castlingRights.get(Color.WHITE).get(Type.QUEEN)) castlingSb.append('Q');
|
// if (castlingRights.get(Color.WHITE).get(Type.QUEEN)) castlingSb.append('Q');
|
||||||
if (castlingRights.get(Color.BLACK).get(Type.KING)) castlingSb.append('k');
|
// if (castlingRights.get(Color.BLACK).get(Type.KING)) castlingSb.append('k');
|
||||||
if (castlingRights.get(Color.BLACK).get(Type.QUEEN)) castlingSb.append('q');
|
// if (castlingRights.get(Color.BLACK).get(Type.QUEEN)) castlingSb.append('q');
|
||||||
if (castlingSb.length() == 0) sb.append("-");
|
if (castlingSb.length() == 0) sb.append("-");
|
||||||
sb.append(castlingSb);
|
sb.append(castlingSb);
|
||||||
|
|
||||||
@ -623,7 +553,7 @@ public class Board {
|
|||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + Arrays.deepHashCode(boardArr);
|
result = prime * result + Arrays.deepHashCode(boardArr);
|
||||||
result = prime * result + Objects.hash(castlingRights, kingPos, log);
|
result = prime * result + Objects.hash(kingPos, log);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,17 +563,14 @@ public class Board {
|
|||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (getClass() != obj.getClass()) return false;
|
if (getClass() != obj.getClass()) return false;
|
||||||
Board other = (Board) obj;
|
Board other = (Board) obj;
|
||||||
return Arrays.deepEquals(boardArr, other.boardArr) && Objects.equals(castlingRights, other.castlingRights)
|
return Arrays.deepEquals(boardArr, other.boardArr) && Objects.equals(kingPos, other.kingPos) && Objects.equals(log, other.log);
|
||||||
&& Objects.equals(kingPos, other.kingPos) && Objects.equals(log, other.log);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
public Piece get(Position pos) {
|
public Piece get(Position pos) { return boardArr[pos.x][pos.y]; }
|
||||||
return boardArr[pos.x][pos.y];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for a {@link Piece} inside a file (A - H).
|
* Searches for a {@link Piece} inside a file (A - H).
|
||||||
@ -656,9 +583,7 @@ public class Board {
|
|||||||
public int get(Type type, char file) {
|
public int get(Type type, char file) {
|
||||||
int x = file - 97;
|
int x = file - 97;
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
if (boardArr[x][i] != null && boardArr[x][i].getType() == type
|
if (boardArr[x][i] != null && boardArr[x][i].getType() == type && boardArr[x][i].getColor() == log.getActiveColor()) return 8 - i;
|
||||||
&& boardArr[x][i].getColor() == log.getActiveColor())
|
|
||||||
return 8 - i;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,8 +598,7 @@ public class Board {
|
|||||||
public char get(Type type, int rank) {
|
public char get(Type type, int rank) {
|
||||||
int y = rank - 1;
|
int y = rank - 1;
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
if (boardArr[i][y] != null && boardArr[i][y].getType() == type
|
if (boardArr[i][y] != null && boardArr[i][y].getType() == type && boardArr[i][y].getColor() == log.getActiveColor())
|
||||||
&& boardArr[i][y].getColor() == log.getActiveColor())
|
|
||||||
return (char) (i + 97);
|
return (char) (i + 97);
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
@ -689,8 +613,7 @@ public class Board {
|
|||||||
public Position get(Type type, Position dest) {
|
public Position get(Type type, Position dest) {
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
for (int j = 0; j < 8; j++)
|
for (int j = 0; j < 8; j++)
|
||||||
if (boardArr[i][j] != null && boardArr[i][j].getType() == type
|
if (boardArr[i][j] != null && boardArr[i][j].getType() == type && boardArr[i][j].getColor() == log.getActiveColor()) {
|
||||||
&& boardArr[i][j].getColor() == log.getActiveColor()) {
|
|
||||||
Position pos = new Position(i, j);
|
Position pos = new Position(i, j);
|
||||||
if (boardArr[i][j].isValidMove(new Move(pos, dest))) return pos;
|
if (boardArr[i][j].isValidMove(new Move(pos, dest))) return pos;
|
||||||
}
|
}
|
||||||
@ -703,25 +626,19 @@ public class Board {
|
|||||||
* @param pos The position to place the piece at
|
* @param pos The position to place the piece at
|
||||||
* @param piece The piece to place
|
* @param piece The piece to place
|
||||||
*/
|
*/
|
||||||
public void set(Position pos, Piece piece) {
|
public void set(Position pos, Piece piece) { boardArr[pos.x][pos.y] = piece; }
|
||||||
boardArr[pos.x][pos.y] = piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param move The move from which position to return a piece
|
* @param move The move from which position to return a piece
|
||||||
* @return The piece at the position of the move
|
* @return The piece at the position of the move
|
||||||
*/
|
*/
|
||||||
public Piece getPos(Move move) {
|
public Piece getPos(Move move) { return get(move.pos); }
|
||||||
return get(move.pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param move The move from which destination to return a piece
|
* @param move The move from which destination to return a piece
|
||||||
* @return The piece at the destination of the move
|
* @return The piece at the destination of the move
|
||||||
*/
|
*/
|
||||||
public Piece getDest(Move move) {
|
public Piece getDest(Move move) { return get(move.dest); }
|
||||||
return get(move.dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places a piece at the position of a move.
|
* Places a piece at the position of a move.
|
||||||
@ -729,9 +646,7 @@ public class Board {
|
|||||||
* @param move The move at which position to place the piece
|
* @param move The move at which position to place the piece
|
||||||
* @param piece The piece to place
|
* @param piece The piece to place
|
||||||
*/
|
*/
|
||||||
public void setPos(Move move, Piece piece) {
|
public void setPos(Move move, Piece piece) { set(move.pos, piece); }
|
||||||
set(move.pos, piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places a piece at the destination of a move.
|
* Places a piece at the destination of a move.
|
||||||
@ -739,9 +654,7 @@ public class Board {
|
|||||||
* @param move The move at which destination to place the piece
|
* @param move The move at which destination to place the piece
|
||||||
* @param piece The piece to place
|
* @param piece The piece to place
|
||||||
*/
|
*/
|
||||||
public void setDest(Move move, Piece piece) {
|
public void setDest(Move move, Piece piece) { set(move.dest, piece); }
|
||||||
set(move.dest, piece);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The board array
|
* @return The board array
|
||||||
|
@ -109,7 +109,24 @@ public class FENString {
|
|||||||
// Active color
|
// Active color
|
||||||
board.getLog().setActiveColor(activeColor);
|
board.getLog().setActiveColor(activeColor);
|
||||||
|
|
||||||
// TODO: Castling availability
|
// Castling availability
|
||||||
|
boolean castlingRights[] = new boolean[4];
|
||||||
|
for (char c : castlingAvailability.toCharArray())
|
||||||
|
switch (c) {
|
||||||
|
case 'K':
|
||||||
|
castlingRights[MoveNode.WHITE_KINGSIDE] = true;
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
castlingRights[MoveNode.WHITE_QUEENSIDE] = true;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
castlingRights[MoveNode.BLACK_KINGSIDE] = true;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
castlingRights[MoveNode.BLACK_QUEENSIDE] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
board.getLog().setCastlingRights(castlingRights);
|
||||||
|
|
||||||
// En passant square
|
// En passant square
|
||||||
board.getLog().setEnPassant(enPassantTargetSquare);
|
board.getLog().setEnPassant(enPassantTargetSquare);
|
||||||
@ -166,7 +183,12 @@ public class FENString {
|
|||||||
// Active color
|
// Active color
|
||||||
activeColor = board.getLog().getActiveColor();
|
activeColor = board.getLog().getActiveColor();
|
||||||
|
|
||||||
// TODO: Castling availability
|
// Castling availability
|
||||||
|
castlingAvailability = "";
|
||||||
|
final char castlingRightsChars[] = new char[] { 'K', 'Q', 'k', 'q' };
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
if (board.getLog().getCastlingRights()[i]) castlingAvailability += castlingRightsChars[i];
|
||||||
|
if (castlingAvailability.isEmpty()) castlingAvailability = "-";
|
||||||
|
|
||||||
// En passant availability
|
// En passant availability
|
||||||
enPassantTargetSquare = board.getLog().getEnPassant();
|
enPassantTargetSquare = board.getLog().getEnPassant();
|
||||||
|
@ -11,9 +11,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class King extends Piece {
|
public class King extends Piece {
|
||||||
|
|
||||||
public King(Color color, Board board) {
|
public King(Color color, Board board) { super(color, board); }
|
||||||
super(color, board);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidMove(Move move) {
|
public boolean isValidMove(Move move) {
|
||||||
@ -33,22 +31,20 @@ public class King extends Piece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean canCastleKingside() {
|
public boolean canCastleKingside() {
|
||||||
if (getMoveCounter() == 0) {
|
if (board.getLog().getCastlingRights()[getColor() == Color.WHITE ? MoveNode.WHITE_KINGSIDE : MoveNode.BLACK_KINGSIDE]) {
|
||||||
int y = getColor() == Color.WHITE ? 7 : 0;
|
int y = getColor() == Color.WHITE ? 7 : 0;
|
||||||
Position rookPos = new Position(7, y);
|
Position rookPos = new Position(7, y);
|
||||||
Piece rook = board.get(rookPos);
|
Piece rook = board.get(rookPos);
|
||||||
return rook != null && rook.getType() == Type.ROOK && rook.getMoveCounter() == 0
|
return rook != null && rook.getType() == Type.ROOK && isFreePath(new Move(new Position(4, y), new Position(6, y)));
|
||||||
&& isFreePath(new Move(new Position(4, y), new Position(6, y)));
|
|
||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canCastleQueenside() {
|
public boolean canCastleQueenside() {
|
||||||
if (getMoveCounter() == 0) {
|
if (board.getLog().getCastlingRights()[getColor() == Color.WHITE ? MoveNode.WHITE_QUEENSIDE : MoveNode.BLACK_QUEENSIDE]) {
|
||||||
int y = getColor() == Color.WHITE ? 7 : 0;
|
int y = getColor() == Color.WHITE ? 7 : 0;
|
||||||
Position rookPos = new Position(0, y);
|
Position rookPos = new Position(0, y);
|
||||||
Piece rook = board.get(rookPos);
|
Piece rook = board.get(rookPos);
|
||||||
return rook != null && rook.getType() == Type.ROOK && rook.getMoveCounter() == 0
|
return rook != null && rook.getType() == Type.ROOK && isFreePath(new Move(new Position(4, y), new Position(1, y)));
|
||||||
&& isFreePath(new Move(new Position(4, y), new Position(1, y)));
|
|
||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
import dev.kske.chess.board.Piece.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -15,13 +17,12 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
|
|
||||||
private MoveNode root, current;
|
private MoveNode root, current;
|
||||||
|
|
||||||
private Position enPassant;
|
|
||||||
private Color activeColor;
|
private Color activeColor;
|
||||||
|
private boolean[] castlingRights;
|
||||||
|
private Position enPassant;
|
||||||
private int fullmoveNumber, halfmoveClock;
|
private int fullmoveNumber, halfmoveClock;
|
||||||
|
|
||||||
public Log() {
|
public Log() { reset(); }
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a (partially deep) copy of another {@link Log} instance which begins
|
* Creates a (partially deep) copy of another {@link Log} instance which begins
|
||||||
@ -34,6 +35,7 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
*/
|
*/
|
||||||
public Log(Log other, boolean copyVariations) {
|
public Log(Log other, boolean copyVariations) {
|
||||||
enPassant = other.enPassant;
|
enPassant = other.enPassant;
|
||||||
|
castlingRights = other.castlingRights.clone();
|
||||||
activeColor = other.activeColor;
|
activeColor = other.activeColor;
|
||||||
fullmoveNumber = other.fullmoveNumber;
|
fullmoveNumber = other.fullmoveNumber;
|
||||||
halfmoveClock = other.halfmoveClock;
|
halfmoveClock = other.halfmoveClock;
|
||||||
@ -54,9 +56,7 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
private boolean hasNext = true;
|
private boolean hasNext = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() { return hasNext; }
|
||||||
return hasNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MoveNode next() {
|
public MoveNode next() {
|
||||||
@ -72,16 +72,20 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
* Adds a move to the move history and adjusts the log to the new position.
|
* Adds a move to the move history and adjusts the log to the new position.
|
||||||
*
|
*
|
||||||
* @param move The move to log
|
* @param move The move to log
|
||||||
|
* @param piece The piece that performed the move
|
||||||
* @param capturedPiece The piece captured with the move
|
* @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) {
|
public void add(Move move, Piece piece, Piece capturedPiece) {
|
||||||
enPassant = pawnMove && move.yDist == 2 ? new Position(move.pos.x, move.pos.y + move.ySign) : null;
|
enPassant = piece.getType() == Type.PAWN && move.yDist == 2 ? new Position(move.pos.x, move.pos.y + move.ySign) : null;
|
||||||
if (activeColor == Color.BLACK) ++fullmoveNumber;
|
if (activeColor == Color.BLACK) ++fullmoveNumber;
|
||||||
if (pawnMove || capturedPiece != null) halfmoveClock = 0;
|
if (piece.getType() == Type.PAWN || capturedPiece != null) halfmoveClock = 0;
|
||||||
else++halfmoveClock;
|
else++halfmoveClock;
|
||||||
activeColor = activeColor.opposite();
|
activeColor = activeColor.opposite();
|
||||||
final MoveNode leaf = new MoveNode(move, capturedPiece, enPassant, activeColor, fullmoveNumber, halfmoveClock);
|
|
||||||
|
// Disable castling rights if a king or a rook has been moved
|
||||||
|
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK) disableCastlingRights(piece, move.pos);
|
||||||
|
|
||||||
|
final MoveNode leaf = new MoveNode(move, capturedPiece, castlingRights.clone(), enPassant, activeColor, fullmoveNumber, halfmoveClock);
|
||||||
|
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
root = leaf;
|
root = leaf;
|
||||||
@ -106,9 +110,7 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
|
|
||||||
public boolean isEmpty() { return root == null; }
|
public boolean isEmpty() { return root == null; }
|
||||||
|
|
||||||
public boolean hasParent() {
|
public boolean hasParent() { return !isEmpty() && current.hasParent(); }
|
||||||
return !isEmpty() && current.hasParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverts the log to its initial state corresponding to the default board
|
* Reverts the log to its initial state corresponding to the default board
|
||||||
@ -117,6 +119,7 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
public void reset() {
|
public void reset() {
|
||||||
root = null;
|
root = null;
|
||||||
current = null;
|
current = null;
|
||||||
|
castlingRights = new boolean[] { true, true, true, true };
|
||||||
enPassant = null;
|
enPassant = null;
|
||||||
activeColor = Color.WHITE;
|
activeColor = Color.WHITE;
|
||||||
fullmoveNumber = 1;
|
fullmoveNumber = 1;
|
||||||
@ -124,8 +127,9 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Changes the current node to one of its children (variations).
|
||||||
*
|
*
|
||||||
* @param index
|
* @param index the index of the variation to select
|
||||||
*/
|
*/
|
||||||
public void selectNextNode(int index) {
|
public void selectNextNode(int index) {
|
||||||
if (!isEmpty() && current.hasVariations() && index < current.getVariations().size()) {
|
if (!isEmpty() && current.hasVariations() && index < current.getVariations().size()) {
|
||||||
@ -156,14 +160,29 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
activeColor = current.activeColor;
|
activeColor = current.activeColor;
|
||||||
|
castlingRights = current.castlingRights.clone();
|
||||||
enPassant = current.enPassant;
|
enPassant = current.enPassant;
|
||||||
fullmoveNumber = current.fullmoveCounter;
|
fullmoveNumber = current.fullmoveCounter;
|
||||||
halfmoveClock = current.halfmoveClock;
|
halfmoveClock = current.halfmoveClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void disableCastlingRights(Piece piece, Position initialPosition) {
|
||||||
|
// Kingside
|
||||||
|
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK && initialPosition.x == 7)
|
||||||
|
castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_KINGSIDE : MoveNode.BLACK_KINGSIDE] = false;
|
||||||
|
|
||||||
|
// Queenside
|
||||||
|
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK && initialPosition.x == 0)
|
||||||
|
castlingRights[piece.getColor() == Color.WHITE ? MoveNode.WHITE_QUEENSIDE : MoveNode.BLACK_QUEENSIDE] = false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(activeColor, current, enPassant, fullmoveNumber, halfmoveClock, root);
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + Arrays.hashCode(castlingRights);
|
||||||
|
result = prime * result + Objects.hash(activeColor, current, enPassant, fullmoveNumber, halfmoveClock);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,9 +191,8 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (getClass() != obj.getClass()) return false;
|
if (getClass() != obj.getClass()) return false;
|
||||||
Log other = (Log) obj;
|
Log other = (Log) obj;
|
||||||
return activeColor == other.activeColor && Objects.equals(current, other.current)
|
return activeColor == other.activeColor && Arrays.equals(castlingRights, other.castlingRights) && Objects.equals(current, other.current)
|
||||||
&& Objects.equals(enPassant, other.enPassant) && fullmoveNumber == other.fullmoveNumber
|
&& Objects.equals(enPassant, other.enPassant) && fullmoveNumber == other.fullmoveNumber && halfmoveClock == other.halfmoveClock;
|
||||||
&& halfmoveClock == other.halfmoveClock && Objects.equals(root, other.root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,6 +205,10 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
*/
|
*/
|
||||||
public MoveNode getLast() { return current; }
|
public MoveNode getLast() { return current; }
|
||||||
|
|
||||||
|
public boolean[] getCastlingRights() { return castlingRights; }
|
||||||
|
|
||||||
|
public void setCastlingRights(boolean[] castlingRights) { this.castlingRights = castlingRights; }
|
||||||
|
|
||||||
public Position getEnPassant() { return enPassant; }
|
public Position getEnPassant() { return enPassant; }
|
||||||
|
|
||||||
public void setEnPassant(Position enPassant) { this.enPassant = enPassant; }
|
public void setEnPassant(Position enPassant) { this.enPassant = enPassant; }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -14,8 +15,11 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
public class MoveNode {
|
public class MoveNode {
|
||||||
|
|
||||||
|
public static final int WHITE_KINGSIDE = 0, WHITE_QUEENSIDE = 1, BLACK_KINGSIDE = 2, BLACK_QUEENSIDE = 3;
|
||||||
|
|
||||||
public final Move move;
|
public final Move move;
|
||||||
public final Piece capturedPiece;
|
public final Piece capturedPiece;
|
||||||
|
public final boolean[] castlingRights;
|
||||||
public final Position enPassant;
|
public final Position enPassant;
|
||||||
public final Color activeColor;
|
public final Color activeColor;
|
||||||
public final int fullmoveCounter, halfmoveClock;
|
public final int fullmoveCounter, halfmoveClock;
|
||||||
@ -34,10 +38,11 @@ public class MoveNode {
|
|||||||
* @param fullmoveCounter
|
* @param fullmoveCounter
|
||||||
* @param halfmoveClock
|
* @param halfmoveClock
|
||||||
*/
|
*/
|
||||||
public MoveNode(Move move, Piece capturedPiece, Position enPassant, Color activeColor, int fullmoveCounter,
|
public MoveNode(Move move, Piece capturedPiece, boolean castlingRights[], Position enPassant, Color activeColor,
|
||||||
int halfmoveClock) {
|
int fullmoveCounter, int halfmoveClock) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.capturedPiece = capturedPiece;
|
this.capturedPiece = capturedPiece;
|
||||||
|
this.castlingRights = castlingRights;
|
||||||
this.enPassant = enPassant;
|
this.enPassant = enPassant;
|
||||||
this.activeColor = activeColor;
|
this.activeColor = activeColor;
|
||||||
this.fullmoveCounter = fullmoveCounter;
|
this.fullmoveCounter = fullmoveCounter;
|
||||||
@ -53,8 +58,8 @@ public class MoveNode {
|
|||||||
* considers subsequent variations
|
* considers subsequent variations
|
||||||
*/
|
*/
|
||||||
public MoveNode(MoveNode other, boolean copyVariations) {
|
public MoveNode(MoveNode other, boolean copyVariations) {
|
||||||
this(other.move, other.capturedPiece, other.enPassant, other.activeColor, other.fullmoveCounter,
|
this(other.move, other.capturedPiece, other.castlingRights.clone(), other.enPassant, other.activeColor,
|
||||||
other.halfmoveClock);
|
other.fullmoveCounter, other.halfmoveClock);
|
||||||
if (copyVariations && other.variations != null) {
|
if (copyVariations && other.variations != null) {
|
||||||
if (variations == null) variations = new ArrayList<>();
|
if (variations == null) variations = new ArrayList<>();
|
||||||
other.variations.forEach(variation -> {
|
other.variations.forEach(variation -> {
|
||||||
@ -97,8 +102,12 @@ public class MoveNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects
|
final int prime = 31;
|
||||||
.hash(activeColor, capturedPiece, enPassant, fullmoveCounter, halfmoveClock, move, parent, variations);
|
int result = 1;
|
||||||
|
result = prime * result + Arrays.hashCode(castlingRights);
|
||||||
|
result = prime * result
|
||||||
|
+ Objects.hash(activeColor, capturedPiece, enPassant, fullmoveCounter, halfmoveClock, move);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -108,8 +117,8 @@ public class MoveNode {
|
|||||||
if (getClass() != obj.getClass()) return false;
|
if (getClass() != obj.getClass()) return false;
|
||||||
MoveNode other = (MoveNode) obj;
|
MoveNode other = (MoveNode) obj;
|
||||||
return activeColor == other.activeColor && Objects.equals(capturedPiece, other.capturedPiece)
|
return activeColor == other.activeColor && Objects.equals(capturedPiece, other.capturedPiece)
|
||||||
&& Objects.equals(enPassant, other.enPassant) && fullmoveCounter == other.fullmoveCounter
|
&& Arrays.equals(castlingRights, other.castlingRights) && Objects.equals(enPassant, other.enPassant)
|
||||||
&& halfmoveClock == other.halfmoveClock && Objects.equals(move, other.move)
|
&& fullmoveCounter == other.fullmoveCounter && halfmoveClock == other.halfmoveClock
|
||||||
&& Objects.equals(parent, other.parent) && Objects.equals(variations, other.variations);
|
&& Objects.equals(move, other.move);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,7 +14,6 @@ public abstract class Piece implements Cloneable {
|
|||||||
|
|
||||||
private final Color color;
|
private final Color color;
|
||||||
protected Board board;
|
protected Board board;
|
||||||
private int moveCounter;
|
|
||||||
|
|
||||||
public Piece(Color color, Board board) {
|
public Piece(Color color, Board board) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
@ -75,19 +74,9 @@ public abstract class Piece implements Cloneable {
|
|||||||
|
|
||||||
public Color getColor() { return color; }
|
public Color getColor() { return color; }
|
||||||
|
|
||||||
public int getMoveCounter() { return moveCounter; }
|
|
||||||
|
|
||||||
public void incMoveCounter() {
|
|
||||||
++moveCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void decMoveCounter() {
|
|
||||||
--moveCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(color, moveCounter);
|
return Objects.hash(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,7 +85,7 @@ public abstract class Piece implements Cloneable {
|
|||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (getClass() != obj.getClass()) return false;
|
if (getClass() != obj.getClass()) return false;
|
||||||
Piece other = (Piece) obj;
|
Piece other = (Piece) obj;
|
||||||
return color == other.color && moveCounter == other.moveCounter;
|
return color == other.color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum Type {
|
public static enum Type {
|
||||||
|
@ -43,10 +43,10 @@ class LogTest {
|
|||||||
log.setActiveColor(Color.WHITE);
|
log.setActiveColor(Color.WHITE);
|
||||||
other.setActiveColor(Color.BLACK);
|
other.setActiveColor(Color.BLACK);
|
||||||
assertNotEquals(log.getActiveColor(), other.getActiveColor());
|
assertNotEquals(log.getActiveColor(), other.getActiveColor());
|
||||||
log.add(Move.fromLAN("a2a4"), null, true);
|
log.add(Move.fromLAN("a2a4"), new Pawn(Color.WHITE, null), null);
|
||||||
log.add(Move.fromLAN("a4a5"), null, true);
|
log.add(Move.fromLAN("a4a5"), new Pawn(Color.WHITE, null), null);
|
||||||
other.add(Move.fromLAN("a2a4"), null, true);
|
other.add(Move.fromLAN("a2a4"), new Pawn(Color.WHITE, null), null);
|
||||||
other.add(Move.fromLAN("a4a5"), null, true);
|
other.add(Move.fromLAN("a4a5"), new Pawn(Color.WHITE, null), null);
|
||||||
assertNotEquals(log.getRoot(), other.getRoot());
|
assertNotEquals(log.getRoot(), other.getRoot());
|
||||||
assertNotEquals(log.getRoot().getVariations(), other.getRoot().getVariations());
|
assertNotEquals(log.getRoot().getVariations(), other.getRoot().getVariations());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user