445 lines
13 KiB
Java
445 lines
13 KiB
Java
package backend;
|
||
|
||
import java.util.ArrayList;
|
||
|
||
public class Board {
|
||
private int colNum;
|
||
private int lineNum;
|
||
private int turnNumber;
|
||
private boolean isWhiteTurn;
|
||
ArrayList<Piece> pieces = new ArrayList<>();
|
||
private int selectedX = -1;
|
||
private int selectedY = -1;
|
||
ArrayList<int[]> highlightedSquares = new ArrayList<>();
|
||
|
||
public Board(int colNum, int lineNum) {
|
||
this.colNum = colNum;
|
||
this.lineNum = lineNum;
|
||
this.turnNumber = 0;
|
||
this.isWhiteTurn = true; // White starts first
|
||
}
|
||
|
||
public int getWidth() {
|
||
return colNum;
|
||
}
|
||
|
||
public int getHeight() {
|
||
return lineNum;
|
||
}
|
||
|
||
public int getTurnNumber() {
|
||
return this.turnNumber;
|
||
}
|
||
|
||
public boolean isTurnWhite() {
|
||
return this.isWhiteTurn;
|
||
}
|
||
|
||
public void resetTurn() {
|
||
this.turnNumber = 0;
|
||
this.isWhiteTurn = true;
|
||
}
|
||
|
||
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
||
Piece newPiece = new Piece(x, y, isWhite, type);
|
||
pieces.add(newPiece);
|
||
}
|
||
|
||
public void populateBoard() {
|
||
for (int y=0;y<8;y++) {
|
||
for(int x=0;x<8;x++) {
|
||
if(x==0||x==7) {
|
||
if (y==0) {
|
||
pieces.add(new Piece(x,y,false, PieceType.Rook));
|
||
}
|
||
if (y==7) {
|
||
pieces.add(new Piece(x,y,true, PieceType.Rook));
|
||
}
|
||
}
|
||
if(x==1||x==6) {
|
||
if (y==0) {
|
||
pieces.add(new Piece(x,y,false, PieceType.Knight));
|
||
}
|
||
if (y==7) {
|
||
pieces.add(new Piece(x,y,true, PieceType.Knight));
|
||
}
|
||
}
|
||
if(x==2||x==5) {
|
||
if (y==0) {
|
||
pieces.add(new Piece(x,y,false, PieceType.Bishop));
|
||
}
|
||
if (y==7) {
|
||
pieces.add(new Piece(x,y,true, PieceType.Bishop));
|
||
}
|
||
}
|
||
if(x==3) {
|
||
if (y==0) {
|
||
pieces.add(new Piece(x,y,false, PieceType.Queen));
|
||
}
|
||
if (y==7) {
|
||
pieces.add(new Piece(x,y,true, PieceType.Queen));
|
||
}
|
||
}
|
||
if(x==4) {
|
||
if (y==0) {
|
||
pieces.add(new Piece(x,y,false, PieceType.King));
|
||
}
|
||
if (y==7) {
|
||
pieces.add(new Piece(x,y,true, PieceType.King));
|
||
}
|
||
}
|
||
if(y==1) {
|
||
pieces.add(new Piece(x,y,false, PieceType.Pawn));
|
||
}
|
||
if(y==6) {
|
||
pieces.add(new Piece(x,y,true, PieceType.Pawn));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void cleanBoard() {
|
||
pieces.clear();
|
||
}
|
||
|
||
public String toString() {
|
||
String result = "Turn: " + turnNumber + "\n";
|
||
result += "Current Player: " + (isWhiteTurn ? "White" : "Black") + "\n";
|
||
result += "Pieces on Board:\n";
|
||
|
||
for (Piece piece : pieces) {
|
||
result += piece + "\n";
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
public ArrayList<Piece> getPieces() {
|
||
return pieces;
|
||
}
|
||
|
||
public Piece getPieceAt(int x, int y) {
|
||
Piece foundPiece = null;
|
||
for (int i = 0; i < pieces.size(); i++) {
|
||
Piece piece = pieces.get(i);
|
||
if (piece.getX() == x && piece.getY() == y) {
|
||
foundPiece = piece;
|
||
}
|
||
}
|
||
return foundPiece;
|
||
}
|
||
|
||
public void userTouch(int x, int y) {
|
||
System.out.println("userTouch triggered at: " + x + ", " + y);
|
||
|
||
Piece selectedPiece = getPieceAt(selectedX, selectedY);
|
||
Piece clickedPiece = getPieceAt(x, y);
|
||
|
||
if (selectedPiece == null) {
|
||
if (clickedPiece != null && clickedPiece.isWhite() == isWhiteTurn) {
|
||
System.out.println("Selecting piece at: " + x + ", " + y);
|
||
selectedX = x;
|
||
selectedY = y;
|
||
highlightedSquares = getValidMoves(clickedPiece);
|
||
System.out.println("Valid moves highlighted for selected piece.");
|
||
} else {
|
||
System.out.println("No valid piece to select at: " + x + ", " + y);
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (x == selectedX && y == selectedY) {
|
||
System.out.println("Unselecting piece at: " + x + ", " + y);
|
||
selectedX = -1;
|
||
selectedY = -1;
|
||
highlightedSquares.clear();
|
||
return;
|
||
}
|
||
|
||
// Check if move is valid (square must be highlighted to avoid our previous problem of moving a piece to any square on the board)
|
||
boolean isValidMove = false;
|
||
for (int[] move : highlightedSquares) {
|
||
if (move[0] == x && move[1] == y) {
|
||
isValidMove = true;
|
||
}
|
||
}
|
||
|
||
if (!isValidMove) {
|
||
System.out.println("Invalid move — not in highlighted squares.");
|
||
return;
|
||
}
|
||
|
||
if (clickedPiece != null) {
|
||
System.out.println("Capturing piece at: " + x + ", " + y);
|
||
pieces.remove(clickedPiece);
|
||
}
|
||
|
||
System.out.println("Moving piece to: " + x + ", " + y);
|
||
selectedPiece.setX(x);
|
||
selectedPiece.setY(y);
|
||
|
||
turnNumber++;
|
||
isWhiteTurn = !isWhiteTurn;
|
||
|
||
selectedX = -1;
|
||
selectedY = -1;
|
||
highlightedSquares.clear();
|
||
|
||
// After move completed, check for check and checkmate
|
||
for (int i = 0; i < 2; i++) {
|
||
boolean isWhite = (i == 0);
|
||
|
||
if (isKingInCheck(isWhite)) {
|
||
System.out.println((isWhite ? "White" : "Black") + " is in check!");
|
||
|
||
if (isCheckmate(isWhite)) {
|
||
System.out.println((isWhite ? "White" : "Black") + " is in checkmate!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public boolean isSelected(int x, int y) {
|
||
return x == selectedX && y == selectedY;
|
||
}
|
||
|
||
/* saving-loading feature :*/
|
||
//this public method returns String[]
|
||
public String[] toFileRep() { //converts the game into a chain of characters : state of the game
|
||
ArrayList<String> lines = new ArrayList<>();//creates a list arraylist to store each line of the save data as a string
|
||
|
||
//number of tour
|
||
lines.add(String.valueOf(turnNumber));//It's converted to a string using String.valueOf
|
||
|
||
//color of the player
|
||
lines.add(String.valueOf(isWhiteTurn));//same
|
||
|
||
// piece type position and color
|
||
for (Piece piece : pieces) { //loop through all pieces of the game
|
||
String line = piece.getType() + "," + piece.getX() + "," + piece.getY() + "," + piece.isWhite();
|
||
lines.add(line);
|
||
}
|
||
|
||
return lines.toArray(new String[0]); //Converts the ArrayList to a fixed-size String[] and returns it
|
||
}
|
||
|
||
//constructor for the Board class.
|
||
public Board(String[] array) { //takes the previous string and reconstruct the game state from it
|
||
this.colNum = 8;//dimensions initialized
|
||
this.lineNum = 8;
|
||
|
||
this.turnNumber = Integer.parseInt(array[0]);//array[0] is the turn number (converted from string to int),
|
||
|
||
this.isWhiteTurn = Boolean.parseBoolean(array[1]);//array[1] is the current player’s turn (converted from string to boolean).
|
||
|
||
this.pieces = new ArrayList<>();//initialize empty list to hold all pieces
|
||
|
||
for (int i = 2; i < array.length; i++) {
|
||
|
||
String[] parts = array[i].split(",");
|
||
|
||
PieceType type = PieceType.valueOf(parts[0]);
|
||
int x = Integer.parseInt(parts[1]);
|
||
int y = Integer.parseInt(parts[2]);
|
||
boolean isWhite = Boolean.parseBoolean(parts[3]);
|
||
|
||
pieces.add(new Piece(x, y, isWhite, type)); //Creates a new Piece with the extracted data and adds it to the pieces list.
|
||
}
|
||
}
|
||
|
||
/* The following methods require more work ! */
|
||
|
||
public boolean isHighlighted(int x, int y) {
|
||
for (int[] pos : highlightedSquares) {
|
||
if (pos[0] == x && pos[1] == y) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void undoLastMove() {
|
||
//TODO
|
||
|
||
}
|
||
|
||
public Board(Board board) {
|
||
this.colNum = board.colNum;
|
||
this.lineNum = board.lineNum;
|
||
this.turnNumber = board.turnNumber;
|
||
this.isWhiteTurn = board.isWhiteTurn;
|
||
|
||
this.pieces = new ArrayList<>();
|
||
for (int i = 0; i < board.pieces.size(); i++) {
|
||
Piece original = board.pieces.get(i);
|
||
Piece copy = new Piece(original.getX(), original.getY(), original.isWhite(), original.getType());
|
||
this.pieces.add(copy);
|
||
}
|
||
|
||
this.selectedX = -1;
|
||
this.selectedY = -1;
|
||
this.highlightedSquares = new ArrayList<>();
|
||
}
|
||
|
||
public void playMove(Move move) {
|
||
//TODO
|
||
|
||
}
|
||
|
||
public ArrayList<int[]> getValidMoves(Piece piece) {
|
||
MoveConditions moveHelper = new MoveConditions(piece, this);
|
||
|
||
switch (piece.getType()) {
|
||
case Pawn:
|
||
return moveHelper.getPawnMoves();
|
||
case Knight:
|
||
return moveHelper.getKnightMoves();
|
||
case Rook:
|
||
return moveHelper.getRookMoves();
|
||
case Bishop:
|
||
return moveHelper.getBishopMoves();
|
||
case Queen:
|
||
return moveHelper.getQueenMoves();
|
||
case King:
|
||
return moveHelper.getKingMoves();
|
||
default:
|
||
return new ArrayList<>();
|
||
}
|
||
}
|
||
|
||
public boolean isKingInCheck(boolean whiteKing) {
|
||
Piece king = null;
|
||
|
||
for (int i = 0; i < pieces.size(); i++) {
|
||
Piece p = pieces.get(i);
|
||
if (p.getType() == PieceType.King && p.isWhite() == whiteKing) {
|
||
king = p;
|
||
}
|
||
}
|
||
|
||
boolean inCheck = false;
|
||
|
||
if (king != null) {
|
||
int kingX = king.getX();
|
||
int kingY = king.getY();
|
||
|
||
for (int i = 0; i < pieces.size(); i++) {
|
||
Piece p = pieces.get(i);
|
||
if (p.isWhite() != whiteKing && p.getType() != PieceType.King) {
|
||
ArrayList<int[]> moves = getValidMoves(p);
|
||
|
||
for (int j = 0; j < moves.size(); j++) {
|
||
int[] move = moves.get(j);
|
||
if (move[0] == kingX && move[1] == kingY) {
|
||
inCheck = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return inCheck;
|
||
}
|
||
|
||
public boolean isCheckmate(boolean whiteKing) {
|
||
boolean kingInCheck = isKingInCheck(whiteKing);
|
||
boolean hasEscape = false;
|
||
|
||
// 1. If the king is not in check, it's never checkmate
|
||
if (!kingInCheck) {
|
||
return false;
|
||
}
|
||
|
||
// 2. Try every possible move of every piece belonging to the checked side
|
||
for (int i = 0; i < pieces.size(); i++) {
|
||
Piece piece = pieces.get(i);
|
||
|
||
if (piece.isWhite() == whiteKing) {
|
||
ArrayList<int[]> rawMoves = getValidMoves(piece);
|
||
|
||
for (int j = 0; j < rawMoves.size(); j++) {
|
||
int[] move = rawMoves.get(j);
|
||
int newX = move[0];
|
||
int newY = move[1];
|
||
|
||
// 3. Simulate this move on a copied board
|
||
Board simBoard = new Board(this);
|
||
|
||
// 4. Find the corresponding piece on the cloned board
|
||
Piece simPiece = null;
|
||
for (int k = 0; k < simBoard.getPieces().size(); k++) {
|
||
Piece p = simBoard.getPieces().get(k);
|
||
if (p.getX() == piece.getX() && p.getY() == piece.getY()
|
||
&& p.getType() == piece.getType()
|
||
&& p.isWhite() == piece.isWhite()) {
|
||
simPiece = p;
|
||
}
|
||
}
|
||
|
||
// 5. Apply the move and check if king is still in check
|
||
if (simPiece != null) {
|
||
Piece captured = simBoard.getPieceAt(newX, newY);
|
||
if (captured != null) {
|
||
simBoard.getPieces().remove(captured);
|
||
}
|
||
|
||
simPiece.setX(newX);
|
||
simPiece.setY(newY);
|
||
|
||
if (!simBoard.isKingInCheck(whiteKing)) {
|
||
hasEscape = true;
|
||
System.out.println("ESCAPE FOUND: " + piece.getType() + " from (" + piece.getX() + "," + piece.getY() + ") to (" + newX + "," + newY + ")");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 6. If the king is in check and no move avoids it → checkmate
|
||
return kingInCheck && !hasEscape;
|
||
}
|
||
|
||
|
||
/*
|
||
private void enPassant(Board board, List<Move> moves) {
|
||
int x = this.x;
|
||
int y = this.y;
|
||
|
||
if (isWhite() == true && this.y == 3) {
|
||
if(isEnPassant(board, new Piece(x - 1, y)))
|
||
moves.add(new Move(this, new Piece(x - 1, y - 1),
|
||
board.getPieceAt(new Piece(x - 1, y))));
|
||
if(canCaptureEnPassant(board, new Piece(x + 1, y)))
|
||
moves.add(new Move(this, new Piece(x + 1, y - 1),
|
||
board.getPieceAt(new Piece(x + 1, y))));
|
||
}
|
||
if (isWhite() == false && this.y == 4) {
|
||
if(isEnPassant(board, new Piece(x - 1, y)))
|
||
moves.add(new Move(this, new Piece(x - 1, y + 1),
|
||
board.getPieceAt(new Piece(x - 1, y))));
|
||
if(canCaptureEnPassant(board, new Piece(x + 1, y)))
|
||
moves.add(new Move(this, new Piece(x + 1, y + 1),
|
||
board.getPieceAt(new Piece(x + 1, y))));
|
||
}
|
||
}
|
||
|
||
|
||
* Checks if the pawn can capture another pawn by en passant
|
||
* @param pt location of the other pawn
|
||
* @return true if can be captured
|
||
|
||
|
||
private boolean isEnPassant(Board board, Point pt) {
|
||
Piece temp = board.getPieceAt(pt);
|
||
if(temp != null) {
|
||
if (temp instanceof Pawn && temp.getColor() != this.color)
|
||
if (((Pawn)temp).enPassantOk)
|
||
return true;
|
||
return false;
|
||
}
|
||
*/
|
||
|
||
|
||
|
||
}
|