diff --git a/src/backend/AutoPlayer.java b/src/backend/AutoPlayer.java index ea326e6..693e002 100644 --- a/src/backend/AutoPlayer.java +++ b/src/backend/AutoPlayer.java @@ -66,7 +66,7 @@ public class AutoPlayer { for (Piece piece : board.getPieces()) { if (piece.isWhite() != isWhite) continue; - ArrayList legalMoves = board.computeLegalMoves(piece); + ArrayList legalMoves = board.computeLegalMovesSafe(piece); for (int[] move : legalMoves) { Piece target = getPieceAt(board, move[0], move[1]); Move candidate = new Move( @@ -101,4 +101,4 @@ public class AutoPlayer { } return null; } -} +} \ No newline at end of file diff --git a/src/backend/Board.java b/src/backend/Board.java index 233b885..c5ee805 100644 --- a/src/backend/Board.java +++ b/src/backend/Board.java @@ -17,6 +17,32 @@ public class Board { private int[] enPassantTarget = null; private GameSoundManager soundManager; + public ArrayList computeLegalMovesSafe(Piece piece) { + ArrayList rawMoves = computeLegalMoves(piece); // All pseudo-legal moves + ArrayList safeMoves = new ArrayList<>(); + + for (int[] move : rawMoves) { + Board copy = new Board(this); // Deep copy the board + Piece simulatedPiece = copy.getPieceAt(piece.getX(), piece.getY()); + + if (simulatedPiece != null) { + copy.playMove(new Move( + simulatedPiece.getType(), + simulatedPiece.isWhite(), + simulatedPiece.getX(), simulatedPiece.getY(), + move[0], move[1], + copy.getPieceAt(move[0], move[1]) + )); + + if (!copy.isKingInCheck(piece.isWhite())) { + safeMoves.add(move); // Keep only if king is safe + } + } + } + + return safeMoves; + } + public Board(int colNum, int lineNum) { @@ -134,7 +160,8 @@ public class Board { if (clickedPiece != null && clickedPiece.isWhite() == turnWhite) { selectedX = x; selectedY = y; - highlightedSquares = computeLegalMoves(clickedPiece); + highlightedSquares = computeLegalMovesSafe(clickedPiece); + } return; } @@ -694,6 +721,40 @@ private boolean canCastleQueenside(boolean isWhite) { } } return moves; + } -} + public boolean isCheckmate(boolean isWhite) { + if (!isKingInCheck(isWhite)) { + return false; // King is not in check → not checkmate + } + + for (Piece p : pieces) { + if (p.isWhite() == isWhite) { + ArrayList moves = computeLegalMoves(p); + if (!moves.isEmpty()) { + return false; // At least one legal move available → not checkmate + } + } + } + + return true; // King is in check AND no legal moves → checkmate + } + public boolean isStalemate(boolean isWhite) { + if (isKingInCheck(isWhite)) { + return false; // Still in danger → not stalemate + } + + for (Piece p : pieces) { + if (p.isWhite() == isWhite) { + ArrayList moves = computeLegalMoves(p); + if (!moves.isEmpty()) { + return false; + } + } + } + + return true; // King not in check but has no legal moves → stalemate + } + +} \ No newline at end of file diff --git a/src/backend/Game.java b/src/backend/Game.java index 4c64f70..7337d9d 100644 --- a/src/backend/Game.java +++ b/src/backend/Game.java @@ -62,6 +62,14 @@ public class Game extends Thread { } if(!isAITurn()) { board.userTouch(x, y); + if (board.isCheckmate(!board.isTurnWhite())) { + System.out.println((!board.isTurnWhite() ? "White" : "Black") + " is checkmated. Game over!"); + } else if (board.isStalemate(!board.isTurnWhite())) { + System.out.println("Stalemate! It's a draw."); + } + + + } } @@ -107,4 +115,4 @@ public class Game extends Thread { this.activationAIFlags[isWhite?1:0] = !this.activationAIFlags[isWhite?1:0]; } -} +} \ No newline at end of file