From edcf16e6e35711b85f8d62f18bf9af171392d223 Mon Sep 17 00:00:00 2001 From: Guillaume VALLENET Date: Fri, 25 Apr 2025 16:02:04 +0200 Subject: [PATCH] Actualiser src/backend/AutoPlayer.java --- src/backend/AutoPlayer.java | 276 ++++++++++++++++++++---------------- 1 file changed, 152 insertions(+), 124 deletions(-) diff --git a/src/backend/AutoPlayer.java b/src/backend/AutoPlayer.java index 9b753af..5b61f34 100644 --- a/src/backend/AutoPlayer.java +++ b/src/backend/AutoPlayer.java @@ -4,162 +4,190 @@ import java.util.ArrayList; import java.util.Random; public class AutoPlayer { - private static final int MAX_DEPTH = 2; // Reduced depth for faster computation - private static final Random random = new Random(); + private static final int MAX_DEPTH = 3; + private Random random = new Random(); /** - * Computes a move for the current player with a deliberate delay - * - * @param board Current state of the board - * @return A reasonable move + * Computes the best move for the current player + * @param board Current board state + * @return The best move found */ public Move computeBestMove(Board board) { - if (board == null) { + ArrayList validMoves = generateAllValidMoves(board); + if (validMoves.isEmpty()) { return null; } - // Add deliberate delay to simulate "thinking" - try { - Thread.sleep(500); // 0.5 second delay - } catch (InterruptedException e) { - // Ignore interruption - } - - boolean isWhiteTurn = board.isTurnWhite(); - ArrayList possibleMoves = generatePossibleMoves(board); - - if (possibleMoves.isEmpty()) { - return null; - } - - // 20% chance to make a random move for unpredictability - if (random.nextDouble() < 0.2) { - return possibleMoves.get(random.nextInt(possibleMoves.size())); - } - Move bestMove = null; - int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE; + int bestScore = Integer.MIN_VALUE; + boolean isMaximizing = board.isTurnWhite(); - for (Move move : possibleMoves) { + // Evaluate each move using minimax algorithm + for (Move move : validMoves) { + // Create a copy of the board and apply the move Board boardCopy = new Board(board); boardCopy.playMove(move); - int score = minimax(boardCopy, MAX_DEPTH - 1, !isWhiteTurn); + // Evaluate the resulting position + int score = minimax(boardCopy, MAX_DEPTH - 1, Integer.MIN_VALUE, Integer.MAX_VALUE, !isMaximizing); - if ((isWhiteTurn && score > bestScore) || (!isWhiteTurn && score < bestScore)) { + // Update best move if this is better + if (score > bestScore || (score == bestScore && random.nextBoolean())) { bestScore = score; bestMove = move; } } - return bestMove != null ? bestMove : possibleMoves.get(random.nextInt(possibleMoves.size())); + return bestMove; } /** - * Simplified minimax algorithm without alpha-beta pruning + * Generates all valid moves for the current player + * @param board Current board state + * @return List of all valid moves */ - private int minimax(Board board, int depth, boolean isWhiteTurn) { - if (depth == 0) { - return evaluateBoard(board); - } - - ArrayList possibleMoves = generatePossibleMoves(board); - - if (possibleMoves.isEmpty()) { - return evaluateBoard(board); - } - - int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE; - - for (Move move : possibleMoves) { - Board boardCopy = new Board(board); - boardCopy.playMove(move); - - int score = minimax(boardCopy, depth - 1, !isWhiteTurn); - - if (isWhiteTurn) { - bestScore = Math.max(bestScore, score); - } else { - bestScore = Math.min(bestScore, score); - } - } - - return bestScore; - } - - /** - * Simplified board evaluation - */ - private int evaluateBoard(Board board) { - int score = 0; - - for (Piece piece : board.getPieces()) { - int pieceValue = getPieceValue(piece.getType()); - score += piece.isWhite() ? pieceValue : -pieceValue; - } - - return score; - } - - /** - * Basic piece values - */ - private int getPieceValue(PieceType type) { - switch (type) { - case Pawn: return 100; - case Knight: return 300; - case Bishop: return 300; - case Rook: return 500; - case Queen: return 900; - case King: return 10000; - default: return 0; - } - } - - /** - * Generates all possible legal moves for the current player - */ - private ArrayList generatePossibleMoves(Board board) { - ArrayList possibleMoves = new ArrayList<>(); + private ArrayList generateAllValidMoves(Board board) { + ArrayList moves = new ArrayList<>(); boolean isWhiteTurn = board.isTurnWhite(); + // Get all pieces of the current player for (Piece piece : board.getPieces()) { if (piece.isWhite() == isWhiteTurn) { - possibleMoves.addAll(generateMovesForPiece(board, piece)); - } - } - - return possibleMoves; - } - - /** - * Generates all possible legal moves for a specific piece - */ - private ArrayList generateMovesForPiece(Board board, Piece piece) { - ArrayList moves = new ArrayList<>(); - int x = piece.getX(); - int y = piece.getY(); - - Board tempBoard = new Board(board); - tempBoard.userTouch(x, y); - - for (int toX = 0; toX < board.getWidth(); toX++) { - for (int toY = 0; toY < board.getHeight(); toY++) { - if (tempBoard.isHighlighted(toX, toY)) { - Piece capturedPiece = null; - - for (Piece boardPiece : board.getPieces()) { - if (boardPiece.getX() == toX && boardPiece.getY() == toY) { - capturedPiece = boardPiece; - break; + // For each piece, simulate selecting it and get valid moves + Board tempBoard = new Board(board); + tempBoard.userTouch(piece.getX(), piece.getY()); + + // For each valid highlighted position, create a move + for (int x = 0; x < board.getWidth(); x++) { + for (int y = 0; y < board.getHeight(); y++) { + if (tempBoard.isHighlighted(x, y)) { + // Create a move for this valid destination + Piece capturedPiece = null; + for (Piece p : board.getPieces()) { + if (p.getX() == x && p.getY() == y) { + capturedPiece = p; + break; + } + } + moves.add(new Move(piece.getX(), piece.getY(), x, y, piece, capturedPiece)); } } - - moves.add(new Move(x, y, toX, toY, piece, capturedPiece)); } } } return moves; } + + /** + * Minimax algorithm with alpha-beta pruning + * @param board Current board state + * @param depth Current search depth + * @param alpha Alpha value for pruning + * @param beta Beta value for pruning + * @param isMaximizing Whether we're maximizing or minimizing + * @return Best score for the position + */ + private int minimax(Board board, int depth, int alpha, int beta, boolean isMaximizing) { + // Base case: reached max depth or game over + if (depth == 0) { + return evaluateBoard(board); + } + + ArrayList validMoves = generateAllValidMoves(board); + if (validMoves.isEmpty()) { + return evaluateBoard(board); + } + + if (isMaximizing) { + int maxScore = Integer.MIN_VALUE; + for (Move move : validMoves) { + Board boardCopy = new Board(board); + boardCopy.playMove(move); + int score = minimax(boardCopy, depth - 1, alpha, beta, false); + maxScore = Math.max(maxScore, score); + alpha = Math.max(alpha, score); + if (beta <= alpha) { + break; // Beta cutoff + } + } + return maxScore; + } else { + int minScore = Integer.MAX_VALUE; + for (Move move : validMoves) { + Board boardCopy = new Board(board); + boardCopy.playMove(move); + int score = minimax(boardCopy, depth - 1, alpha, beta, true); + minScore = Math.min(minScore, score); + beta = Math.min(beta, score); + if (beta <= alpha) { + break; // Alpha cutoff + } + } + return minScore; + } + } + + /** + * Evaluates a board position + * @param board Board to evaluate + * @return Score for the position (positive favors white, negative favors black) + */ + private int evaluateBoard(Board board) { + int score = 0; + + for (Piece piece : board.getPieces()) { + int pieceValue = getPieceValue(piece.getType()); + int positionBonus = getPositionBonus(piece); + + // Add piece value (positive for white, negative for black) + score += piece.isWhite() ? pieceValue + positionBonus : -(pieceValue + positionBonus); + } + + return score; + } + + /** + * Returns the material value of a piece type + * @param type Piece type + * @return Value of the piece + */ + private int getPieceValue(PieceType type) { + switch (type) { + case Pawn: return 100; + case Knight: return 320; + case Bishop: return 330; + case Rook: return 500; + case Queen: return 900; + case King: return 20000; + default: return 0; + } + } + + /** + * Gets a bonus for piece position (higher for center control, etc.) + * @param piece The piece to evaluate + * @return Position bonus value + */ + private int getPositionBonus(Piece piece) { + // Simple position evaluation: + // - Pawns: advance toward promotion + // - Other pieces: control center squares + int x = piece.getX(); + int y = piece.getY(); + + int centerDistance = Math.abs(x - 3) + Math.abs(y - 3); + + if (piece.getType() == PieceType.Pawn) { + // Bonus for advancing pawns + return piece.isWhite() ? (7 - y) * 10 : y * 10; + } else { + // Bonus for controlling center (higher for knights and bishops) + int centerBonus = (8 - centerDistance) * 5; + if (piece.getType() == PieceType.Knight || piece.getType() == PieceType.Bishop) { + centerBonus *= 2; + } + return centerBonus; + } + } }