OOP_1B3_Project/src/backend/Board.java

393 lines
10 KiB
Java

package backend;
import java.util.ArrayList;
public class Board {
private int width;
private int height;
private ArrayList<Piece> pieces;
private int turnNumber;
private boolean turnWhite;
private Integer selectedX = null;
private Integer selectedY = null;
private ArrayList<int[]> highlightedSquares = new ArrayList<>();
private ArrayList<Move> moveHistory = new ArrayList<>();
/*public Board(int colNum, int lineNum) {
this.width = colNum;
this.height = lineNum;
this.pieces = new ArrayList<>();
}
*/
public Board(int colNum, int lineNum) {
this.width = colNum;
this.height = lineNum;
this.pieces = new ArrayList<>();
this.turnNumber = 0;
this.turnWhite = true; // White starts first in chess
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;// the above part set the checked board
}
public int getTurnNumber() {
return this.turnNumber;
}
public boolean isTurnWhite() {
return this.turnWhite;
}
public void setPiece(boolean isWhite, PieceType type, int x, int y) {
pieces.add(new Piece(isWhite, type, x, y));
}
public void populateBoard() {
cleanBoard(); // make sure it's empty first
// Place white pawns
for (int x = 0; x < 8; x++) {
setPiece(true, PieceType.Pawn, x, 1);
}
// Place black pawns
for (int x = 0; x < 8; x++) {
setPiece(false, PieceType.Pawn, x, 6);
}
// Back rows (R, N, B, Q, K, B, N, R)
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() {
//TODO
pieces.clear();
}
@Override
public String toString() {
String[][] grid = new String[height][width];
// Fill the grid with empty squares
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
grid[y][x] = "--";
}
}
// Place pieces on the grid
for (Piece piece : pieces) {
String color = piece.isWhite() ? "W" : "B";
String type = piece.getType().toString().substring(0, 1); // e.g., "P" for Pawn
grid[piece.getY()][piece.getX()] = color + type;
}
// Build the string row by row
StringBuilder sb = new StringBuilder();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
sb.append(grid[y][x]).append(" ");
}
sb.append("\n");
}
return sb.toString();
}
public ArrayList<Piece> getPieces() {
return pieces; // this refers to the instance variable
}
public void userTouch(int x, int y) {
Piece clickedPiece = getPieceAt(x, y);
// No selection yet
if (selectedX == null || selectedY == null) {
if (clickedPiece != null && clickedPiece.isWhite() == turnWhite) {
selectedX = x;
selectedY = y;
highlightedSquares = computeLegalMoves(clickedPiece);
}
return;
}
// Clicked the same square again → unselect
if (selectedX == x && selectedY == y) {
selectedX = null;
selectedY = null;
highlightedSquares.clear();
return;
}
// Otherwise, try to move
Piece selectedPiece = getPieceAt(selectedX, selectedY);
if (selectedPiece == null) {
// Somehow no piece at selected position (safety check)
selectedX = null;
selectedY = null;
highlightedSquares.clear();
return;
}
// Check if clicked destination is valid
boolean validMove = false;
for (int[] pos : highlightedSquares) {
if (pos[0] == x && pos[1] == y) {
validMove = true;
break;
}
}
if (!validMove) {
// Invalid destination → reset
selectedX = null;
selectedY = null;
highlightedSquares.clear();
return;
}
// Move is valid → capture if needed
Piece target = getPieceAt(x, y);
// Log the move for undo
Move move = new Move(
selectedPiece.getType(),
selectedPiece.isWhite(),
selectedX, selectedY,
x, y,
target // may be null
);
moveHistory.add(move);
// Remove captured piece if any
if (target != null) {
pieces.remove(target);
}
// Remove the original piece
pieces.remove(selectedPiece);
// Add new piece at destination
setPiece(selectedPiece.isWhite(), selectedPiece.getType(), x, y);
// Update turn
turnNumber++;
turnWhite = !turnWhite;
// Clear selection and highlights
selectedX = null;
selectedY = null;
highlightedSquares.clear();
}
public boolean isSelected(int x, int y) {
return selectedX != null && selectedY != null && selectedX == x && selectedY == y;
}
/* saving-loading feature :*/
public String[] toFileRep() {
String[] fileRep = new String[height + 1]; // 8 rows + 1 for turn
String[][] grid = new String[height][width];
// Fill with empty squares
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
grid[y][x] = "--";
}
}
// Fill with pieces
for (Piece piece : pieces) {
String color = piece.isWhite() ? "W" : "B";
String type = piece.getType().toString().substring(0, 1); // P, R, N, B, Q, K
grid[piece.getY()][piece.getX()] = color + type;
}
// Convert grid to CSV-like strings
for (int y = 0; y < height; y++) {
StringBuilder row = new StringBuilder();
for (int x = 0; x < width; x++) {
row.append(grid[y][x]);
if (x < width - 1) {
row.append(",");
}
}
fileRep[y] = row.toString();
}
// Last line = turn
fileRep[height] = turnWhite ? "W" : "B";
return fileRep;
}
public Board(String[] array) {
this.width = 8;
this.height = 8;
this.pieces = new ArrayList<>();
this.turnNumber = 0;
this.turnWhite = array[8].equals("W");
for (int y = 0; y < height; y++) {
String[] row = array[y].split(",");
for (int x = 0; x < width; x++) {
String code = row[x];
if (!code.equals("--")) {
boolean isWhite = code.charAt(0) == 'W';
char typeChar = code.charAt(1);
PieceType type = null;
switch (typeChar) {
case 'P':
type = PieceType.Pawn;
break;
case 'R':
type = PieceType.Rook;
break;
case 'N':
type = PieceType.Knight;
break;
case 'B':
type = PieceType.Bishop;
break;
case 'Q':
type = PieceType.Queen;
break;
case 'K':
type = PieceType.King;
break;
}
if (type != null) {
setPiece(isWhite, type, x, y);
}
}
}
}
}
/* 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 void undoLastMove() {
if (moveHistory.isEmpty()) return;
Move lastMove = moveHistory.remove(moveHistory.size() - 1);
// Remove piece from destination
Piece movedPiece = getPieceAt(lastMove.getToX(), lastMove.getToY());
if (movedPiece != null) {
pieces.remove(movedPiece);
}
// Restore moved piece to original location
setPiece(lastMove.isWhite(), lastMove.getType(), lastMove.getFromX(), lastMove.getFromY());
// Restore captured piece if there was one
if (lastMove.getCapturedPiece() != null) {
Piece cap = lastMove.getCapturedPiece();
setPiece(cap.isWhite(), cap.getType(), cap.getX(), cap.getY());
}
turnNumber--;
turnWhite = !turnWhite;
}
public Board(Board board) {
//TODO
}
public void playMove(Move move) {
//TODO
}
private Piece getPieceAt(int x, int y) {
for (Piece p : pieces) {
if (p.getX() == x && p.getY() == y) {
return p;
}
}
return null;
}
private boolean isEmpty(int x, int y) {
return getPieceAt(x, y) == null;
}
private boolean isEnemy(int x, int y, boolean isWhite) {
Piece p = getPieceAt(x, y);
return p != null && p.isWhite() != isWhite;
}
private ArrayList<int[]> computeLegalMoves(Piece piece) {
ArrayList<int[]> moves = new ArrayList<>();
int x = piece.getX();
int y = piece.getY();
PieceType type = piece.getType();
if (type == PieceType.Pawn) {
int dir = piece.isWhite() ? 1 : -1;
int nextY = y + dir;
// Move forward if square is empty
if (isEmpty(x, nextY)) {
moves.add(new int[]{x, nextY});
}
// Diagonal capture
if (isEnemy(x - 1, nextY, piece.isWhite())) {
moves.add(new int[]{x - 1, nextY});
}
if (isEnemy(x + 1, nextY, piece.isWhite())) {
moves.add(new int[]{x + 1, nextY});
}
}
return moves;
}
}