package backend; import java.util.ArrayList; public class Board { public int width; public int height; private Piece[][] board; private boolean hasSelectedPiece = false; private int selectedX = -1; private int selectedY = -1; private int turnNumber = 0; private boolean turnWhite = true; private ArrayList highlightedSquares = new ArrayList<>(); private int[] enPassantTarget = null; // [x,y] coordinates of en passant target square private Move moveHelper = new Move(); public Board(int colNum, int lineNum) { this.width = colNum; this.height = lineNum; this.board = new Piece[width][height]; } public int getWidth() { return width; } public int getHeight() { return height; } public int getTurnNumber() { return turnNumber; } public boolean isTurnWhite() { return turnWhite; } public void setPiece(boolean isWhite, PieceType type, int x, int y) { if (x >= 0 && x < width && y >= 0 && y < height) { board[x][y] = new Piece(x, y, isWhite, type); } } public void populateBoard() { cleanBoard(); // White pawns for (int x = 0; x < 8; x++) { setPiece(true, PieceType.Pawn, x, 1); } // Black pawns for (int x = 0; x < 8; x++) { setPiece(false, PieceType.Pawn, x, 6); } PieceType[] backRow = { PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen, PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook }; // White back row for (int x = 0; x < 8; x++) { setPiece(true, backRow[x], x, 0); } // Black back row for (int x = 0; x < 8; x++) { setPiece(false, backRow[x], x, 7); } } public void cleanBoard() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { board[x][y] = null; } } } public String toString() { StringBuilder stringboard= new StringBuilder(); for (int row = height - 1; row >= 0; row--) { for (int column = 0; column < width; column++) { Piece piece = board[column][row]; if (piece == null) { stringboard.append(". "); } else { char sym = piece.getType().name().charAt(0); stringboard.append(piece.isWhite() ? sym : Character.toLowerCase(sym)) .append(' '); } } stringboard.append("\n"); } stringboard.append(" "); for (int x = 0; x < width; x++) { stringboard.append((char)('a' + x)).append(' '); } stringboard.append("\n"); stringboard.append("Turn: ").append(isTurnWhite() ? "White" : "Black"); return stringboard.toString(); } public ArrayList getPieces() { ArrayList pieces = new ArrayList<>(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (board[x][y] != null) { pieces.add(board[x][y]); } } } return pieces; } public boolean isSelected(int x, int y) { return hasSelectedPiece && selectedX == x && selectedY == y; } public void userTouch(int x, int y) { if (x < 0 || x >= width || y < 0 || y >= height) return; Piece clicked = board[x][y]; if (!hasSelectedPiece) { if (clicked != null && clicked.isWhite() == turnWhite) { // Select piece selectedX = x; selectedY = y; hasSelectedPiece = true; highlightedSquares = moveHelper.getValidMoves(clicked, board, width, height, enPassantTarget, this); } } else { // Check if clicked again on the same square to unselect if (selectedX == x && selectedY == y) { hasSelectedPiece = false; highlightedSquares.clear(); } // If clicked on a highlighted square, move there else if (isHighlighted(x, y)) { Piece selectedPiece = board[selectedX][selectedY]; // Check if this is an en passant capture boolean isEnPassant = selectedPiece.getType() == PieceType.Pawn && enPassantTarget != null && x == enPassantTarget[0] && y == enPassantTarget[1] && board[x][y] == null; // Move piece previousBoard = cloneBoard(board); board[x][y] = selectedPiece; board[selectedX][selectedY] = null; selectedPiece.setX(x); selectedPiece.setY(y); selectedPiece.setMoved(true); // ✅ Marque la pièce comme ayant bougé // Déplacement de la tour si roque if (selectedPiece.getType() == PieceType.King && Math.abs(x - selectedX) == 2) { if (x > selectedX) { // Petit roque (côté roi) Piece rook = board[7][y]; board[5][y] = rook; board[7][y] = null; rook.setX(5); rook.setMoved(true); } else { // Grand roque (côté dame) Piece rook = board[0][y]; board[3][y] = rook; board[0][y] = null; rook.setX(3); rook.setMoved(true); } } // If en passant, remove the captured pawn if (isEnPassant) { int capturedPawnY = selectedY; // The pawn is beside, not in front board[x][capturedPawnY] = null; } // Set en passant target if pawn moved two squares enPassantTarget = null; if (selectedPiece.getType() == PieceType.Pawn && Math.abs(y - selectedY) == 2) { enPassantTarget = new int[]{x, (selectedY + y) / 2}; } // Update turn turnWhite = !turnWhite; turnNumber++; // Clear selection & highlights hasSelectedPiece = false; highlightedSquares.clear(); } // Invalid move: just unselect else { hasSelectedPiece = false; highlightedSquares.clear(); } } } /* saving-loading feature */ public String[] toFileRep() { ArrayList fileLines = new ArrayList<>(); fileLines.add(turnNumber + "," + (turnWhite ? "white" : "black")); fileLines.add(width + "," + height); for (Piece piece : getPieces()) { StringBuilder sb = new StringBuilder(); sb.append(piece.getType()) // e.g. "Pawn" .append(",").append(piece.getX()) // file X .append(",").append(piece.getY()) // file Y .append(",").append(piece.isWhite() ? "W" : "B"); fileLines.add(sb.toString()); } return fileLines.toArray(new String[0]); } public Board(String[] array) { String[] gameState = array[0].split(","); turnNumber = Integer.parseInt(gameState[0]); turnWhite = gameState[1].equals("white"); String[] dims = array[1].split(","); width = Integer.parseInt(dims[0]); height = Integer.parseInt(dims[1]); board = new Piece[width][height]; for (int i = 2; i < array.length; i++) { String[] p = array[i].split(","); PieceType type = PieceType.valueOf(p[0]); int x = Integer.parseInt(p[1]); int y = Integer.parseInt(p[2]); boolean isWhite = p[3].equals("W"); board[x][y] = new Piece(x, y, isWhite, type); } hasSelectedPiece = false; selectedX = selectedY = -1; highlightedSquares.clear(); } /* 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 boolean isInCheck(boolean white) { // Trouver le roi for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Piece p = board[x][y]; if (p != null && p.getType() == PieceType.King && p.isWhite() == white) { return isSquareAttacked(x, y, !white); } } } return false; } public boolean isSquareAttacked(int x, int y, boolean byWhite) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { Piece p = board[i][j]; if (p != null && p.isWhite() == byWhite) { ArrayList moves = moveHelper.getValidMoves(p, board, width, height, enPassantTarget, this); for (int[] m : moves) { if (m[0] == x && m[1] == y) { return true; } } } } } return false; } private Piece[][] previousBoard = null; private Piece[][] cloneBoard(Piece[][] original) { Piece[][] copy = new Piece[width][height]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (original[i][j] != null) { Piece p = original[i][j]; copy[i][j] = new Piece(p.getX(), p.getY(), p.isWhite(), p.getType()); copy[i][j].setMoved(p.hasMoved()); } } } return copy; } public void undoLastMove() { if (previousBoard != null) { board = cloneBoard(previousBoard); // Restore the board previousBoard = null; // Clear saved state hasSelectedPiece = false; // Deselect piece highlightedSquares.clear(); // Remove highlights turnWhite = !turnWhite; // Go back to previous player turnNumber--; // Go back a turn } } public Board(Board board) { // TODO } public void playMove(Move move) { // TODO } }