435 lines
11 KiB
Java
435 lines
11 KiB
Java
package backend;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
public class Board {
|
|
|
|
private int colNum;
|
|
private int lineNum;
|
|
private Piece[][] board;
|
|
private int x;
|
|
private int y;
|
|
private int turns;
|
|
private boolean whiteTurn;
|
|
private boolean enPassant;
|
|
private int pawnX;
|
|
private int pawnY;
|
|
private int enPassantX;
|
|
private int enPassantY;
|
|
private boolean whiteRookLeft;
|
|
private boolean whiteRookRight;
|
|
private boolean blackRookLeft;
|
|
private boolean blackRookRight;
|
|
private boolean whiteKing;
|
|
private boolean blackKing;
|
|
private boolean castlingRight;
|
|
private boolean castlingLeft;
|
|
ArrayList<String> states;
|
|
|
|
// CONSTRUCTOR
|
|
public Board(int colNum, int lineNum) {
|
|
this.colNum = colNum;
|
|
this.lineNum = lineNum;
|
|
this.board = new Piece[lineNum][colNum];
|
|
this.x = -1;
|
|
this.y = -1;
|
|
turns = 0;
|
|
whiteTurn = true;
|
|
|
|
enPassant = false;
|
|
pawnX = -1;
|
|
pawnY = -1;
|
|
enPassantX = -1;
|
|
enPassantY = -1;
|
|
whiteRookLeft = false;
|
|
whiteRookRight = false;
|
|
blackRookLeft = false;
|
|
blackRookRight = false;
|
|
whiteKing = false;
|
|
blackKing = false;
|
|
castlingRight = false;
|
|
castlingLeft = false;
|
|
states = new ArrayList<>();
|
|
}
|
|
|
|
// GETTERS
|
|
public int getWidth() {
|
|
return this.colNum;
|
|
}
|
|
|
|
public int getHeight() {
|
|
return this.lineNum;
|
|
}
|
|
|
|
public int getTurnNumber() {
|
|
return turns;
|
|
}
|
|
|
|
public boolean isTurnWhite() {
|
|
return whiteTurn;
|
|
}
|
|
|
|
// INITIALISE THE BOARD
|
|
public void initialise() {
|
|
x = -1;
|
|
y = -1;
|
|
turns = 0;
|
|
whiteTurn = true;
|
|
|
|
enPassant = false;
|
|
pawnX = -1;
|
|
pawnY = -1;
|
|
enPassantX = -1;
|
|
enPassantY = -1;
|
|
whiteRookLeft = false;
|
|
whiteRookRight = false;
|
|
blackRookLeft = false;
|
|
blackRookRight = false;
|
|
whiteKing = false;
|
|
blackKing = false;
|
|
states = new ArrayList<>();
|
|
}
|
|
|
|
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
|
|
board[y][x] = new Piece(isWhite, type, x, y);
|
|
}
|
|
|
|
public void populateBoard() {
|
|
for (int i = 0; i < lineNum; i++) {
|
|
boolean white = (i > 5);
|
|
if (i == 1 || i == 6) {
|
|
for (int j = 0; j < colNum; j++) {
|
|
setPiece(white, PieceType.Pawn, j, i);
|
|
}
|
|
}
|
|
else if (i == 0 || i == 7){
|
|
setPiece(white, PieceType.Rook, 0, i);
|
|
setPiece(white, PieceType.Rook, 7, i);
|
|
setPiece(white, PieceType.Knight, 1, i);
|
|
setPiece(white, PieceType.Knight, 6, i);
|
|
setPiece(white, PieceType.Bishop, 2, i);
|
|
setPiece(white, PieceType.Bishop, 5, i);
|
|
setPiece(white, PieceType.Queen, 3, i);
|
|
setPiece(white, PieceType.King, 4, i);
|
|
}
|
|
}
|
|
states.add(toString());
|
|
}
|
|
|
|
public void cleanBoard() {
|
|
initialise();
|
|
for (int i = 0; i < lineNum; i++) {
|
|
for (int j = 0; j < colNum; j++) {
|
|
board[i][j] = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// WRITE THE BOARD AS A READABLE STRING
|
|
public String toString() {
|
|
String str = "";
|
|
// iterate through lines
|
|
for (int i = 0; i < lineNum; i++) {
|
|
// iterate through columns
|
|
for (int j = 0; j < colNum; j++) {
|
|
// write the corresponding letters depending on the piece on the board
|
|
if (board[i][j] == null) {
|
|
str += " ";
|
|
}
|
|
else if (board[i][j].isWhite()) {
|
|
str += "W" + board[i][j].getType().getSummary();
|
|
}
|
|
else if (board[i][j].isWhite() == false) {
|
|
str += "B" + board[i][j].getType().getSummary();
|
|
}
|
|
if (j != colNum-1) {
|
|
str += ",";
|
|
}
|
|
}
|
|
str += "\n";
|
|
}
|
|
String turn = "B";
|
|
if (isTurnWhite()) {
|
|
turn = "W";
|
|
}
|
|
str += turn;
|
|
return str;
|
|
}
|
|
|
|
// LIST THE PIECES OF THE BOARD
|
|
public ArrayList<Piece> getPieces() {
|
|
ArrayList<Piece> pieces = new ArrayList<>();
|
|
for (int i = 0; i < colNum; i++) {
|
|
for (int j = 0; j < lineNum; j++) {
|
|
if (board[j][i] != null) {
|
|
pieces.add(board[j][i]);
|
|
}
|
|
}
|
|
}
|
|
return pieces;
|
|
}
|
|
|
|
public boolean inBoard(int x, int y) {
|
|
if (x > -1 && x < colNum && y > -1 && y < lineNum) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public Piece getPieceAt(int x, int y) {
|
|
if (inBoard(x,y)) {
|
|
return board[y][x];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// PROCESS THE USER CLICK
|
|
public void userTouch(int x, int y) {
|
|
// there have been no preselected location (no piece is selected)
|
|
if (this.x == -1 && this.y == -1) {
|
|
// if the location selected has a piece and the piece has the right color
|
|
if (board[y][x] != null && board[y][x].isWhite() == whiteTurn) {
|
|
// update coordinates
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
}
|
|
// a piece is already selected (so the new click is where the user wants to move the piece)
|
|
else {
|
|
Move move = new Move(this.x,this.y,x,y);
|
|
// if the new location is the same as before, de-selects the piece and no move happens
|
|
if (this.x == x && this.y == y || board[this.y][this.x] == null) {
|
|
this.x = -1;
|
|
this.y = -1;
|
|
}
|
|
// the new location is highlighted, meaning it is a legal displacement
|
|
else if (isHighlighted(x,y)) {
|
|
// handling en passant
|
|
if (this.enPassant == true && board[this.y][this.x].getType() == PieceType.Pawn && x == enPassantX && y == enPassantY) {
|
|
board[pawnY][pawnX] = null;
|
|
playMove(move);
|
|
}
|
|
|
|
// castling to the left
|
|
else if (this.castlingLeft && x == this.x-2) {
|
|
if (board[this.y][this.x].isWhite()) {
|
|
// rook displacement (white left)
|
|
playMove(new Move(0,7,x+1,y));
|
|
}
|
|
else {
|
|
// rook displacement (black left)
|
|
playMove(new Move(0,0,x+1,y));
|
|
}
|
|
// king displacement
|
|
playMove(move);
|
|
}
|
|
|
|
// castling to the right
|
|
else if (this.castlingRight && x == this.x+2) {
|
|
if (board[this.y][this.x].isWhite()) {
|
|
// rook displacement (white right)
|
|
playMove(new Move(7,7,x-1,y));
|
|
}
|
|
else {
|
|
// rook displacement (black right)
|
|
playMove(new Move(7,0,x-1,y));
|
|
}
|
|
// king displacement
|
|
playMove(move);
|
|
}
|
|
|
|
// basic legal move
|
|
else {
|
|
// verify if the pawn goes two steps forward (to know if en passant will be possible for the opponent)
|
|
if (board[this.y][this.x].getType() == PieceType.Pawn && (y == this.y+2 || y == this.y-2)) {
|
|
enPassant = true;
|
|
pawnX = x;
|
|
pawnY = y;
|
|
}
|
|
else {
|
|
enPassant = false;
|
|
pawnX = -1;
|
|
pawnX = -1;
|
|
}
|
|
|
|
// check if rooks or kings are beeing moved to enable (or not) castling later
|
|
if (board[this.y][this.x].getType() == PieceType.Rook) {
|
|
if (this.x == 0) {
|
|
if (board[this.y][this.x].isWhite() && whiteRookLeft == false) {
|
|
whiteRookLeft = true;
|
|
}
|
|
else if (board[this.y][this.x].isWhite() == false && blackRookLeft == false) {
|
|
blackRookLeft = true;
|
|
}
|
|
}
|
|
else if (this.x == 7) {
|
|
if (board[this.y][this.x].isWhite() && whiteRookRight == false) {
|
|
whiteRookRight = true;
|
|
}
|
|
else if (board[this.y][this.x].isWhite() == false && blackRookRight == false) {
|
|
blackRookRight = true;
|
|
}
|
|
}
|
|
}
|
|
else if (board[this.y][this.x].getType() == PieceType.King) {
|
|
if (board[this.y][this.x].isWhite()) {
|
|
whiteKing = true;
|
|
}
|
|
else if (board[this.y][this.x].isWhite() == false) {
|
|
blackKing = true;
|
|
}
|
|
}
|
|
playMove(move);
|
|
}
|
|
turns += 1;
|
|
this.x = -1;
|
|
this.y = -1;
|
|
whiteTurn = !whiteTurn;
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isSelected(int x, int y) {
|
|
if (this.x == x && this.y == y) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* saving-loading feature :*/
|
|
|
|
public String[] toFileRep() {
|
|
String myFile = toString();
|
|
String[] myArray = myFile.split("\n");
|
|
return myArray;
|
|
}
|
|
|
|
public Board(String[] array) {
|
|
this.colNum = 8;
|
|
this.lineNum = 8;
|
|
this.board = new Piece[lineNum][colNum];
|
|
this.x = -1;
|
|
this.y = -1;
|
|
//this.turns = turns;
|
|
|
|
String[] line;
|
|
boolean white;
|
|
|
|
for (int j = 0; j < colNum; j++) {
|
|
line = array[j].split(",");
|
|
for (int i = 0; i < lineNum; i++) {
|
|
if (line[i].charAt(0) != ' ') {
|
|
white = false;
|
|
if (line[i].charAt(0) == 'W') {
|
|
white = true;
|
|
}
|
|
Piece piece = new Piece(white, PieceType.fromSummary(line[i].charAt(1)), i, j);
|
|
board[j][i] = new Piece(piece);
|
|
}
|
|
}
|
|
}
|
|
if (array[lineNum] == "B") {
|
|
whiteTurn = false;
|
|
}
|
|
else {
|
|
whiteTurn = true;
|
|
}
|
|
}
|
|
|
|
|
|
/* The following methods require more work ! */
|
|
|
|
public boolean isHighlighted(int x, int y) {
|
|
boolean king;
|
|
boolean rookRight;
|
|
boolean rookLeft;
|
|
|
|
if (this.x != -1 && this.y != -1) {
|
|
if (board[this.y][this.x].isWhite()) {
|
|
king = whiteKing;
|
|
rookRight = whiteRookRight;
|
|
rookLeft = whiteRookLeft;
|
|
}
|
|
else {
|
|
king = blackKing;
|
|
rookRight = blackRookRight;
|
|
rookLeft = blackRookLeft;
|
|
}
|
|
MoveCalculator legalMoves = new MoveCalculator(this.board);
|
|
ArrayList<int[]> moves = legalMoves.getMove(board[this.y][this.x].getType(), board[this.y][this.x].isWhite(), this.x, this.y, king, rookRight, rookLeft, enPassant, pawnX, pawnY);
|
|
this.castlingLeft = legalMoves.getCastlingLeft();
|
|
this.castlingRight = legalMoves.getCastlingRight();
|
|
this.enPassantX = legalMoves.getEnPassantX();
|
|
this.enPassantY = legalMoves.getEnPassantY();
|
|
for (int i = 0; i < moves.size(); i++) {
|
|
if (x == moves.get(i)[0] && y == moves.get(i)[1]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void undoLastMove() {
|
|
if (this.turns > 0) {
|
|
states.remove(this.turns);
|
|
this.turns = turns - 1;
|
|
//this.board = new Piece[lineNum][colNum];
|
|
this.x = -1;
|
|
this.y = -1;
|
|
|
|
String[] undo = states.get(turns).split("\n");
|
|
Board newBoard = new Board(undo);
|
|
this.board = newBoard.board;
|
|
|
|
if (undo[lineNum] == "B" || turns == 0) {
|
|
whiteTurn = true;
|
|
}
|
|
else {
|
|
whiteTurn = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public Board(Board board) {
|
|
Piece[][] newBoard = new Piece[lineNum][colNum];
|
|
for (int i = 0; i < colNum; i++) {
|
|
for (int j = 0; j < lineNum; j++) {
|
|
Piece piece = board.getPieceAt(i,j);
|
|
if (piece != null) {
|
|
newBoard[j][i] = new Piece(piece);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void playMove(Move move) {
|
|
board[move.getFromY()][move.getFromX()].setX(move.getToX());
|
|
board[move.getFromY()][move.getFromX()].setY(move.getToY());
|
|
board[move.getToY()][move.getToX()] = board[move.getFromY()][move.getFromX()];
|
|
board[move.getFromY()][move.getFromX()] = null;
|
|
|
|
for (int x = 0; x < colNum; x++) {
|
|
for (int y = 0; y < lineNum; y++) {
|
|
canPromote(x, y);
|
|
}
|
|
}
|
|
this.states.add(toString());
|
|
}
|
|
|
|
ArrayList<Piece> promoPieces= new ArrayList<>();
|
|
boolean promotion;
|
|
|
|
private boolean canPromote(int x, int y) {
|
|
if (board[y][x] != null && board[y][x].getType() == PieceType.Pawn) {
|
|
boolean isWhite = board[y][x].isWhite(); // ✅ Declare 'isWhite' here
|
|
if ((isWhite && y == 0) || (!isWhite && y == 7)) {
|
|
board[y][x] = new Piece(isWhite, PieceType.Queen, x, y); // ✅ Now valid
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|