OOP_2A5_Project/src/backend/Board.java

435 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 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 players 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;
}
}