diff --git a/OOP_2B6_PROJECT/src/backend/AutoPlayer.java b/OOP_2B6_PROJECT/src/backend/AutoPlayer.java index d7f3197..63e3e83 100644 --- a/OOP_2B6_PROJECT/src/backend/AutoPlayer.java +++ b/OOP_2B6_PROJECT/src/backend/AutoPlayer.java @@ -15,48 +15,160 @@ public class AutoPlayer { int px = p.getX(); int py = p.getY(); - for (int dx = -1; dx <= 1; dx++) { - for (int dy = -1; dy <= 1; dy++) { - if (dx == 0 && dy == 0) continue; - int nx = px + dx; - int ny = py + dy; + ArrayList candidateMoves = generatePossibleMoves(p, board); + for (int[] move : candidateMoves) { + int nx = move[0]; + int ny = move[1]; + Piece target = board.getPieceAt(nx, ny); - if (nx >= 0 && ny >= 0 && nx < board.getWidth() && ny < board.getHeight()) { - Piece target = getPieceAt(pieces, nx, ny); - if (target == null || target.isWhite() != aiColor) { - int score = (target != null) ? pieceValue(target) : 0; - if (score > bestScore) { - bestScore = score; - bestMove = new Move(p, px, py, nx, ny, target); - } - } - } + Board simulated = new Board(board); + simulated.playMove(new Move(p, px, py, nx, ny, target)); + + int score = evaluateBoard(simulated, aiColor); + if (score > bestScore) { + bestScore = score; + bestMove = new Move(p, px, py, nx, ny, target); } } } } - return bestMove; } + private ArrayList generatePossibleMoves(Piece piece, Board board) { + ArrayList moves = new ArrayList<>(); + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + + switch (piece.getType()) { + case Pawn: + int dir = isWhite ? -1 : 1; + int oneStepY = y + dir; + int twoStepY = y + 2 * dir; + if (inBounds(x, oneStepY, board) && board.getPieceAt(x, oneStepY) == null) { + moves.add(new int[] { x, oneStepY }); + if ((isWhite && y == 6) || (!isWhite && y == 1)) { + if (board.getPieceAt(x, twoStepY) == null) { + moves.add(new int[] { x, twoStepY }); + } + } + } + for (int dx = -1; dx <= 1; dx += 2) { + int nx = x + dx; + if (inBounds(nx, oneStepY, board)) { + Piece target = board.getPieceAt(nx, oneStepY); + if (target != null && target.isWhite() != isWhite) { + moves.add(new int[] { nx, oneStepY }); + } + } + } + break; + + case Knight: + int[][] knightMoves = { { 2, 1 }, { 1, 2 }, { -1, 2 }, { -2, 1 }, + { -2, -1 }, { -1, -2 }, { 1, -2 }, { 2, -1 } }; + for (int[] d : knightMoves) { + int nx = x + d[0]; + int ny = y + d[1]; + if (inBounds(nx, ny, board)) { + Piece target = board.getPieceAt(nx, ny); + if (target == null || target.isWhite() != isWhite) + moves.add(new int[] { nx, ny }); + } + } + break; + + case Bishop: + addSlideMoves(moves, board, piece, 1, 1); + addSlideMoves(moves, board, piece, 1, -1); + addSlideMoves(moves, board, piece, -1, 1); + addSlideMoves(moves, board, piece, -1, -1); + break; + + case Rook: + addSlideMoves(moves, board, piece, 1, 0); + addSlideMoves(moves, board, piece, -1, 0); + addSlideMoves(moves, board, piece, 0, 1); + addSlideMoves(moves, board, piece, 0, -1); + break; + + case Queen: + for (int dx = -1; dx <= 1; dx++) { + for (int dy = -1; dy <= 1; dy++) { + if (dx != 0 || dy != 0) { + addSlideMoves(moves, board, piece, dx, dy); + } + } + } + break; + + case King: + for (int dx = -1; dx <= 1; dx++) { + for (int dy = -1; dy <= 1; dy++) { + if (dx == 0 && dy == 0) continue; + int nx = x + dx; + int ny = y + dy; + if (inBounds(nx, ny, board)) { + Piece target = board.getPieceAt(nx, ny); + if (target == null || target.isWhite() != isWhite) { + moves.add(new int[] { nx, ny }); + } + } + } + } + break; + } + return moves; + } + + private void addSlideMoves(ArrayList moves, Board board, Piece piece, int dx, int dy) { + int x = piece.getX(); + int y = piece.getY(); + boolean isWhite = piece.isWhite(); + int nx = x + dx; + int ny = y + dy; + + while (inBounds(nx, ny, board)) { + Piece p = board.getPieceAt(nx, ny); + if (p == null) { + moves.add(new int[] { nx, ny }); + } else { + if (p.isWhite() != isWhite) + moves.add(new int[] { nx, ny }); + break; + } + nx += dx; + ny += dy; + } + } + + private boolean inBounds(int x, int y, Board board) { + return x >= 0 && y >= 0 && x < board.getWidth() && y < board.getHeight(); + } + + private int evaluateBoard(Board board, boolean aiColor) { + int score = 0; + for (Piece p : board.getPieces()) { + int value = pieceValue(p); + score += p.isWhite() == aiColor ? value : -value; + } + return score; + } + private int pieceValue(Piece piece) { switch (piece.getType()) { - case Pawn: return 1; + case Pawn: return 10; case Knight: - case Bishop: return 3; - case Rook: return 5; - case Queen: return 9; - case King: return 1000; + case Bishop: return 30; + case Rook: return 50; + case Queen: return 90; + case King: return 900; default: return 0; } } - - private Piece getPieceAt(ArrayList list, int x, int y) { - for (Piece p : list) { - if (p.getX() == x && p.getY() == y) return p; - } - return null; - } } + + diff --git a/OOP_2B6_PROJECT/src/backend/Board.java b/OOP_2B6_PROJECT/src/backend/Board.java index 31582ac..05dbfef 100644 --- a/OOP_2B6_PROJECT/src/backend/Board.java +++ b/OOP_2B6_PROJECT/src/backend/Board.java @@ -10,6 +10,7 @@ public class Board { private ArrayList pieces; private int turnNumber = 0; private boolean turnIsWhite = true; + private boolean gameOver = false; private Integer selectedX = null; private Integer selectedY = null; @@ -39,6 +40,10 @@ public class Board { return turnIsWhite; } + public boolean isGameOver() { + return gameOver; + } + public void setPiece(boolean isWhite, PieceType type, int x, int y) { pieces.removeIf(p -> p.getX() == x && p.getY() == y); pieces.add(new Piece(isWhite, type, x, y)); @@ -73,6 +78,7 @@ public class Board { selectedY = null; highlightedPositions.clear(); moveHistory.clear(); + gameOver = false; } public ArrayList getPieces() { @@ -80,6 +86,8 @@ public class Board { } public void userTouch(int x, int y) { + if (gameOver) return; + Piece clickedPiece = getPieceAt(x, y); if (selectedX == null || selectedY == null) { if (clickedPiece != null && clickedPiece.isWhite() == turnIsWhite) { @@ -104,6 +112,10 @@ public class Board { moveHistory.push(move); turnNumber++; turnIsWhite = !turnIsWhite; + + if (isCheckmate(!turnIsWhite)) { + gameOver = true; + } } selectedX = null; selectedY = null; @@ -129,9 +141,52 @@ public class Board { selectedX = null; selectedY = null; highlightedPositions.clear(); + gameOver = false; } } + public boolean isCheckmate(boolean forWhite) { + for (Piece piece : pieces) { + if (piece.isWhite() == forWhite) { + ArrayList moves = getLegalMovesFor(piece); + for (int[] move : moves) { + Board copy = new Board(this); + Piece captured = copy.getPieceAt(move[0], move[1]); + copy.pieces.removeIf(p -> p.getX() == piece.getX() && p.getY() == piece.getY()); + copy.pieces.removeIf(p -> p.getX() == move[0] && p.getY() == move[1]); + copy.pieces.add(new Piece(piece.isWhite(), piece.getType(), move[0], move[1])); + if (!copy.isKingInCheck(forWhite)) { + return false; + } + } + } + } + return isKingInCheck(forWhite); + } + + public boolean isKingInCheck(boolean isWhite) { + Piece king = null; + for (Piece p : pieces) { + if (p.getType() == PieceType.King && p.isWhite() == isWhite) { + king = p; + break; + } + } + if (king == null) return true; + + for (Piece enemy : pieces) { + if (enemy.isWhite() != isWhite) { + ArrayList moves = getLegalMovesFor(enemy); + for (int[] pos : moves) { + if (pos[0] == king.getX() && pos[1] == king.getY()) { + return true; + } + } + } + } + return false; + } + public boolean isSelected(int x, int y) { return selectedX != null && selectedY != null && selectedX == x && selectedY == y; } @@ -265,7 +320,7 @@ public class Board { return x >= 0 && y >= 0 && x < width && y < height; } - private Piece getPieceAt(int x, int y) { + public Piece getPieceAt(int x, int y) { for (Piece p : pieces) { if (p.getX() == x && p.getY() == y) return p; } @@ -318,7 +373,7 @@ public class Board { } public void playMove(Move move) { - if (move == null) return; + if (move == null || gameOver) return; pieces.removeIf(p -> p.getX() == move.getToX() && p.getY() == move.getToY()); pieces.removeIf(p -> p.getX() == move.getFromX() && p.getY() == move.getFromY()); pieces.add(new Piece( @@ -333,6 +388,10 @@ public class Board { selectedX = null; selectedY = null; highlightedPositions.clear(); + + if (isCheckmate(!turnIsWhite)) { + gameOver = true; + } } }