Actualiser src/backend/AutoPlayer.java
This commit is contained in:
parent
9f5b27769f
commit
edcf16e6e3
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue