package fr.iut_fbleau.Bot; import fr.iut_fbleau.Avalam.AvalamBoard; import fr.iut_fbleau.Avalam.AvalamPly; import fr.iut_fbleau.Avalam.Color; import fr.iut_fbleau.Avalam.Tower; import fr.iut_fbleau.GameAPI.AbstractGamePlayer; import fr.iut_fbleau.GameAPI.AbstractPly; import fr.iut_fbleau.GameAPI.IBoard; import fr.iut_fbleau.GameAPI.Player; import fr.iut_fbleau.GameAPI.Result; import java.util.*; /** * Bot "Divin" (fort) pour Avalam. * * * 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; } }