Compare commits
2 Commits
5d5c023f1a
...
15fc3a6851
| Author | SHA1 | Date |
|---|---|---|
|
|
15fc3a6851 | |
|
|
f854687c3e |
|
|
@ -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
|
||||||
|
|
@ -11,8 +11,8 @@ public class Board {
|
||||||
private boolean turnWhite=true; // True if it's White's turn, False if it's Black's turn
|
private boolean turnWhite=true; // True if it's White's turn, False if it's Black's turn
|
||||||
private ArrayList<int[]> highlightedPositions = new ArrayList<>(); // List containing all board positions
|
private ArrayList<int[]> highlightedPositions = new ArrayList<>(); // List containing all board positions
|
||||||
private ArrayList<MoveRecord> moveHistory = new ArrayList<>(); // List to store move history
|
private ArrayList<MoveRecord> moveHistory = new ArrayList<>(); // List to store move history
|
||||||
private String winnerMessage;
|
private GameResult gameResult = new GameResult();
|
||||||
private boolean suppressCheckmateCheck = false;
|
|
||||||
private boolean inBounds(int x, int y) {
|
private boolean inBounds(int x, int y) {
|
||||||
// Verify the bounds of the board
|
// Verify the bounds of the board
|
||||||
return x >= 0 && y >= 0 && x < col && y < line;
|
return x >= 0 && y >= 0 && x < col && y < line;
|
||||||
|
|
@ -42,7 +42,10 @@ public class Board {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameResult getGameResult() {
|
||||||
|
return gameResult;
|
||||||
|
}
|
||||||
|
|
||||||
public Board(int colNum, int lineNum) {
|
public Board(int colNum, int lineNum) {
|
||||||
this.col=colNum;
|
this.col=colNum;
|
||||||
|
|
@ -115,6 +118,11 @@ public class Board {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.turnNumber=0;
|
this.turnNumber=0;
|
||||||
|
this.turnWhite=true;
|
||||||
|
|
||||||
|
// Reset game result
|
||||||
|
this.gameResult.reset();
|
||||||
|
|
||||||
System.out.println("Board cleaned. All pieces removed.");
|
System.out.println("Board cleaned. All pieces removed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,6 +164,11 @@ public class Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void userTouch(int x, int y) {
|
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
|
// Case 1: No position is selected
|
||||||
if (selectedPosition==null) {
|
if (selectedPosition==null) {
|
||||||
Piece clickedPiece = board[y][x];
|
Piece clickedPiece = board[y][x];
|
||||||
|
|
@ -195,6 +208,9 @@ public class Board {
|
||||||
// Update turn
|
// Update turn
|
||||||
this.turnNumber++;
|
this.turnNumber++;
|
||||||
this.turnWhite = !this.turnWhite;
|
this.turnWhite = !this.turnWhite;
|
||||||
|
|
||||||
|
// Check for victory after the move
|
||||||
|
gameResult.checkForVictory(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deselect the position after moving
|
// Deselect the position after moving
|
||||||
|
|
@ -428,7 +444,12 @@ public class Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playMove(Move move) {
|
public void playMove(Move move) {
|
||||||
//get current piece coordinate
|
// If game is already over, prevent further moves
|
||||||
|
if (gameResult.isGameOver()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//gets current piece coordinate
|
||||||
int fromX = move.piece.getX();
|
int fromX = move.piece.getX();
|
||||||
int fromY = move.piece.getY();
|
int fromY = move.piece.getY();
|
||||||
int toX = move.toX;
|
int toX = move.toX;
|
||||||
|
|
@ -437,7 +458,7 @@ public class Board {
|
||||||
Piece movingPiece = move.piece;
|
Piece movingPiece = move.piece;
|
||||||
Piece capturedPiece = board[toY][toX]; // capture if any
|
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
|
//Remove the piece from the original position
|
||||||
board[fromY][fromX] = null;
|
board[fromY][fromX] = null;
|
||||||
//Update the internal position of the piece
|
//Update the internal position of the piece
|
||||||
|
|
@ -450,66 +471,18 @@ public class Board {
|
||||||
this.turnWhite = !this.turnWhite;
|
this.turnWhite = !this.turnWhite;
|
||||||
this.turnNumber++;
|
this.turnNumber++;
|
||||||
|
|
||||||
|
// Check for victory after the move
|
||||||
|
gameResult.checkForVictory(this);
|
||||||
|
|
||||||
//Clear selection/highlight
|
//Clear selection/highlight
|
||||||
this.selectedPosition = null;
|
this.selectedPosition = null;
|
||||||
this.highlightedPositions.clear();
|
this.highlightedPositions.clear();
|
||||||
|
|
||||||
if (!suppressCheckmateCheck && isCheckmate(!turnWhite)) {
|
|
||||||
winnerMessage = turnWhite ? "White is the winner" : "Black is the winner";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
public boolean isKingInCheck(boolean kingIsWhite) {
|
|
||||||
int kingX = -1, kingY = -1;
|
|
||||||
|
|
||||||
//Find the king
|
|
||||||
for (Piece p : getPieces()) {
|
|
||||||
if (p.getType() == PieceType.King && p.isWhite() == kingIsWhite) {
|
|
||||||
kingX = p.getX();
|
|
||||||
kingY = p.getY();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (kingX == -1)
|
|
||||||
return false;
|
|
||||||
for (Piece p : getPieces()) {
|
|
||||||
if (p.isWhite() != kingIsWhite) {
|
|
||||||
for (int[] m : getValidMoves(p)) {
|
|
||||||
if (m[0] == kingX && m[1] == kingY) {
|
|
||||||
return true; //King in check
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public boolean isCheckmate(boolean playerWhite) {
|
|
||||||
if (!isKingInCheck(playerWhite))
|
|
||||||
return false;
|
|
||||||
for (Piece p : getPieces()) {
|
|
||||||
if (p.isWhite() == playerWhite) {
|
|
||||||
for (int[] move : getValidMoves(p)) {
|
|
||||||
//simulate the move
|
|
||||||
Board copy = new Board(this);
|
|
||||||
copy.suppressCheckmateCheck = true;
|
|
||||||
Piece simPiece = copy.board[p.getY()][p.getX()];
|
|
||||||
Move m = new Move(simPiece, move[0], move[1]);
|
|
||||||
copy.playMove(m);
|
|
||||||
|
|
||||||
if (!copy.isKingInCheck(playerWhite)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public String getWinnerMessage() {
|
|
||||||
return winnerMessage;
|
|
||||||
}
|
|
||||||
public void setWinnerMessage(String message) {
|
|
||||||
this.winnerMessage = message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//manually checks for victory if needed
|
||||||
|
public boolean isCheckmate() {
|
||||||
|
gameResult.checkForVictory(this);
|
||||||
|
return gameResult.isGameOver();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,22 +49,7 @@ public class Game extends Thread {
|
||||||
|
|
||||||
private void aiPlayerTurn() {
|
private void aiPlayerTurn() {
|
||||||
if(isAITurn()) {
|
if(isAITurn()) {
|
||||||
Move move = aiPlayer.computeBestMove(new Board(board));
|
board.playMove(aiPlayer.computeBestMove(new Board(board)));
|
||||||
|
|
||||||
if (move != null) {
|
|
||||||
board.playMove(move);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (board.isKingInCheck(board.isTurnWhite())) {
|
|
||||||
System.out.println((board.isTurnWhite() ? "White" : "Black") + "is checkmated!");
|
|
||||||
board.setWinnerMessage((!board.isTurnWhite() ? "White" : "Black") + "wins by checkmate!");
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
System.out.println("It's a draw");
|
|
||||||
board.setWinnerMessage("Draw!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
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 = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 so opposite color
|
||||||
|
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<int[]> 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<int[]> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue