diff --git a/fr/iut_fbleau/Bot/DivineBot.java b/fr/iut_fbleau/Bot/DivineBot.java index cbc6fec..3ffd569 100644 --- a/fr/iut_fbleau/Bot/DivineBot.java +++ b/fr/iut_fbleau/Bot/DivineBot.java @@ -18,5 +18,175 @@ import java.util.*; * * Objectif : trop fort. */ public class DivineBot{ + private final Player me; + private final int maxDepth; + private final Random rng = new Random(); + public DivineBot(Player p, int maxDepth) { + super(p); + this.me = p; + this.maxDepth = Math.max(1, maxDepth); + } + + // ===================== COUP À JOUER ===================== + + @Override + public AbstractPly giveYourMove(IBoard board) { + + if (board == null || board.isGameOver()) return null; + + List moves = listMoves(board); + if (moves.isEmpty()) return null; + + boolean isMax = board.getCurrentPlayer() == me; + + int bestValue = isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE; + List bestMoves = new ArrayList<>(); + + int alpha = Integer.MIN_VALUE; + int beta = Integer.MAX_VALUE; + + for (AbstractPly m : moves) { + IBoard next = board.safeCopy(); + next.doPly(m); + + int value = alphaBeta(next, maxDepth - 1, alpha, beta); + + if (isMax) { + if (value > bestValue) { + bestValue = value; + bestMoves.clear(); + bestMoves.add(m); + } else if (value == bestValue) { + bestMoves.add(m); + } + alpha = Math.max(alpha, bestValue); + } else { + if (value < bestValue) { + bestValue = value; + bestMoves.clear(); + bestMoves.add(m); + } else if (value == bestValue) { + bestMoves.add(m); + } + beta = Math.min(beta, bestValue); + } + } + + return bestMoves.get(rng.nextInt(bestMoves.size())); + } + + // ===================== ALPHA-BETA ===================== + + private int alphaBeta(IBoard board, int depth, int alpha, int beta) { + + if (board.isGameOver()) { + return terminalValue(board); + } + + if (depth == 0) { + return evaluate(board); + } + + List moves = listMoves(board); + if (moves.isEmpty()) { + return evaluate(board); + } + + boolean isMax = board.getCurrentPlayer() == me; + + if (isMax) { + int best = Integer.MIN_VALUE; + for (AbstractPly m : moves) { + IBoard next = board.safeCopy(); + next.doPly(m); + + int val = alphaBeta(next, depth - 1, alpha, beta); + best = Math.max(best, val); + alpha = Math.max(alpha, best); + + if (alpha >= beta) break; + } + return best; + } else { + int best = Integer.MAX_VALUE; + for (AbstractPly m : moves) { + IBoard next = board.safeCopy(); + next.doPly(m); + + int val = alphaBeta(next, depth - 1, alpha, beta); + best = Math.min(best, val); + beta = Math.min(beta, best); + + if (alpha >= beta) break; + } + return best; + } + } + + // ===================== TERMINAL ===================== + + private int terminalValue(IBoard board) { + Result r = board.getResult(); + if (r == null) return 0; + + boolean botIsP1 = (me == Player.PLAYER1); + + if (r == Result.DRAW) return 0; + + if (botIsP1) { + return (r == Result.WIN) ? 100000 : -100000; + } else { + return (r == Result.LOSS) ? 100000 : -100000; + } + } + + // ===================== ÉVALUATEUR ===================== + + /** + * Évaluateur heuristique Avalam : + * - tours finales > quasi finales > stables > faibles + * - approximation du score final + */ + private int evaluate(IBoard board) { + + if (!(board instanceof AvalamBoard)) return 0; + AvalamBoard b = (AvalamBoard) board; + + Color myColor = (me == Player.PLAYER1) ? Color.YELLOW : Color.RED; + Color oppColor = (me == Player.PLAYER1) ? Color.RED : Color.YELLOW; + + int score = 0; + + for (int r = 0; r < AvalamBoard.SIZE; r++) { + for (int c = 0; c < AvalamBoard.SIZE; c++) { + + Tower t = b.getTowerAt(r, c); + if (t == null) continue; + + int h = t.getHeight(); + int value; + + if (h == 5) value = 1000; // tour gagnée + else if (h == 4) value = 300; // quasi gagnée + else if (h == 3) value = 120; // stable + else if (h == 2) value = 40; + else value = 10; + + if (t.getColor() == myColor) score += value; + else if (t.getColor() == oppColor) score -= value; + } + } + + return score; + } + + // ===================== OUTILS ===================== + + private List listMoves(IBoard board) { + List moves = new ArrayList<>(); + Iterator it = board.iterator(); + while (it.hasNext()) moves.add(it.next()); + return moves; + } }