From b09b46607ade798e28b6edda44ba169fc6c7f37c Mon Sep 17 00:00:00 2001 From: PIRANUT_PHLANG Date: Tue, 13 May 2025 14:48:53 +0200 Subject: [PATCH] implement SEF and Negamax --- src/backend/AutoPlayer.java | 61 +++++++++++++++++++++++++++++++++++++ src/backend/Board.java | 16 ++++++++++ src/backend/Game.java | 7 +++-- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/backend/AutoPlayer.java b/src/backend/AutoPlayer.java index 960d406..5510750 100644 --- a/src/backend/AutoPlayer.java +++ b/src/backend/AutoPlayer.java @@ -36,6 +36,67 @@ public class AutoPlayer { return possibleMoves.get(rand.nextInt(possibleMoves.size())); } + // Negamax search + public int negamax(Board board, int depth, int color) { + if (depth == 0) { + return color * board.evaluateBoard(); + } + + int bestScore = Integer.MIN_VALUE; + + for (Move move : getAllPossibleMoves(board)) { + board.playMove(move); + int score = -negamax(board, depth - 1, -color); + board.undoLastMove(); + + if (score > bestScore) { + bestScore = score; + } + } + + return bestScore; + } + + // Get best move using negamax + public Move getBestMoveUsingNegamax(Board board, int depth) { + int bestScore = Integer.MIN_VALUE; + Move bestMove = null; + int color = board.isTurnWhite() ? 1 : -1; + + for (Move move : getAllPossibleMoves(board)) { + board.playMove(move); + int score = -negamax(board, depth - 1, -color); + board.undoLastMove(); + + if (score > bestScore) { + bestScore = score; + bestMove = move; + } + } + + return bestMove; + } + + // Helper to get all legal moves for current player + private ArrayList getAllPossibleMoves(Board board) { + ArrayList possibleMoves = new ArrayList<>(); + boolean isWhiteTurn = board.isTurnWhite(); + + for (Piece piece : board.getPieces()) { + if (piece.isWhite() == isWhiteTurn) { + ArrayList legalPositions = board.getLegalMoves(piece); + for (int[] pos : legalPositions) { + Piece target = board.getPieceAt(pos[0], pos[1]); + Move move = new Move(piece, piece.getX(), piece.getY(), pos[0], pos[1], target); + possibleMoves.add(move); + } + } + } + + return possibleMoves; + } + + } diff --git a/src/backend/Board.java b/src/backend/Board.java index fc7469a..474b9bd 100644 --- a/src/backend/Board.java +++ b/src/backend/Board.java @@ -353,5 +353,21 @@ public void undoLastMove() { selected = null; highlighted.clear(); } + public int evaluateBoard() { + int score = 0; + for (Piece piece : pieces) { + int value = 0; + switch (piece.getType()) { + case Pawn: value = 100; break; + case Knight: value = 320; break; + case Bishop: value = 330; break; + case Rook: value = 500; break; + case Queen: value = 900; break; + } + if (piece.isWhite()) score += value; + else score -= value; + } + return score; + } } \ No newline at end of file diff --git a/src/backend/Game.java b/src/backend/Game.java index 4c64f70..3834699 100644 --- a/src/backend/Game.java +++ b/src/backend/Game.java @@ -48,8 +48,11 @@ public class Game extends Thread { } private void aiPlayerTurn() { - if(isAITurn()) { - board.playMove(aiPlayer.computeBestMove(new Board(board))); + if (isAITurn()) { + Move bestMove = aiPlayer.getBestMoveUsingNegamax(board, 2); // Change depth as needed + if (bestMove != null) { + board.playMove(bestMove); + } } }