Arbre
This commit is contained in:
@@ -6,6 +6,13 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
|
||||
private int MAXDEPTH = 5;
|
||||
|
||||
/**
|
||||
* En dessous (ou égal) à ce nombre de coups restants (cases vides),
|
||||
* on considère que l'arbre est "petit" et on fait un alpha-bêta simple :
|
||||
* pas de cut-off, on explore jusqu'aux positions terminales (isGameOver()).
|
||||
*/
|
||||
private int SMALL_TREE_MOVE_LIMIT = 6;
|
||||
|
||||
public MiniMaxBot(Player me) {
|
||||
super(me); // Correct constructor usage
|
||||
}
|
||||
@@ -20,12 +27,19 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
float bestScore = -Float.MAX_VALUE;
|
||||
HexPly bestMove = null;
|
||||
|
||||
// Détermine si l'arbre est petit ou grand
|
||||
int movesLeft = countLegalMoves(hb);
|
||||
boolean useCutoff = (movesLeft > SMALL_TREE_MOVE_LIMIT);
|
||||
int depthToUse = useCutoff ? MAXDEPTH : 0; // 0 car en "simple" on ne coupe pas sur depth
|
||||
|
||||
for (int i = 0; i < hb.getSize(); i++) {
|
||||
for (int j = 0; j < hb.getSize(); j++) {
|
||||
HexPly move = new HexPly(hb.getCurrentPlayer(), i, j);
|
||||
if (hb.isLegal(move)) {
|
||||
hb.doPly(move);
|
||||
float score = minimax(hb, MAXDEPTH, -Float.MAX_VALUE, Float.MAX_VALUE, true);
|
||||
|
||||
float score = minimax(hb, depthToUse, -Float.MAX_VALUE, Float.MAX_VALUE, true, useCutoff);
|
||||
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestMove = move;
|
||||
@@ -37,8 +51,19 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
return bestMove;
|
||||
}
|
||||
|
||||
private float minimax(HexBoard board, int depth, float alpha, float beta, boolean isMaximizing) {
|
||||
if (depth == 0 || board.isGameOver()) {
|
||||
/**
|
||||
* Minimax + alpha-bêta
|
||||
* - useCutoff = false : alpha-bêta "simple" -> on s'arrête uniquement sur isGameOver()
|
||||
* - useCutoff = true : alpha-bêta avec cut-off -> arrêt si depth == 0 (heuristique)
|
||||
*/
|
||||
private float minimax(HexBoard board, int depth, float alpha, float beta, boolean isMaximizing, boolean useCutoff) {
|
||||
// Toujours prioritaire : position terminale
|
||||
if (board.isGameOver()) {
|
||||
return terminalScore(board);
|
||||
}
|
||||
|
||||
// Cut-off uniquement si demandé
|
||||
if (useCutoff && depth == 0) {
|
||||
return evaluateBoard(board);
|
||||
}
|
||||
|
||||
@@ -49,10 +74,18 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
HexPly move = new HexPly(board.getCurrentPlayer(), i, j);
|
||||
if (board.isLegal(move)) {
|
||||
board.doPly(move);
|
||||
float score = minimax(board, depth - 1, alpha, beta, false);
|
||||
|
||||
int nextDepth = useCutoff ? (depth - 1) : depth;
|
||||
float score = minimax(board, nextDepth, alpha, beta, false, useCutoff);
|
||||
|
||||
bestScore = Math.max(bestScore, score);
|
||||
alpha = Math.max(alpha, bestScore);
|
||||
if (beta <= alpha) break; // Pruning
|
||||
|
||||
if (beta <= alpha) {
|
||||
board.undoPly();
|
||||
break; // Pruning
|
||||
}
|
||||
|
||||
board.undoPly();
|
||||
}
|
||||
}
|
||||
@@ -65,10 +98,18 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
HexPly move = new HexPly(board.getCurrentPlayer(), i, j);
|
||||
if (board.isLegal(move)) {
|
||||
board.doPly(move);
|
||||
float score = minimax(board, depth - 1, alpha, beta, true);
|
||||
|
||||
int nextDepth = useCutoff ? (depth - 1) : depth;
|
||||
float score = minimax(board, nextDepth, alpha, beta, true, useCutoff);
|
||||
|
||||
bestScore = Math.min(bestScore, score);
|
||||
beta = Math.min(beta, bestScore);
|
||||
if (beta <= alpha) break; // Pruning
|
||||
|
||||
if (beta <= alpha) {
|
||||
board.undoPly();
|
||||
break; // Pruning
|
||||
}
|
||||
|
||||
board.undoPly();
|
||||
}
|
||||
}
|
||||
@@ -77,6 +118,22 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Score terminal (feuille) du point de vue de PLAYER1 :
|
||||
* - WIN : PLAYER1 gagne
|
||||
* - LOSS : PLAYER1 perd
|
||||
*/
|
||||
private float terminalScore(HexBoard board) {
|
||||
Result r = board.getResult();
|
||||
if (r == null) return 0f;
|
||||
if (r == Result.WIN) return 1000000f;
|
||||
return -1000000f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Heuristique actuelle (inchangée) : distance au centre des pions PLAYER1.
|
||||
* (Je ne la modifie pas pour ne pas toucher à la logique existante.)
|
||||
*/
|
||||
private float evaluateBoard(HexBoard board) {
|
||||
int size = board.getSize();
|
||||
int center = size / 2;
|
||||
@@ -90,4 +147,19 @@ public class MiniMaxBot extends AbstractGamePlayer {
|
||||
}
|
||||
return score;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compte les coups légaux (cases vides) sur le plateau courant.
|
||||
*/
|
||||
private int countLegalMoves(HexBoard board) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < board.getSize(); i++) {
|
||||
for (int j = 0; j < board.getSize(); j++) {
|
||||
if (board.getCellPlayer(i, j) == null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user