426 lines
14 KiB
Java
426 lines
14 KiB
Java
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<int[]> highlightedPositions = new ArrayList<>(); // List containing all board positions
|
|
private ArrayList<MoveRecord> 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<int[]> lineMoves(int x, int y, boolean isWhite, int[][] directions) {
|
|
ArrayList<int[]> 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<Piece> getPieces() {
|
|
ArrayList<Piece> 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<int[]> getValidMoves(Piece p) {
|
|
// Calculate the valid moves for each Piece type
|
|
ArrayList<int[]> 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<String> 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<Piece> 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
|
|
|
|
}
|
|
|
|
}
|