castling
This commit is contained in:
parent
b08bd6477f
commit
9ee1df68d8
|
|
@ -0,0 +1,359 @@
|
||||||
|
package backend;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CastlingHandler {
|
||||||
|
private Board board;
|
||||||
|
|
||||||
|
public CastlingHandler(Board board) {
|
||||||
|
this.board = board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CastlingMove {
|
||||||
|
public final int kingFromX, kingFromY, kingToX, kingToY;
|
||||||
|
public final int rookFromX, rookFromY, rookToX, rookToY;
|
||||||
|
public final boolean isKingside;
|
||||||
|
|
||||||
|
public CastlingMove(int kingFromX, int kingFromY, int kingToX, int kingToY,
|
||||||
|
int rookFromX, int rookFromY, int rookToX, int rookToY,
|
||||||
|
boolean isKingside) {
|
||||||
|
this.kingFromX = kingFromX;
|
||||||
|
this.kingFromY = kingFromY;
|
||||||
|
this.kingToX = kingToX;
|
||||||
|
this.kingToY = kingToY;
|
||||||
|
this.rookFromX = rookFromX;
|
||||||
|
this.rookFromY = rookFromY;
|
||||||
|
this.rookToX = rookToX;
|
||||||
|
this.rookToY = rookToY;
|
||||||
|
this.isKingside = isKingside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Position {
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
|
||||||
|
public Position(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null || getClass() != obj.getClass()) return false;
|
||||||
|
Position position = (Position) obj;
|
||||||
|
return x == position.x && y == position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if castling is possible and returns the castling move details
|
||||||
|
*/
|
||||||
|
public CastlingMove getCastlingMove(int fromX, int fromY, int toX, int toY) {
|
||||||
|
Piece piece = board.getPieceAt(fromX, fromY);
|
||||||
|
|
||||||
|
// Must be a king
|
||||||
|
if (piece == null || piece.getType() != PieceType.King) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isWhite = piece.isWhite();
|
||||||
|
int kingRow = isWhite ? 7 : 0;
|
||||||
|
|
||||||
|
// King must be on its starting position
|
||||||
|
if (fromY != kingRow || fromX != 4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is a castling move (king moves 2 squares horizontally)
|
||||||
|
if (fromY != toY || Math.abs(toX - fromX) != 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isKingside = toX > fromX;
|
||||||
|
int rookStartX = isKingside ? 7 : 0;
|
||||||
|
int rookEndX = isKingside ? 5 : 3;
|
||||||
|
|
||||||
|
return new CastlingMove(fromX, fromY, toX, toY,
|
||||||
|
rookStartX, kingRow, rookEndX, kingRow,
|
||||||
|
isKingside);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if castling is legal
|
||||||
|
*/
|
||||||
|
public boolean isCastlingValid(CastlingMove castling) {
|
||||||
|
if (castling == null) return false;
|
||||||
|
|
||||||
|
Piece king = board.getPieceAt(castling.kingFromX, castling.kingFromY);
|
||||||
|
Piece rook = board.getPieceAt(castling.rookFromX, castling.rookFromY);
|
||||||
|
|
||||||
|
// Verify pieces exist and are correct type/color
|
||||||
|
if (king == null || king.getType() != PieceType.King) return false;
|
||||||
|
if (rook == null || rook.getType() != PieceType.Rook) return false;
|
||||||
|
if (king.isWhite() != rook.isWhite()) return false;
|
||||||
|
|
||||||
|
// Check if king or rook have moved (simplified - assumes starting positions)
|
||||||
|
boolean isWhite = king.isWhite();
|
||||||
|
int expectedKingRow = isWhite ? 7 : 0;
|
||||||
|
if (castling.kingFromY != expectedKingRow || castling.kingFromX != 4) return false;
|
||||||
|
if (castling.rookFromY != expectedKingRow) return false;
|
||||||
|
if (castling.isKingside && castling.rookFromX != 7) return false;
|
||||||
|
if (!castling.isKingside && castling.rookFromX != 0) return false;
|
||||||
|
|
||||||
|
// Check path is clear between king and rook
|
||||||
|
int startX = Math.min(castling.kingFromX, castling.rookFromX) + 1;
|
||||||
|
int endX = Math.max(castling.kingFromX, castling.rookFromX) - 1;
|
||||||
|
|
||||||
|
for (int x = startX; x <= endX; x++) {
|
||||||
|
if (board.getPieceAt(x, castling.kingFromY) != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that king is not in check
|
||||||
|
if (isKingInCheck(isWhite)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that king doesn't pass through check
|
||||||
|
for (int x = castling.kingFromX; x != castling.kingToX + (castling.isKingside ? 1 : -1);
|
||||||
|
x += castling.isKingside ? 1 : -1) {
|
||||||
|
|
||||||
|
// Create temporary board with king at this position
|
||||||
|
Board tempBoard = new Board(board);
|
||||||
|
tempBoard.removePiece(castling.kingFromX, castling.kingFromY);
|
||||||
|
tempBoard.setPiece(isWhite, PieceType.King, x, castling.kingFromY);
|
||||||
|
|
||||||
|
CastlingHandler tempHandler = new CastlingHandler(tempBoard);
|
||||||
|
if (tempHandler.isKingInCheck(isWhite)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the castling move on the board
|
||||||
|
*/
|
||||||
|
public void executeCastling(CastlingMove castling) {
|
||||||
|
Piece king = board.getPieceAt(castling.kingFromX, castling.kingFromY);
|
||||||
|
Piece rook = board.getPieceAt(castling.rookFromX, castling.rookFromY);
|
||||||
|
|
||||||
|
// Move the king
|
||||||
|
board.removePiece(castling.kingFromX, castling.kingFromY);
|
||||||
|
board.setPiece(king.isWhite(), king.getType(), castling.kingToX, castling.kingToY);
|
||||||
|
|
||||||
|
// Move the rook
|
||||||
|
board.removePiece(castling.rookFromX, castling.rookFromY);
|
||||||
|
board.setPiece(rook.isWhite(), rook.getType(), castling.rookToX, castling.rookToY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all possible castling moves for a king
|
||||||
|
*/
|
||||||
|
public List<Position> getCastlingPositions(Piece king) {
|
||||||
|
List<Position> castlingMoves = new ArrayList<>();
|
||||||
|
|
||||||
|
if (king.getType() != PieceType.King) {
|
||||||
|
return castlingMoves;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isWhite = king.isWhite();
|
||||||
|
int kingRow = isWhite ? 7 : 0;
|
||||||
|
|
||||||
|
// King must be on starting position
|
||||||
|
if (king.getX() != 4 || king.getY() != kingRow) {
|
||||||
|
return castlingMoves;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check kingside castling
|
||||||
|
CastlingMove kingsideCastling = getCastlingMove(4, kingRow, 6, kingRow);
|
||||||
|
if (isCastlingValid(kingsideCastling)) {
|
||||||
|
castlingMoves.add(new Position(6, kingRow));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check queenside castling
|
||||||
|
CastlingMove queensideCastling = getCastlingMove(4, kingRow, 2, kingRow);
|
||||||
|
if (isCastlingValid(queensideCastling)) {
|
||||||
|
castlingMoves.add(new Position(2, kingRow));
|
||||||
|
}
|
||||||
|
|
||||||
|
return castlingMoves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKingInCheck(boolean isWhiteKing) {
|
||||||
|
// Find the king's position
|
||||||
|
Piece king = null;
|
||||||
|
for (Piece p : board.getPieces()) {
|
||||||
|
if (p.getType() == PieceType.King && p.isWhite() == isWhiteKing) {
|
||||||
|
king = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (king == null) return false;
|
||||||
|
|
||||||
|
return checkIfKingUnderAttack(isWhiteKing, king);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkIfKingUnderAttack(boolean isWhiteKing, Piece king) {
|
||||||
|
// Check if any opponent piece can attack the king
|
||||||
|
for (Piece p : board.getPieces()) {
|
||||||
|
if (p.isWhite() == isWhiteKing) continue; // Skip pieces of same color
|
||||||
|
|
||||||
|
// Get raw moves without check validation
|
||||||
|
List<Position> attackMoves = getValidDestinations(p);
|
||||||
|
|
||||||
|
// If any piece can move to king's position, king is in check
|
||||||
|
for (Position pos : attackMoves) {
|
||||||
|
if (pos.x == king.getX() && pos.y == king.getY()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Position> getValidDestinations(Piece piece) {
|
||||||
|
List<Position> moves = new ArrayList<>();
|
||||||
|
|
||||||
|
switch (piece.getType()) {
|
||||||
|
case Pawn:
|
||||||
|
addPawnMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
case Rook:
|
||||||
|
addRookMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
case Knight:
|
||||||
|
addKnightMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
case Bishop:
|
||||||
|
addBishopMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
case Queen:
|
||||||
|
addRookMoves(moves, piece);
|
||||||
|
addBishopMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
case King:
|
||||||
|
addKingMoves(moves, piece);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return moves;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPawnMoves(List<Position> validMoves, Piece piece) {
|
||||||
|
int x = piece.getX();
|
||||||
|
int y = piece.getY();
|
||||||
|
boolean isWhite = piece.isWhite();
|
||||||
|
|
||||||
|
int direction = isWhite ? -1 : 1;
|
||||||
|
|
||||||
|
// Diagonal captures only (for attack patterns)
|
||||||
|
int newY = y + direction;
|
||||||
|
if (newY >= 0 && newY < board.getHeight()) {
|
||||||
|
for (int dx = -1; dx <= 1; dx += 2) {
|
||||||
|
int newX = x + dx;
|
||||||
|
if (newX >= 0 && newX < board.getWidth()) {
|
||||||
|
validMoves.add(new Position(newX, newY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRookMoves(List<Position> validMoves, Piece piece) {
|
||||||
|
int x = piece.getX();
|
||||||
|
int y = piece.getY();
|
||||||
|
boolean isWhite = piece.isWhite();
|
||||||
|
|
||||||
|
int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
|
||||||
|
|
||||||
|
for (int[] dir : directions) {
|
||||||
|
int dx = dir[0];
|
||||||
|
int dy = dir[1];
|
||||||
|
|
||||||
|
int newX = x + dx;
|
||||||
|
int newY = y + dy;
|
||||||
|
|
||||||
|
while (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) {
|
||||||
|
validMoves.add(new Position(newX, newY));
|
||||||
|
|
||||||
|
Piece targetPiece = board.getPieceAt(newX, newY);
|
||||||
|
if (targetPiece != null) {
|
||||||
|
break; // Cannot move beyond a piece
|
||||||
|
}
|
||||||
|
|
||||||
|
newX += dx;
|
||||||
|
newY += dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKnightMoves(List<Position> validMoves, Piece piece) {
|
||||||
|
int x = piece.getX();
|
||||||
|
int y = piece.getY();
|
||||||
|
|
||||||
|
int[][] knightMoves = {
|
||||||
|
{-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},
|
||||||
|
{1, -2}, {1, 2}, {2, -1}, {2, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int[] move : knightMoves) {
|
||||||
|
int newX = x + move[0];
|
||||||
|
int newY = y + move[1];
|
||||||
|
|
||||||
|
if (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) {
|
||||||
|
validMoves.add(new Position(newX, newY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBishopMoves(List<Position> validMoves, Piece piece) {
|
||||||
|
int x = piece.getX();
|
||||||
|
int y = piece.getY();
|
||||||
|
|
||||||
|
int[][] directions = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
|
||||||
|
|
||||||
|
for (int[] dir : directions) {
|
||||||
|
int dx = dir[0];
|
||||||
|
int dy = dir[1];
|
||||||
|
|
||||||
|
int newX = x + dx;
|
||||||
|
int newY = y + dy;
|
||||||
|
|
||||||
|
while (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) {
|
||||||
|
validMoves.add(new Position(newX, newY));
|
||||||
|
|
||||||
|
Piece targetPiece = board.getPieceAt(newX, newY);
|
||||||
|
if (targetPiece != null) {
|
||||||
|
break; // Cannot move beyond a piece
|
||||||
|
}
|
||||||
|
|
||||||
|
newX += dx;
|
||||||
|
newY += dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKingMoves(List<Position> validMoves, Piece piece) {
|
||||||
|
int x = piece.getX();
|
||||||
|
int y = piece.getY();
|
||||||
|
|
||||||
|
for (int dx = -1; dx <= 1; dx++) {
|
||||||
|
for (int dy = -1; dy <= 1; dy++) {
|
||||||
|
if (dx == 0 && dy == 0) continue;
|
||||||
|
|
||||||
|
int newX = x + dx;
|
||||||
|
int newY = y + dy;
|
||||||
|
|
||||||
|
if (newX >= 0 && newX < board.getWidth() && newY >= 0 && newY < board.getHeight()) {
|
||||||
|
validMoves.add(new Position(newX, newY));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue