diff --git a/src/backend/AutoPlayer.java b/src/backend/AutoPlayer.java index a988a22..a8cd782 100644 --- a/src/backend/AutoPlayer.java +++ b/src/backend/AutoPlayer.java @@ -1,17 +1,90 @@ package backend; +import java.util.ArrayList; +import java.util.Random; + public class AutoPlayer { - - - /** - * returns the best Move to try on provided board for active player - * @param board - * @return - */ - public Move computeBestMove(Board board) { - - return null; - } - - -} + + private final Move moveHelper = new Move(); + private final Random random = new Random(); + + /** + * Returns a random legal move for the current player + * @param boardObj The board to find moves for + * @return a valid Move or null if no moves available + */ + public Move computeBestMove(Board boardObj) { + // Create a list of pieces that can move + ArrayList candidates = new ArrayList<>(); + + + ArrayList allPieces = boardObj.getPieces(); + int width = boardObj.getWidth(); + int height = boardObj.getHeight(); + boolean isWhiteTurn = boardObj.isTurnWhite(); + + + Piece[][] boardArray = new Piece[width][height]; + + // Find all pieces with legal moves + for (Piece piece : allPieces) { + // Only consider pieces of the current player's color + if (piece.isWhite() == isWhiteTurn) { + + clearBoard(boardArray); + for (Piece p : allPieces) { + boardArray[p.getX()][p.getY()] = p; + } + + + ArrayList moves = moveHelper.getValidMoves( + piece, boardArray, width, height, null, boardObj + ); + + + if (!moves.isEmpty()) { + candidates.add(piece); + } + } + } + + + if (candidates.isEmpty()) return null; + + // Select a random piece to move + Piece selected = candidates.get(random.nextInt(candidates.size())); + + + clearBoard(boardArray); + for (Piece p : allPieces) { + boardArray[p.getX()][p.getY()] = p; + } + + + ArrayList moves = moveHelper.getValidMoves( + selected, boardArray, width, height, null, boardObj + ); + + // Select a random destination for the piece + int[] target = moves.get(random.nextInt(moves.size())); + + + Move aiMove = new Move(); + aiMove.setFromX(selected.getX()); + aiMove.setFromY(selected.getY()); + aiMove.setToX(target[0]); + aiMove.setToY(target[1]); + return aiMove; + } + + /** + * Clears the given board array by setting all elements to null + */ + private void clearBoard(Piece[][] boardArray) { + for (int x = 0; x < boardArray.length; x++) { + for (int y = 0; y < boardArray[x].length; y++) { + boardArray[x][y] = null; + } + } + } +} \ No newline at end of file diff --git a/src/backend/Board.java b/src/backend/Board.java index db99f9c..0e83d23 100644 --- a/src/backend/Board.java +++ b/src/backend/Board.java @@ -15,7 +15,8 @@ public class Board { private ArrayList highlightedSquares = new ArrayList<>(); private int[] enPassantTarget = null; // [x,y] coordinates of en passant target square private Move moveHelper = new Move(); - + private final AutoPlayer ai = new AutoPlayer(); + public Board(int colNum, int lineNum) { this.width = colNum; this.height = lineNum; @@ -214,13 +215,21 @@ public class Board { // Clear selection & highlights hasSelectedPiece = false; highlightedSquares.clear(); + + if (!turnWhite) { + Move aiMove = ai.computeBestMove(this); + if (aiMove != null) { + playMove(aiMove); + } } // Invalid move: just unselect else { hasSelectedPiece = false; highlightedSquares.clear(); } + } } + } @@ -342,6 +351,52 @@ public class Board { } public void playMove(Move move) { - // TODO + Piece selectedPiece = board[move.getFromX()][move.getFromY()]; + if (selectedPiece == null) return; + + boolean isEnPassant = selectedPiece.getType() == PieceType.Pawn && + enPassantTarget != null && + move.getToX() == enPassantTarget[0] && + move.getToY() == enPassantTarget[1] && + board[move.getToX()][move.getToY()] == null; + + previousBoard = cloneBoard(board); + board[move.getToX()][move.getToY()] = selectedPiece; + board[move.getFromX()][move.getFromY()] = null; + selectedPiece.setX(move.getToX()); + selectedPiece.setY(move.getToY()); + selectedPiece.setMoved(true); + + if (isEnPassant) { + board[move.getToX()][move.getFromY()] = null; + } + + if (selectedPiece.getType() == PieceType.King && Math.abs(move.getToX() - move.getFromX()) == 2) { + if (move.getToX() > move.getFromX()) { + Piece rook = board[7][move.getToY()]; + board[5][move.getToY()] = rook; + board[7][move.getToY()] = null; + rook.setX(5); + rook.setMoved(true); + } else { + Piece rook = board[0][move.getToY()]; + board[3][move.getToY()] = rook; + board[0][move.getToY()] = null; + rook.setX(3); + rook.setMoved(true); + } + } + + enPassantTarget = null; + if (selectedPiece.getType() == PieceType.Pawn && + Math.abs(move.getToY() - move.getFromY()) == 2) { + enPassantTarget = new int[]{move.getToX(), (move.getFromY() + move.getToY()) / 2}; + } + + turnWhite = !turnWhite; + turnNumber++; + hasSelectedPiece = false; + highlightedSquares.clear(); } + } \ No newline at end of file diff --git a/src/backend/Move.java b/src/backend/Move.java index b927245..470dd14 100644 --- a/src/backend/Move.java +++ b/src/backend/Move.java @@ -143,4 +143,41 @@ public class Move { private boolean inBounds(int x, int y, int width, int height) { return x >= 0 && x < width && y >= 0 && y < height; } + private int fromX; + private int fromY; + private int toX; + private int toY; + + public int getFromX() { + return fromX; + } + + public void setFromX(int fromX) { + this.fromX = fromX; + } + + public int getFromY() { + return fromY; + } + + public void setFromY(int fromY) { + this.fromY = fromY; + } + + public int getToX() { + return toX; + } + + public void setToX(int toX) { + this.toX = toX; + } + + public int getToY() { + return toY; + } + + public void setToY(int toY) { + this.toY = toY; + } + }