Actualiser src/backend/AutoPlayer.java

This commit is contained in:
Guillaume VALLENET 2025-04-25 16:02:04 +02:00
parent 9f5b27769f
commit edcf16e6e3
1 changed files with 152 additions and 124 deletions

View File

@ -4,162 +4,190 @@ import java.util.ArrayList;
import java.util.Random; import java.util.Random;
public class AutoPlayer { public class AutoPlayer {
private static final int MAX_DEPTH = 2; // Reduced depth for faster computation private static final int MAX_DEPTH = 3;
private static final Random random = new Random(); private Random random = new Random();
/** /**
* Computes a move for the current player with a deliberate delay * Computes the best move for the current player
* * @param board Current board state
* @param board Current state of the board * @return The best move found
* @return A reasonable move
*/ */
public Move computeBestMove(Board board) { public Move computeBestMove(Board board) {
if (board == null) { ArrayList<Move> validMoves = generateAllValidMoves(board);
if (validMoves.isEmpty()) {
return null; 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<Move> 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; 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); Board boardCopy = new Board(board);
boardCopy.playMove(move); 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; bestScore = score;
bestMove = move; 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) { private ArrayList<Move> generateAllValidMoves(Board board) {
if (depth == 0) { ArrayList<Move> moves = new ArrayList<>();
return evaluateBoard(board);
}
ArrayList<Move> 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<Move> generatePossibleMoves(Board board) {
ArrayList<Move> possibleMoves = new ArrayList<>();
boolean isWhiteTurn = board.isTurnWhite(); boolean isWhiteTurn = board.isTurnWhite();
// Get all pieces of the current player
for (Piece piece : board.getPieces()) { for (Piece piece : board.getPieces()) {
if (piece.isWhite() == isWhiteTurn) { if (piece.isWhite() == isWhiteTurn) {
possibleMoves.addAll(generateMovesForPiece(board, piece)); // For each piece, simulate selecting it and get valid moves
} Board tempBoard = new Board(board);
} tempBoard.userTouch(piece.getX(), piece.getY());
return possibleMoves; // 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)) {
* Generates all possible legal moves for a specific piece // Create a move for this valid destination
*/ Piece capturedPiece = null;
private ArrayList<Move> generateMovesForPiece(Board board, Piece piece) { for (Piece p : board.getPieces()) {
ArrayList<Move> moves = new ArrayList<>(); if (p.getX() == x && p.getY() == y) {
int x = piece.getX(); capturedPiece = p;
int y = piece.getY(); break;
}
Board tempBoard = new Board(board); }
tempBoard.userTouch(x, y); moves.add(new Move(piece.getX(), piece.getY(), x, y, piece, capturedPiece));
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;
} }
} }
moves.add(new Move(x, y, toX, toY, piece, capturedPiece));
} }
} }
} }
return moves; 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<Move> 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;
}
}
} }