- hVertical/hHorizontal : différence de coups disponibles entre les deux rôles - MiniMax : bestMove + maxValue/minValue récursifs avec comptage nœuds/feuilles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
124 lines
2.8 KiB
Java
124 lines
2.8 KiB
Java
package iialib.games.algs.algorithms;
|
|
|
|
import iialib.games.algs.GameAlgorithm;
|
|
import iialib.games.algs.IHeuristic;
|
|
import iialib.games.model.IBoard;
|
|
import iialib.games.model.IMove;
|
|
import iialib.games.model.IRole;
|
|
|
|
public class MiniMax<Move extends IMove,Role extends IRole,Board extends IBoard<Move,Role,Board>> implements GameAlgorithm<Move,Role,Board> {
|
|
|
|
// Constants
|
|
/** Defaut value for depth limit
|
|
*/
|
|
private final static int DEPTH_MAX_DEFAUT = 4;
|
|
|
|
// Attributes
|
|
/** Role of the max player
|
|
*/
|
|
private final Role playerMaxRole;
|
|
|
|
/** Role of the min player
|
|
*/
|
|
private final Role playerMinRole;
|
|
|
|
/** Algorithm max depth
|
|
*/
|
|
private int depthMax = DEPTH_MAX_DEFAUT;
|
|
|
|
|
|
/** Heuristic used by the max player
|
|
*/
|
|
private IHeuristic<Board, Role> h;
|
|
|
|
//
|
|
/** number of internal visited (developed) nodes (for stats)
|
|
*/
|
|
private int nbNodes;
|
|
|
|
/** number of leaves nodes nodes (for stats)
|
|
|
|
*/
|
|
private int nbLeaves;
|
|
|
|
// --------- Constructors ---------
|
|
|
|
public MiniMax(Role playerMaxRole, Role playerMinRole, IHeuristic<Board, Role> h) {
|
|
this.playerMaxRole = playerMaxRole;
|
|
this.playerMinRole = playerMinRole;
|
|
this.h = h;
|
|
}
|
|
|
|
//
|
|
public MiniMax(Role playerMaxRole, Role playerMinRole, IHeuristic<Board, Role> h, int depthMax) {
|
|
this(playerMaxRole, playerMinRole, h);
|
|
this.depthMax = depthMax;
|
|
}
|
|
|
|
/*
|
|
* IAlgo METHODS =============
|
|
*/
|
|
|
|
@Override
|
|
public Move bestMove(Board board, Role playerRole) {
|
|
System.out.println("[MiniMax]");
|
|
nbNodes = 0;
|
|
nbLeaves = 0;
|
|
|
|
Move bestMove = null;
|
|
int bestValue = IHeuristic.MIN_VALUE;
|
|
|
|
for (Move move : board.possibleMoves(playerMaxRole)) {
|
|
Board successor = board.play(move, playerMaxRole);
|
|
int value = minValue(successor, 1);
|
|
if (value > bestValue) {
|
|
bestValue = value;
|
|
bestMove = move;
|
|
}
|
|
}
|
|
|
|
System.out.println("Nodes=" + nbNodes + " Leaves=" + nbLeaves);
|
|
return bestMove;
|
|
}
|
|
|
|
/*
|
|
* PUBLIC METHODS ==============
|
|
*/
|
|
|
|
public String toString() {
|
|
return "MiniMax(ProfMax=" + depthMax + ")";
|
|
}
|
|
|
|
/*
|
|
* PRIVATE METHODS ===============
|
|
*/
|
|
|
|
private int maxValue(Board board, int depth) {
|
|
nbNodes++;
|
|
if (board.isGameOver() || depth >= depthMax) {
|
|
nbLeaves++;
|
|
return h.eval(board, playerMaxRole);
|
|
}
|
|
int value = IHeuristic.MIN_VALUE;
|
|
for (Move move : board.possibleMoves(playerMaxRole)) {
|
|
Board successor = board.play(move, playerMaxRole);
|
|
value = Math.max(value, minValue(successor, depth + 1));
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private int minValue(Board board, int depth) {
|
|
nbNodes++;
|
|
if (board.isGameOver() || depth >= depthMax) {
|
|
nbLeaves++;
|
|
return h.eval(board, playerMaxRole);
|
|
}
|
|
int value = IHeuristic.MAX_VALUE;
|
|
for (Move move : board.possibleMoves(playerMinRole)) {
|
|
Board successor = board.play(move, playerMinRole);
|
|
value = Math.min(value, maxValue(successor, depth + 1));
|
|
}
|
|
return value;
|
|
}
|
|
}
|