OOP_3B4_Project/src/backend/Board.java

359 lines
10 KiB
Java

package backend;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class Board {
private int colNum;
private int lineNum;
private Piece[][] board;
private EnPassant enPassant = new EnPassant();
private int turnNumber = 0;
private boolean isWhiteTurn = true;
private Piece selectedPiece = null;
private Set<String> highlightedPositions = new HashSet<>();
public Board(int colNum, int lineNum) {
this.colNum = colNum;
this.lineNum = lineNum;
this.board = new Piece[lineNum][colNum];
}
public int getWidth() {
return colNum;
}
public int getHeight() {
return lineNum;
}
public int getTurnNumber() { //for checking
return turnNumber;
}
public Piece[][] getBoardMatrix() {
return board;
}
public boolean isTurnWhite() {
return isWhiteTurn;
}
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
board[y][x] = new Piece(x, y, type, isWhite);
}
public void populateBoard() {
cleanBoard();
for (int x = 0; x < getWidth(); x++) {
setPiece(false, PieceType.Pawn, x, 1);
setPiece(true, PieceType.Pawn, x, 6);
}
setPiece(false, PieceType.Rook, 0, 0);
setPiece(false, PieceType.Rook, 7, 0);
setPiece(true, PieceType.Rook, 0, 7);
setPiece(true, PieceType.Rook, 7, 7);
setPiece(false, PieceType.Knight, 1, 0);
setPiece(false, PieceType.Knight, 6, 0);
setPiece(true, PieceType.Knight, 1, 7);
setPiece(true, PieceType.Knight, 6, 7);
setPiece(false, PieceType.Bishop, 2, 0);
setPiece(false, PieceType.Bishop, 5, 0);
setPiece(true, PieceType.Bishop, 2, 7);
setPiece(true, PieceType.Bishop, 5, 7);
setPiece(false, PieceType.Queen, 3, 0);
setPiece(true, PieceType.Queen, 3, 7);
setPiece(false, PieceType.King, 4, 0);
setPiece(true, PieceType.King, 4, 7);
}
public void cleanBoard() {
for (int y = 0; y < getHeight(); y++) { //each column
for (int x = 0; x < getWidth(); x++) { //each row
board[y][x] = null; //starts at 0,0
}
}
selectedPiece = null;
highlightedPositions.clear();
}
public ArrayList<Piece> getPieces() {
ArrayList<Piece> pieces = new ArrayList<>();
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
if (board[y][x] != null) {
pieces.add(board[y][x]);
}
}
}
return pieces;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) {
Piece piece = board[y][x];
if (piece == null) {
sb.append(". ");
} else {
String symbol = piece.getType().getSummary();
sb.append(piece.isWhite() ? symbol.toUpperCase() : symbol.toLowerCase()).append(" ");
}
}
sb.append("\n");
}
return sb.toString();
}
public void userTouch(int x, int y) {
if (selectedPiece == null) {
Piece p = board[y][x];
if (p != null && p.isWhite() == isWhiteTurn) {
selectedPiece = p;
highlightedPositions = getValidMoves(p);
}
} else {
if (highlightedPositions.contains(x + "," + y)) {
movePiece(selectedPiece.getX(), selectedPiece.getY(), x, y);
isWhiteTurn = !isWhiteTurn;
turnNumber++;
}
selectedPiece = null;
highlightedPositions.clear();
}
}
public boolean isSelected(int x, int y) {
return selectedPiece != null && selectedPiece.getX() == x && selectedPiece.getY() == y;
}
public boolean isHighlighted(int x, int y) {
return highlightedPositions.contains(x + "," + y);
}
void movePiece(int fromX, int fromY, int toX, int toY) { //from private to not
Piece moving = board[fromY][fromX];
// En passant capture
if (enPassant.isEnPassantCapture(moving, fromX, toX, toY, board)) {
int capturedY = moving.isWhite() ? toY + 1 : toY - 1;
board[capturedY][toX] = null; // Remove captured pawn
}
board[toY][toX] = new Piece(toX, toY, moving.getType(), moving.isWhite());
board[fromY][fromX] = null;
enPassant.updateTarget(moving, fromY, toY, toX);
}
public Set<String> getValidMoves(Piece piece, boolean skipKingCheck) {
Set<String> validMoves = new HashSet<>();
int x = piece.getX();
int y = piece.getY();
boolean isWhite = piece.isWhite();
PieceType type = piece.getType();
int direction = isWhite ? -1 : 1;
switch (type) {
case Pawn:
if (inBounds(x, y + direction) && board[y + direction][x] == null) {
validMoves.add(x + "," + (y + direction));
}
boolean onStartRow = (isWhite && y == 6) || (!isWhite && y == 1);
if (onStartRow && board[y + direction][x] == null && board[y + 2 * direction][x] == null) {
validMoves.add(x + "," + (y + 2 * direction));
}
int[] dx = {-1, 1};
for (int i : dx) {
int targetX = x + i;
int targetY = y + direction;
if (inBounds(targetX, targetY)) {
Piece target = board[targetY][targetX];
if (target != null && target.isWhite() != isWhite) {
validMoves.add(targetX + "," + targetY);
}
}
}
int[] epTarget = enPassant.getTarget();
if (epTarget != null && Math.abs(epTarget[0] - x) == 1 && epTarget[1] == y + direction) {
validMoves.add(epTarget[0] + "," + epTarget[1]);
}
break;
case Rook:
addLinearMoves(validMoves, x, y, isWhite, 1, 0);
addLinearMoves(validMoves, x, y, isWhite, -1, 0);
addLinearMoves(validMoves, x, y, isWhite, 0, 1);
addLinearMoves(validMoves, x, y, isWhite, 0, -1);
break;
case Bishop:
addLinearMoves(validMoves, x, y, isWhite, 1, 1);
addLinearMoves(validMoves, x, y, isWhite, 1, -1);
addLinearMoves(validMoves, x, y, isWhite, -1, 1);
addLinearMoves(validMoves, x, y, isWhite, -1, -1);
break;
case Queen:
int[][] queenDirections = {
{1, 0}, {-1, 0}, {0, 1}, {0, -1},
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}
};
for (int[] dir : queenDirections) {
addLinearMoves(validMoves, x, y, isWhite, dir[0], dir[1]);
}
break;
case Knight:
int[][] knightMoves = {
{1, 2}, {2, 1}, {-1, 2}, {-2, 1},
{1, -2}, {2, -1}, {-1, -2}, {-2, -1}
};
for (int[] move : knightMoves) {
int nx = x + move[0];
int ny = y + move[1];
if (inBounds(nx, ny)) {
Piece target = board[ny][nx];
if (target == null || target.isWhite() != isWhite) {
validMoves.add(nx + "," + ny);
}
}
}
break;
case King:
for (int dxKing = -1; dxKing <= 1; dxKing++) {
for (int dyKing = -1; dyKing <= 1; dyKing++) {
if (dxKing == 0 && dyKing == 0) continue;
int nx = x + dxKing;
int ny = y + dyKing;
if (inBounds(nx, ny)) {
Piece target = board[ny][nx];
if (target == null || target.isWhite() != isWhite) {
validMoves.add(nx + "," + ny);
}
}
}
}
break;
}
if (skipKingCheck) {
return validMoves;
} else {
return CheckKing.filterLegalMoves(this, piece, validMoves);
}
}
private void addLinearMoves(Set<String> valid, int x, int y, boolean isWhite, int dx, int dy) {
int nx = x + dx;
int ny = y + dy;
while (inBounds(nx, ny)) {
Piece target = board[ny][nx];
if (target == null) {
valid.add(nx + "," + ny);
} else {
if (target.isWhite() != isWhite) {
valid.add(nx + "," + ny);
}
break;
}
nx += dx;
ny += dy;
}
}
private Set<String> getValidMoves(Piece piece) {
return getValidMoves(piece, false);
}
private boolean inBounds(int x, int y) {
return x >= 0 && y >= 0 && x < colNum && y < lineNum;
}
// PART3
public String[] toFileRep() {
String[] result = new String[lineNum + 1];
for (int y = 0; y < lineNum; y++) {
StringBuilder sb = new StringBuilder();
for (int x = 0; x < colNum; x++) {
if (x > 0) sb.append(",");
Piece piece = board[y][x];
if (piece != null) {
sb.append(piece.isWhite() ? "W" : "B");
sb.append(piece.getType().getSummary()); // Ensure this returns K/Q/R/N/B/P
}
}
result[y] = sb.toString();
}
result[lineNum] = isWhiteTurn ? "W" : "B";
return result;
}
public Board(String[] array) {
this.colNum = 8;
this.lineNum = 8;
this.board = new Piece[lineNum][colNum];
for (int y = 0; y < lineNum; y++) {
String[] tokens = array[y].split(",", -1);
for (int x = 0; x < colNum; x++) {
String token = tokens[x].trim();
if (token.length() == 2) {
boolean isWhite = token.charAt(0) == 'W';
char typeChar = token.charAt(1);
PieceType type = PieceType.fromSummary(typeChar); // You must implement this method
board[y][x] = new Piece(x, y, type, isWhite);
}
}
}
this.isWhiteTurn = array[lineNum].equalsIgnoreCase("W");
}
public void undoLastMove() {
//TODO
}
public Board(Board other) {
this.colNum = other.colNum;
this.lineNum = other.lineNum;
this.board = new Piece[lineNum][colNum];
for (int y = 0; y < lineNum; y++) {
for (int x = 0; x < colNum; x++) {
Piece p = other.board[y][x];
if (p != null) {
this.board[y][x] = new Piece(p.getX(), p.getY(), p.getType(), p.isWhite());
}
}
}
this.isWhiteTurn = other.isWhiteTurn;
this.turnNumber = other.turnNumber;
this.enPassant = new EnPassant(); // you can improve this if EnPassant has a copy constructor
}
public void playMove(Move move) {
//TODO
}
}