347 lines
11 KiB
Java
347 lines
11 KiB
Java
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<int[]> 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<Piece> getPieces() {
|
|
ArrayList<Piece> 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<String> 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<int[]> 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
|
|
}
|
|
} |