From f854687c3e30af00ffb2fc849433e9b7d71d87fa Mon Sep 17 00:00:00 2001 From: VALENTINE GIRAL Date: Fri, 16 May 2025 12:17:11 +0200 Subject: [PATCH] display victory --- Test.board | 34 ++++++ src/backend/Board.java | 37 ++++++- src/backend/GameResult.java | 59 ++++++++++ src/backend/VictoryChecker.java | 186 ++++++++++++++++++++++++++++++++ test2.board | 33 ++++++ 5 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 Test.board create mode 100644 src/backend/GameResult.java create mode 100644 src/backend/VictoryChecker.java create mode 100644 test2.board diff --git a/Test.board b/Test.board new file mode 100644 index 0000000..7f4670c --- /dev/null +++ b/Test.board @@ -0,0 +1,34 @@ +8,white +8,8 +Rook,0,0,B +Knight,1,0,B +Bishop,2,0,B +Queen,3,0,B +King,4,0,B +Bishop,5,0,B +Knight,6,0,B +Rook,7,0,B +Pawn,0,1,B +Pawn,1,1,B +Pawn,2,1,B +Pawn,4,1,B +Pawn,5,1,B +Pawn,6,2,B +Pawn,7,2,B +Pawn,3,3,B +Pawn,3,4,W +Pawn,7,5,W +Pawn,0,6,W +Pawn,1,6,W +Pawn,2,6,W +Pawn,4,6,W +Pawn,5,6,W +Pawn,6,6,W +Rook,7,6,W +Rook,0,7,W +Knight,1,7,W +Bishop,2,7,W +Queen,3,7,W +King,4,7,W +Bishop,5,7,W +Knight,6,7,W diff --git a/src/backend/Board.java b/src/backend/Board.java index 8b7d184..f8ecb5b 100644 --- a/src/backend/Board.java +++ b/src/backend/Board.java @@ -11,6 +11,7 @@ public class Board { private boolean turnWhite=true; // True if it's White's turn, False if it's Black's turn private ArrayList highlightedPositions = new ArrayList<>(); // List containing all board positions private ArrayList moveHistory = new ArrayList<>(); // List to store move history + private GameResult gameResult = new GameResult(); private boolean inBounds(int x, int y) { // Verify the bounds of the board @@ -41,7 +42,10 @@ public class Board { } return result; } - + + public GameResult getGameResult() { + return gameResult; + } public Board(int colNum, int lineNum) { this.col=colNum; @@ -114,6 +118,11 @@ public class Board { } } this.turnNumber=0; + this.turnWhite=true; + + // Reset game result + this.gameResult.reset(); + System.out.println("Board cleaned. All pieces removed."); } @@ -155,6 +164,11 @@ public class Board { } public void userTouch(int x, int y) { + // If game is already over, prevent further moves + if (gameResult.isGameOver()) { + return; + } + // Case 1: No position is selected if (selectedPosition==null) { Piece clickedPiece = board[y][x]; @@ -194,6 +208,9 @@ public class Board { // Update turn this.turnNumber++; this.turnWhite = !this.turnWhite; + + // Check for victory after the move + gameResult.checkForVictory(this); } // Deselect the position after moving @@ -427,6 +444,11 @@ public class Board { } public void playMove(Move move) { + // If game is already over, prevent further moves + if (gameResult.isGameOver()) { + return; + } + //get current piece coordinate int fromX = move.piece.getX(); int fromY = move.piece.getY(); @@ -436,7 +458,7 @@ public class Board { Piece movingPiece = move.piece; Piece capturedPiece = board[toY][toX]; // capture if any - moveHistory.add(new MoveRecord(movingPiece, capturedPiece, fromX, fromY, toX, toY,turnNumber, turnWhite)); + moveHistory.add(new MoveRecord(movingPiece, capturedPiece, fromX, fromY, toX, toY,turnNumber, turnWhite)); //Remove the piece from the original position board[fromY][fromX] = null; //Update the internal position of the piece @@ -449,11 +471,18 @@ public class Board { this.turnWhite = !this.turnWhite; this.turnNumber++; + // Check for victory after the move + gameResult.checkForVictory(this); + //Clear selection/highlight this.selectedPosition = null; this.highlightedPositions.clear(); - - } + + //manually check for victory if needed + public boolean isCheckmate() { + gameResult.checkForVictory(this); + return gameResult.isGameOver(); + } } diff --git a/src/backend/GameResult.java b/src/backend/GameResult.java new file mode 100644 index 0000000..1812295 --- /dev/null +++ b/src/backend/GameResult.java @@ -0,0 +1,59 @@ +package backend; + +// Class to track the outcome of a chess game + +public class GameResult { + private boolean gameOver = false; + private boolean whiteWon = false; + private boolean blackWon = false; + private String message = ""; + + // Checks for game victory after a move is made + public GameResult checkForVictory(Board board) { + // If game is already over, don't check again + if (gameOver) { + return this; + } + + // Check if White has won + if (VictoryChecker.checkVictory(board, true)) { + gameOver = true; + whiteWon = true; + message = "White wins by checkmate!"; + System.out.println(message); + } + // Check if Black has won + else if (VictoryChecker.checkVictory(board, false)) { + gameOver = true; + blackWon = true; + message = "Black wins by checkmate!"; + System.out.println(message); + } + + return this; + } + + public boolean isGameOver() { + return gameOver; + } + + public boolean hasWhiteWon() { + return whiteWon; + } + + public boolean hasBlackWon() { + return blackWon; + } + + public String getMessage() { + return message; + } + + // Reset the game result to start a new game + public void reset() { + gameOver = false; + whiteWon = false; + blackWon = false; + message = ""; + } +} \ No newline at end of file diff --git a/src/backend/VictoryChecker.java b/src/backend/VictoryChecker.java new file mode 100644 index 0000000..342860b --- /dev/null +++ b/src/backend/VictoryChecker.java @@ -0,0 +1,186 @@ +package backend; + +import java.util.ArrayList; + +public class VictoryChecker { + + // For debugging + private static final boolean DEBUG = true; + + // Check if a player has won the chess game via checkmate + + public static boolean checkVictory(Board board, boolean isWhitePlayer) { + // The opponent is the one who would be checkmated + boolean opponentColor = !isWhitePlayer; + + // Debug info + if (DEBUG) { + System.out.println("Checking if " + (isWhitePlayer ? "White" : "Black") + " has won..."); + } + + // Find the opponent's king + int[] kingPosition = findKingPosition(board, opponentColor); + if (kingPosition == null) { + if (DEBUG) { + System.err.println((opponentColor ? "White" : "Black") + " king not found on the board!"); + } + // If opponent's king is not on board, the player has won + return true; + } + + // Check if opponent's king is in check + boolean kingInCheck = isKingInCheck(board, opponentColor, kingPosition); + if (!kingInCheck) { + if (DEBUG) { + System.out.println((opponentColor ? "White" : "Black") + " king is not in check, no checkmate."); + } + return false; + } + + if (DEBUG) { + System.out.println((opponentColor ? "White" : "Black") + " king is in check."); + } + + // Check if opponent has any legal moves left + boolean hasLegalMoves = hasLegalMoves(board, opponentColor); + if (hasLegalMoves) { + if (DEBUG) { + System.out.println((opponentColor ? "White" : "Black") + " has legal moves available, no checkmate."); + } + return false; + } + + // If the king is in check and there are no legal moves, it's checkmate + if (DEBUG) { + System.out.println("CHECKMATE! " + (isWhitePlayer ? "White" : "Black") + " wins!"); + } + return true; + } + + //Determine if a player's king is in check + + private static boolean isKingInCheck(Board board, boolean isWhite, int[] kingPosition) { + // Get all opponent pieces + boolean opponentColor = !isWhite; + + if (DEBUG) { + System.out.println("Checking if " + (isWhite ? "White" : "Black") + + " king at [" + kingPosition[0] + "," + kingPosition[1] + "] is in check"); + } + + for (Piece piece : board.getPieces()) { + if (piece.isWhite() == opponentColor) { + // Get valid moves for this opponent piece + ArrayList validMoves = board.getValidMoves(piece); + + for (int[] move : validMoves) { + // If the move targets the king's position, the king is in check + if (move[0] == kingPosition[0] && move[1] == kingPosition[1]) { + if (DEBUG) { + System.out.println("King is attacked by " + piece.getType() + + " at [" + piece.getX() + "," + piece.getY() + "]"); + } + return true; + } + } + } + } + + return false; + } + + //Find the position of a player's king on the board + private static int[] findKingPosition(Board board, boolean isWhite) { + if (DEBUG) { + System.out.println("Looking for " + (isWhite ? "White" : "Black") + " king"); + } + + for (Piece piece : board.getPieces()) { + if (piece.getType() == PieceType.King && piece.isWhite() == isWhite) { + if (DEBUG) { + System.out.println("Found king at [" + piece.getX() + "," + piece.getY() + "]"); + } + return new int[] {piece.getX(), piece.getY()}; + } + } + + if (DEBUG) { + System.err.println((isWhite ? "White" : "Black") + " king not found!"); + } + return null; + } + + // Check if a player has any legal moves available + private static boolean hasLegalMoves(Board board, boolean isWhite) { + if (DEBUG) { + System.out.println("Checking if " + (isWhite ? "White" : "Black") + " has any legal moves"); + } + + int legalMovesCount = 0; + + // For each piece of the player + for (Piece piece : board.getPieces()) { + if (piece.isWhite() == isWhite) { + // Get all valid moves for this piece + ArrayList validMoves = board.getValidMoves(piece); + + for (int[] move : validMoves) { + // Check if this move would still leave the king in check + if (isLegalMoveWithoutCheck(board, piece, move[0], move[1], isWhite)) { + legalMovesCount++; + if (DEBUG) { + System.out.println("Legal move found: " + piece.getType() + + " from [" + piece.getX() + "," + piece.getY() + "] to [" + + move[0] + "," + move[1] + "]"); + // We found at least one legal move, can return early + return true; + } + } + } + } + } + + if (DEBUG) { + System.out.println("Total legal moves found: " + legalMovesCount); + } + + return legalMovesCount > 0; + } + + // Check if a move is legal considering check rules + private static boolean isLegalMoveWithoutCheck(Board board, Piece piece, int toX, int toY, boolean isWhite) { + int fromX = piece.getX(); + int fromY = piece.getY(); + + if (DEBUG) { + System.out.println("Testing move: " + piece.getType() + + " from [" + fromX + "," + fromY + "] to [" + toX + "," + toY + "]"); + } + + // Create a copy of the board to simulate the move + Board simulatedBoard = new Board(board); + + // Execute the move on the simulated board + simulatedBoard.movePiece(fromX, fromY, toX, toY); + + // Find the king's position after the move + int[] kingPos = findKingPosition(simulatedBoard, isWhite); + if (kingPos == null) { + // This shouldn't happen unless the moved piece was the king and it was captured somehow + if (DEBUG) { + System.err.println("King disappeared after simulated move!"); + } + return false; + } + + // Check if the king is in check after the move + boolean kingInCheck = isKingInCheck(simulatedBoard, isWhite, kingPos); + + if (DEBUG && !kingInCheck) { + System.out.println("Move is legal (doesn't leave king in check)"); + } + + return !kingInCheck; + } + +} \ No newline at end of file diff --git a/test2.board b/test2.board new file mode 100644 index 0000000..d83bf53 --- /dev/null +++ b/test2.board @@ -0,0 +1,33 @@ +6,white +8,8 +Rook,0,0,B +Knight,1,0,B +Queen,3,0,B +King,4,0,B +Bishop,5,0,B +Knight,6,0,B +Rook,7,0,B +Pawn,0,1,B +Pawn,1,1,B +Pawn,4,1,B +Pawn,5,1,B +Pawn,6,1,B +Pawn,7,1,B +Pawn,2,3,B +Pawn,3,3,B +Bishop,5,3,B +Pawn,4,4,W +Pawn,0,6,W +Pawn,1,6,W +Pawn,2,6,W +Pawn,3,6,W +Pawn,6,6,W +Pawn,7,6,W +Rook,0,7,W +Knight,1,7,W +Bishop,2,7,W +Queen,3,7,W +King,4,7,W +Bishop,5,7,W +Knight,6,7,W +Rook,7,7,W