package backend; import java.util.ArrayList; public class Board { private int line; private int col; private Piece[][] board; // 2D array to hold pieces private int [] selectedPosition = null; // No piece selected initially private int turnNumber=0; // Tracks the number of turns elapsed 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 boolean inBounds(int x, int y) { // Verify the bounds of the board return x >= 0 && y >= 0 && x < col && y < line; } private boolean hasEnemy(int x, int y, boolean isWhite) { // Detect an enemy piece, meaning from a different color return board[y][x] != null && board[y][x].isWhite() != isWhite; } private ArrayList lineMoves(int x, int y, boolean isWhite, int[][] directions) { ArrayList result = new ArrayList<>(); for (int[] d : directions) { int nx = x + d[0], ny = y + d[1]; while (inBounds(nx, ny)) { if (board[ny][nx] == null) { result.add(new int[]{nx, ny}); } else { if (hasEnemy(nx, ny, isWhite)) { result.add(new int[]{nx, ny}); } break; } nx += d[0]; ny += d[1]; } } return result; } public Board(int colNum, int lineNum) { this.col=colNum; this.line=lineNum; this.board =new Piece [colNum][lineNum];// Create the 2D board array } public int getWidth() { return this.line; } public int getHeight() { return this.col; } public int getTurnNumber() { return this.turnNumber; } public boolean isTurnWhite() { return this.turnWhite; } public void setPiece(boolean isWhite, PieceType type, int x, int y) { // Create a new Piece object with the provided attributes Piece piece =new Piece (isWhite, type,x,y); // Place the piece on the board at the specified position if (x >= 0 && x < col && y >= 0 && y < line) { board[y][x] = piece; } else { System.out.println("Invalid position"); } } public void populateBoard() { // Puts the board in its default configuration // adding all necessary pieces at the expected starting locations PieceType[] backRow = { PieceType.Rook, PieceType.Knight, PieceType.Bishop, PieceType.Queen, PieceType.King, PieceType.Bishop, PieceType.Knight, PieceType.Rook }; // Place black pieces (false = black) for (int x=0;x<8;x++) { // Row 0: black major pieces setPiece(false,backRow[x],x,0); // Row 1: black pawns setPiece(false, PieceType.Pawn,x,1); } // Place white pieces (true = white) for (int x = 0; x < 8; x++) { // Row 6: white pawns setPiece(true, PieceType.Pawn, x, 6); // Row 7: white major pieces setPiece(true, backRow[x], x, 7); } } public void cleanBoard() { // Removes all pieces from the board, readying it to add pieces for a new game // Iterate over each row and column and set the board position to null for (int y = 0; y < line; y++) { for (int x = 0; x < col; x++) { board[y][x] = null; // Remove the piece } } this.turnNumber=0; System.out.println("Board cleaned. All pieces removed."); } public String toString() { // Returns a string representation of the board's current state StringBuilder boardString = new StringBuilder(); // To construct the string representation // Iterate through each row and column to build the string for (int row = 0; row < line; row++) { for (int col = 0; col < this.col; col++) { Piece piece = board[row][col]; if (piece != null) { boardString.append(piece.getType().getSummary()); // append the piece symbol } else { boardString.append("."); // the dot symbolizes empty space } if (col < this.col - 1) { boardString.append(" "); // add space between columns } } boardString.append("\n"); // new line after each row } return boardString.toString(); } public ArrayList getPieces() { ArrayList pieces = new ArrayList<>(); // Iterate through the 2D array to gather all non-null pieces for (int y = 0; y < line; y++) { for (int x = 0; x < col; x++) { Piece piece = board[y][x]; if (piece != null) { pieces.add(piece); // Add the piece to the list if it's not null } } } return pieces; // return the list or array of pieces } public void userTouch(int x, int y) { // Case 1: No position is selected if (selectedPosition==null) { Piece clickedPiece = board[y][x]; // Check if there is a piece at clicked position and it belongs to current player if (clickedPiece!=null && clickedPiece.isWhite()==turnWhite){ // Select this position selectedPosition = new int[] {x,y}; highlightedPositions = getValidMoves(clickedPiece); //Calculate Highlights } } // Case 2: A position is already selected else{ int selectedX = selectedPosition[0]; int selectedY = selectedPosition[1]; // If the selected position is clicked again, deselect it if(selectedX == x && selectedY == y) { selectedPosition = null; highlightedPositions.clear(); //Unhighlight } // If a piece is selected and the user clicks a new position else { // Check if the move is valid by checking if it exists in highlightedPositions boolean isValidMove = false; for (int[] pos : highlightedPositions) { if (pos[0] == x && pos[1] == y) { isValidMove = true; break; } } // Only move the piece if the destination is valid if (isValidMove) { movePiece(selectedX, selectedY, x, y); // Update turn this.turnNumber++; this.turnWhite = !this.turnWhite; } // Deselect the position after moving this.selectedPosition = null; highlightedPositions.clear();//Clear after move } } } public ArrayList getValidMoves(Piece p) { // Calculate the valid moves for each Piece type ArrayList moves = new ArrayList<>(); int x = p.getX(), y = p.getY(); boolean isWhite = p.isWhite(); switch (p.getType()) { case Pawn: int dir = isWhite ? -1 : 1; // Forward one square if (inBounds(x, y + dir) && board[y + dir][x] == null) { moves.add(new int[]{x, y + dir}); // Initial two-square move int startRow = isWhite ? 6 : 1; // Starting row for pawns if (y == startRow && inBounds(x, y + 2*dir) && board[y + 2*dir][x] == null) { moves.add(new int[]{x, y + 2*dir}); } } // Captures (diagonal) if (inBounds(x - 1, y + dir) && hasEnemy(x - 1, y + dir, isWhite)) { moves.add(new int[]{x - 1, y + dir}); } if (inBounds(x + 1, y + dir) && hasEnemy(x + 1, y + dir, isWhite)) { moves.add(new int[]{x + 1, y + dir}); } break; case Rook: moves.addAll(lineMoves(x, y, isWhite, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}})); break; case Bishop: moves.addAll(lineMoves(x, y, isWhite, new int[][]{{1, 1}, {-1, 1}, {1, -1}, {-1, -1}})); break; case Queen: moves.addAll(lineMoves(x, y, isWhite, new int[][]{ {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1} })); break; case Knight: int[][] jumps = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1}}; for (int[] j : jumps) { int nx = x + j[0], ny = y + j[1]; if (inBounds(nx, ny) && (board[ny][nx] == null || hasEnemy(nx, ny, isWhite))) moves.add(new int[]{nx, ny}); } break; case King: // Regular king moves for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx == 0 && dy == 0) continue; int nx = x + dx, ny = y + dy; if (inBounds(nx, ny) && (board[ny][nx] == null || hasEnemy(nx, ny, isWhite))) moves.add(new int[]{nx, ny}); } } break; } return moves; } public void movePiece(int fromX, int fromY, int toX, int toY) { // Additional method: moves a piece from one position to another on the board Piece movingPiece = board[fromY][fromX]; Piece capturedPiece = board[toY][toX]; // Record the move before making it moveHistory.add(new MoveRecord( movingPiece, capturedPiece, fromX, fromY, toX, toY, turnNumber, turnWhite)); // Move the piece on the board board[toY][toX] = movingPiece; // Place piece at the new position board[fromY][fromX] = null; // Clear the old position if (movingPiece != null) { // Update the piece's internal position movingPiece.setX(toX); movingPiece.setY(toY); } } public boolean isSelected(int x, int y) { return this.selectedPosition!=null && this.selectedPosition[0] == x && this.selectedPosition[1] == y; } /* saving-loading feature :*/ public String[] toFileRep() { ArrayList fileLines = new ArrayList<>(); // First line: game state (turn number and current player) fileLines.add(turnNumber + "," + (turnWhite ? "white" : "black")); // Second line: board dimensions fileLines.add(line + "," + col); // Get all pieces on the board ArrayList pieces = getPieces(); // Add one line per piece with format: pieceType,x,y,color for (Piece piece : pieces) { StringBuilder pieceInfo = new StringBuilder(); pieceInfo.append(piece.getType()).append(","); pieceInfo.append(piece.getX()).append(","); pieceInfo.append(piece.getY()).append(","); pieceInfo.append(piece.isWhite() ? "W" : "B"); fileLines.add(pieceInfo.toString()); } return fileLines.toArray(new String[0]); } public Board(String[] fileRepresentation) { // Parse game state from first line String[] gameState = fileRepresentation[0].split(","); turnNumber = Integer.parseInt(gameState[0]); turnWhite = gameState[1].equals("white"); // Parse board dimensions from second line String[] dimensions = fileRepresentation[1].split(","); line = Integer.parseInt(dimensions[0]); col = Integer.parseInt(dimensions[1]); // Initialize the board with the specified dimensions board = new Piece[line][col]; // Parse pieces from the remaining lines for (int i = 2; i < fileRepresentation.length; i++) { String[] pieceInfo = fileRepresentation[i].split(","); PieceType pieceType = PieceType.valueOf(pieceInfo[0]); int x = Integer.parseInt(pieceInfo[1]); int y = Integer.parseInt(pieceInfo[2]); boolean isWhite = pieceInfo[3].equals("W"); // Create the piece and place it on the board board[y][x] = new Piece(isWhite,pieceType, x, y); } // Initialize other state variables selectedPosition = null; highlightedPositions = new ArrayList<>(); } public boolean isHighlighted(int x, int y) { // Storing valid moves when piece is selected for (int[] pos : highlightedPositions) { if (pos[0] == x && pos[1] == y) return true; } return false; } public void undoLastMove() { // Check if there are moves to undo if (moveHistory.isEmpty()) { return; // Nothing to undo } // Get the last move MoveRecord lastMove = moveHistory.remove(moveHistory.size() - 1); // Restore the moved piece to its original position board[lastMove.fromY][lastMove.fromX] = lastMove.movedPiece; if (lastMove.movedPiece != null) { lastMove.movedPiece.setX(lastMove.fromX); lastMove.movedPiece.setY(lastMove.fromY); } // Restore the captured piece if any board[lastMove.toY][lastMove.toX] = lastMove.capturedPiece; if (lastMove.capturedPiece != null) { lastMove.capturedPiece.setX(lastMove.toX); lastMove.capturedPiece.setY(lastMove.toY); } // Restore game state turnNumber = lastMove.turnNumberAtMove; turnWhite = lastMove.turnWhiteAtMove; // Clear any selections or highlights selectedPosition = null; highlightedPositions.clear(); } public Board(Board board) { //copy the board size this.col = board.col; //number of column this.line = board.line; //number of row this.turnNumber = board.turnNumber; this.turnWhite = board.turnWhite; //copy the selected positions this.selectedPosition = board.selectedPosition == null ? null: new int[] {board.selectedPosition[0], board.selectedPosition[1]}; //Deep copy highlighted positions this.highlightedPositions = new ArrayList<>(); for (int[] pos : highlightedPositions) { //TO BE DONE } } public void playMove(Move move) { //TODO } }