IAAAAAAAAAAAA

This commit is contained in:
Romain MURPHY 2025-04-23 16:48:35 +02:00
parent 30dfb5a6cd
commit 84605fdf60
4 changed files with 290 additions and 34 deletions

View File

@ -1,19 +1,227 @@
package backend;
import java.util.ArrayList;
public class AutoPlayer {
/**
* returns the best Move to try on provided board for active player
* @param board
* @return
*/
public Move computeBestMove(Board board) {
return null;
}
}
private int MAX_DEPTH = 3;
private int[][] PAWN_TABLE = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 5, 5, 5, -5, -5, 5, 5, 5 },
{ 1, 1, 2, 3, 3, 2, 1, 1 },
{ 0, 0, 0, 2, 2, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 1, 1, 1 },
{ 2, 2, 2, -2, -2, 2, 2, 2 },
{ 5, 5, 5, 5, 5, 5, 5, 5 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
};
private int[][] KNIGHT_TABLE = {
{-50,-40,-30,-30,-30,-30,-40,-50},
{-40,-20, 0, 0, 0, 0,-20,-40},
{-30, 0, 10, 15, 15, 10, 0,-30},
{-30, 5, 15, 20, 20, 15, 5,-30},
{-30, 0, 15, 20, 20, 15, 0,-30},
{-30, 5, 10, 15, 15, 10, 5,-30},
{-40,-20, 0, 5, 5, 0,-20,-40},
{-50,-40,-30,-30,-30,-30,-40,-50}
};
private int[][] BISHOP_TABLE = {
{-20,-10,-10,-10,-10,-10,-10,-20},
{-10, 5, 0, 0, 0, 0, 5,-10},
{-10, 10, 10, 10, 10, 10, 10,-10},
{-10, 0, 10, 10, 10, 10, 0,-10},
{-10, 5, 5, 10, 10, 5, 5,-10},
{-10, 0, 5, 10, 10, 5, 0,-10},
{-10, 0, 0, 0, 0, 0, 0,-10},
{-20,-10,-10,-10,-10,-10,-10,-20}
};
private int[][] ROOK_TABLE = {
{ 0, 0, 0, 5, 5, 0, 0, 0 },
{ -5, 0, 0, 0, 0, 0, 0, -5 },
{ -5, 0, 0, 0, 0, 0, 0, -5 },
{ -5, 0, 0, 0, 0, 0, 0, -5 },
{ -5, 0, 0, 0, 0, 0, 0, -5 },
{ -5, 0, 0, 0, 0, 0, 0, -5 },
{ 5, 10, 10, 10, 10, 10, 10, 5 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }
};
private int[][] QUEEN_TABLE = {
{-20,-10,-10, -5, -5,-10,-10,-20},
{-10, 0, 0, 0, 0, 0, 0,-10},
{-10, 0, 5, 5, 5, 5, 0,-10},
{ -5, 0, 5, 5, 5, 5, 0, -5},
{ 0, 0, 5, 5, 5, 5, 0, -5},
{-10, 5, 5, 5, 5, 5, 0,-10},
{-10, 0, 5, 0, 0, 0, 0,-10},
{-20,-10,-10, -5, -5,-10,-10,-20}
};
private int[][] KING_TABLE = {
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-20,-30,-30,-40,-40,-30,-30,-20},
{-10,-20,-20,-20,-20,-20,-20,-10},
{ 20, 20, 0, 0, 0, 0, 20, 20},
{ 20, 30, 10, 0, 0, 10, 30, 20}
};
public Move computeBestMove(ArrayList<ArrayList<Piece>> board, boolean isWhiteTurn) {
Move bestMove = null;
int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE;
ArrayList<Move> allMoves = getAllLegalMoves(board, isWhiteTurn);
for (Move move : allMoves) {
ArrayList<ArrayList<Piece>> simulatedBoard = simulateMove(board, move);
int score = minimax(simulatedBoard, MAX_DEPTH - 1, !isWhiteTurn);
if (isWhiteTurn && score > bestScore) {
bestScore = score;
bestMove = move;
} else if (!isWhiteTurn && score < bestScore) {
bestScore = score;
bestMove = move;
}
}
return bestMove;
}
private int minimax(ArrayList<ArrayList<Piece>> board, int depth, boolean isWhiteTurn) {
if (depth == 0) {
return evaluateBoard(board);
}
ArrayList<Move> allMoves = getAllLegalMoves(board, isWhiteTurn);
if (allMoves.isEmpty()) return evaluateBoard(board); // checkmate or stalemate
int bestScore = isWhiteTurn ? Integer.MIN_VALUE : Integer.MAX_VALUE;
for (Move move : allMoves) {
ArrayList<ArrayList<Piece>> simulatedBoard = simulateMove(board, move);
int score = minimax(simulatedBoard, depth - 1, !isWhiteTurn);
if (isWhiteTurn) {
bestScore = Math.max(bestScore, score);
} else {
bestScore = Math.min(bestScore, score);
}
}
return bestScore;
}
private int evaluateBoard(ArrayList<ArrayList<Piece>> board) {
int score = 0;
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
Piece p = board.get(y).get(x);
if (p != null) {
int value = getPieceValue(p.getType());
int positionalBonus = getPositionalBonus(p, x, y);
if (p.isWhite()) {
score += value + positionalBonus;
} else {
score -= value + positionalBonus; // subtract opponent's bonus too
}
}
}
}
return score;
}
private int getPieceValue(PieceType type) {
switch (type) {
case Pawn:
return 10;
case Knight:
return 30;
case Bishop:
return 30;
case Rook:
return 50;
case Queen:
return 90;
case King:
return 900;
default:
return 0;
}
}
private ArrayList<ArrayList<Piece>> simulateMove(ArrayList<ArrayList<Piece>> board, Move move) {
ArrayList<ArrayList<Piece>> newBoard = deepCopyBoard(board);
Piece piece = newBoard.get(move.fromY).get(move.fromX);
newBoard.get(move.fromY).set(move.fromX, null);
piece.x = move.toX;
piece.y = move.toY;
newBoard.get(move.toY).set(move.toX, piece);
return newBoard;
}
private ArrayList<ArrayList<Piece>> deepCopyBoard(ArrayList<ArrayList<Piece>> original) {
ArrayList<ArrayList<Piece>> copy = new ArrayList<>();
for (ArrayList<Piece> row : original) {
ArrayList<Piece> newRow = new ArrayList<>();
for (Piece p : row) {
if (p != null) {
newRow.add(PieceCreation.createPiece(p.getX(), p.getY(), p.getType(), p.isWhite()));
} else {
newRow.add(null);
}
}
copy.add(newRow);
}
return copy;
}
private ArrayList<Move> getAllLegalMoves(ArrayList<ArrayList<Piece>> board, boolean isWhiteTurn) {
ArrayList<Move> legalMoves = new ArrayList<>();
for (ArrayList<Piece> row : board) {
for (Piece p : row) {
if (p != null && p.isWhite() == isWhiteTurn) {
ArrayList<ArrayList<Boolean>> moves = p.getPossibleMoves(board);
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if (moves.get(y).get(x)) {
legalMoves.add(new Move(p.getX(), p.getY(), x, y));
}
}
}
}
}
}
return legalMoves;
}
private int getPositionalBonus(Piece piece, int x, int y) {
if (!piece.isWhite()) {
y = 7 - y; // mirror for black
}
switch (piece.getType()) {
case Pawn:
return PAWN_TABLE[y][x];
case Knight:
return KNIGHT_TABLE[y][x];
case Bishop:
return BISHOP_TABLE[y][x];
case Rook:
return ROOK_TABLE[y][x];
case Queen:
return QUEEN_TABLE[y][x];
case King:
return KING_TABLE[y][x];
default:
return 0;
}
}
}

View File

@ -240,8 +240,46 @@ public class Board {
}
public void playMove(Move move) {
//TODO
int xm = move.getFromX();
int ym = move.getFromY();
int x = move.getToX();
int y = move.getToY();
boardHistory.add(new BoardHistory(board,turnNumber,turnColor));
Piece pieceToMove = this.board.get(ym).get(xm);
boolean isCastlingMove = pieceToMove.getType() == PieceType.King && Math.abs(x - xm) == 2;
//check for castling mode:
if (isCastlingMove) {
//kingside
if (x > xm) {
Piece rook = board.get(ym).get(7);
board.get(ym).set(5, rook);
board.get(ym).set(7, null);
if (rook != null) {
rook.x = 5;
rook.setMoved(true);
}
}
if (x < xm) {
Piece rook = board.get(ym).get(0);
board.get(ym).set(3, rook);
board.get(ym).set(0, null);
if (rook != null) {
rook.x = 3;
rook.setMoved(true);
}
}
}
this.setPiece(x,y,pieceToMove.getType(),pieceToMove.isWhite());
Piece movedPiece = this.getPiece(x, y);
if (movedPiece != null) {
movedPiece.setMoved(true);
}
board.get(ym).set(xm,null);
this.turnColor = !this.turnColor;
this.turnNumber +=1;
}
public void setBoard(ArrayList<ArrayList<Piece>> board) {

View File

@ -49,7 +49,7 @@ public class Game extends Thread {
private void aiPlayerTurn() {
if(isAITurn()) {
board.playMove(aiPlayer.computeBestMove(new Board(board)));
board.playMove(aiPlayer.computeBestMove(board.getBoard(),board.isTurnWhite()));
}
}

View File

@ -1,24 +1,34 @@
package backend;
import java.util.ArrayList;
public class Move {
private int x;
private int y;
public Move(int x, int y) {
this.x=x;
this.y=y;
public int fromX, fromY, toX, toY;
public Move(int fromX, int fromY, int toX, int toY) {
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
public int getFromX() {
return fromX;
}
public int getFromY() {
return fromY;
}
}
public int getToX() {
return toX;
}
public int getToY() {
return toY;
}
@Override
public String toString() {
return "(" + fromX + "," + fromY + ") → (" + toX + "," + toY + ")";
}
}