package backend; import java.util.ArrayList; public class Board { private int selectedX = -1; // negative value means impossible x and y so unselected private int selectedY = -1; private int turnNumber = 0; // tracks current turn private int width; // enables to define the dimensions of board private int height; private Piece[][] board; // 2D array chess board private ArrayList highlightedPositions = new ArrayList<>(); // list of valid positions to highlight public Board(int colNum, int lineNum) { this.width = colNum; this.height = lineNum; this.board = new Piece[width][height]; // first empty board *********REVIEW************ clearConsole(); System.out.println(toString()); // print the chess at the beginning of the game } public int getWidth() { return width; } public int getHeight() { return height; } // new piece on the board at x,y (More specifically changes the empty cell of coordinates x,y with a new chess piece) public void setPiece(boolean isWhite, PieceType type, int x, int y) { board[x][y] = new Piece(x, y, type, isWhite); } public boolean isTurnWhite() { if (turnNumber % 2 == 0) { // even turns including 0 are white's ones (% calculates the reminder of the euclidean division) return true; } else { // same reasoning, odd turns are black's ones return false; } } public int getTurnNumber() { // this class enables to obtain the current turn number while increment adds 1 to this value for each turn return turnNumber; // Necessarly in two functions to get rid of an infinite loop ****WHY**** } public void incrementTurn() { turnNumber++; } // set up the classic chess board taking it as a matrix and putting each corresponding starting piece at its place 0,0 is the top left spot of the board public void populateBoard() { // Black setPiece(false, PieceType.Rook, 0, 0); setPiece(false, PieceType.Knight, 1, 0); setPiece(false, PieceType.Bishop, 2, 0); setPiece(false, PieceType.Queen, 3, 0); setPiece(false, PieceType.King, 4, 0); setPiece(false, PieceType.Bishop, 5, 0); setPiece(false, PieceType.Knight, 6, 0); setPiece(false, PieceType.Rook, 7, 0); // Black pawns for (int i = 0; i < 8; i++) { setPiece(false, PieceType.Pawn, i, 1); } // White pawns for (int i = 0; i < 8; i++) { setPiece(true, PieceType.Pawn, i, 6); } // White setPiece(true, PieceType.Rook, 0, 7); setPiece(true, PieceType.Knight, 1, 7); setPiece(true, PieceType.Bishop, 2, 7); setPiece(true, PieceType.Queen, 3, 7); setPiece(true, PieceType.King, 4, 7); setPiece(true, PieceType.Bishop, 5, 7); setPiece(true, PieceType.Knight, 6, 7); setPiece(true, PieceType.Rook, 7, 7); } public void cleanBoard() { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { board[x][y] = null; // each position becomes empty } } } private void clearConsole() { for (int i = 0; i < 50; i++) { System.out.println(); // Print 50 empty lines to "clear" the console } } public String toString() { StringBuilder str = new StringBuilder(); str.append(" A B C D E F G H\n"); // columns letter at the top // representation of the rows for (int y = 0; y < height; y++) { str.append(8 - y).append(" "); // row number on the left for (int x = 0; x < width; x++) { if (board[x][y] == null) { str.append("- "); // empty positions } else { // convert each piece of both color into a character Piece piece = board[x][y]; char pieceChar; switch (piece.getType()) { // switch function avoids too many if-else case King: pieceChar = 'K'; break; case Queen: pieceChar = 'Q'; break; case Bishop: pieceChar = 'B'; break; case Knight: pieceChar = 'N'; break; // N because we already have King case Rook: pieceChar = 'R'; break; case Pawn: pieceChar = 'P'; break; default: pieceChar = '?'; break; // safety net } // Make black pieces in lowercase if (!piece.isWhite()) { pieceChar = Character.toLowerCase(pieceChar); } str.append(pieceChar).append(" "); // gives structure to the output } } str.append("\n"); // change of row } // Additional infos for a proper output str.append("Turn ").append(getTurnNumber()).append(": "); str.append(isTurnWhite() ? "White" : "Black"); return str.toString(); } // list the placement of the pieces on the board public ArrayList getPieces() { ArrayList pieces = new ArrayList<>(); // collect infos for the non-empty positions 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; } // user clicks on the board public void userTouch(int x, int y) { if (selectedX == -1 && selectedY == -1) { // check if the position is empty and the color if (board[x][y] != null && board[x][y].isWhite() == isTurnWhite()) { // select it as active location selectedX = x; selectedY = y; highlightedPositions = getValidMoves(board[x][y]); // compute valid moves } } else { if (x == selectedX && y == selectedY) { // unselect it selectedX = -1; selectedY = -1; highlightedPositions.clear(); } else { // allow move if valid destination boolean valid = false; for (int[] pos : highlightedPositions) { if (pos[0] == x && pos[1] == y) { valid = true; break; } } if (valid) { Piece pieceToMove = board[selectedX][selectedY]; board[x][y] = new Piece(x, y, pieceToMove.getType(), pieceToMove.isWhite()); board[selectedX][selectedY] = null; incrementTurn(); } // reset selection selectedX = -1; selectedY = -1; highlightedPositions.clear(); clearConsole(); System.out.println(toString()); } } } public boolean isSelected(int x, int y) { return (x == selectedX && y == selectedY); // true if matching position } public boolean isHighlighted(int x, int y) { // checking for a given position if the square is highlighted or not for (int[] pos : highlightedPositions) { if (pos[0] == x && pos[1] == y) { return true; } } return false; } /* utility methods */ private boolean isInBounds(int x, int y) { return x >= 0 && x < width && y >= 0 && y < height; } private void addLinearMoves(ArrayList moves, int x, int y, Piece piece, int dx, int dy) { int nx = x + dx; int ny = y + dy; while (isInBounds(nx, ny)) { if (board[nx][ny] == null) { moves.add(new int[]{nx, ny}); } else { if (board[nx][ny].isWhite() != piece.isWhite()) { moves.add(new int[]{nx, ny}); } break; } nx += dx; ny += dy; } } private ArrayList getValidMoves(Piece piece) { ArrayList moves = new ArrayList<>(); int x = piece.getX(); int y = piece.getY(); switch (piece.getType()) { case Pawn: int direction = piece.isWhite() ? -1 : 1; int nextY = y + direction; // forward move if (isInBounds(x, nextY) && board[x][nextY] == null) { moves.add(new int[]{x, nextY}); // double move from starting position int startRow = piece.isWhite() ? 6 : 1; int doubleStepY = y + 2 * direction; if (y == startRow && isInBounds(x, doubleStepY) && board[x][doubleStepY] == null) { moves.add(new int[]{x, doubleStepY}); } } // diagonal captures for (int dx = -1; dx <= 1; dx += 2) { int nx = x + dx; if (isInBounds(nx, nextY) && board[nx][nextY] != null && board[nx][nextY].isWhite() != piece.isWhite()) { moves.add(new int[]{nx, nextY}); } } break; //for each piece, we calculate the positions it can end up in from an initial position case Rook: addLinearMoves(moves, x, y, piece, 1, 0); addLinearMoves(moves, x, y, piece, -1, 0); addLinearMoves(moves, x, y, piece, 0, 1); addLinearMoves(moves, x, y, piece, 0, -1); break; case Bishop: addLinearMoves(moves, x, y, piece, 1, 1); addLinearMoves(moves, x, y, piece, -1, 1); addLinearMoves(moves, x, y, piece, 1, -1); addLinearMoves(moves, x, y, piece, -1, -1); break; case Queen: for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx != 0 || dy != 0) { addLinearMoves(moves, x, y, piece, dx, dy); } } } break; case King: for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { if (dx != 0 || dy != 0) { int nx = x + dx; int ny = y + dy; if (isInBounds(nx, ny) && (board[nx][ny] == null || board[nx][ny].isWhite() != piece.isWhite())) { moves.add(new int[]{nx, ny}); } } } } break; case Knight: int[][] jumps = { {1, 2}, {2, 1}, {-1, 2}, {-2, 1}, // possible moves for {-1, -2}, {-2, -1}, {1, -2}, {2, -1} }; for (int[] j : jumps) { int nx = x + j[0]; int ny = y + j[1]; if (isInBounds(nx, ny) && (board[nx][ny] == null || board[nx][ny].isWhite() != piece.isWhite())) { moves.add(new int[]{nx, ny}); } } break; } return moves; } /* saving-loading feature : */ public String[] toFileRep() { // TODO return null; } public Board(String[] array) { // TODO } /* additional functionality to implement later */ public void undoLastMove() { // TODO } public void playMove(Move move) { // TODO } public Board(Board board) { // TODO } }