Skip to content

Labo IA

Claude edited this page Oct 13, 2026 · 3 revisions

Labo IA (moteur en jeu) : ce qui existait déjà, ce qui manquait vraiment

À distinguer du Solveur d'éjection forcée — module de preuve exhaustive côté backend, sans évaluation. Cette page couvre le moteur qui joue réellement les parties : evaluateBoard, minimax, searchBestMove, et depuis la v1.47, « Pourquoi ce coup ? ».

Une proposition externe a servi de test de réalité

Une proposition détaillée (« Meta IA ») suggérait de transformer le « labo IA » avec alpha-bêta, table de transposition, tri des coups, WebWorker, une heuristique de danger d'éjection, et un panneau d'explication. Vérifié avant de coder, poste par poste :

Suggéré comme manquant État réel
Alpha-bêta + tri des coups Déjà là — minimax(depth, alpha, beta, ...), coups triés par le code de priorité ULA (éjections d'abord)
Table de transposition (Zobrist) Déjà là — ZOBRIST, hashBoard()
WebWorker (éviter que l'UI gèle) Déjà là — AI_WORKER_CODE, calcul en thread séparé
Heuristique de danger d'éjection Déjà là — dngScore dans evaluateBoard
Bibliothèque d'ouvertures nommées avec winrate Contredit un principe déjà établi — voir Ouvertures : les noms (Belgian Daisy, etc.) désignent des positions de départ, pas des séquences ; il n'existe pas de théorie d'ouvertures façon échecs pour Abalone
Génération automatique de puzzles en masse Contredit un principe déjà établi — voir Solveur : les puzzles doivent être certifiés depuis de vraies parties, jamais générés sans vérification
« Pourquoi ce coup ? » (panneau d'explication) Réellement absent — seule idée retenue

Vérifier avant de construire coûte moins cher que de reconstruire. Cinq des sept points d'une proposition détaillée décrivaient déjà l'existant ou allaient à l'encontre de principes déjà tranchés pour de bonnes raisons. Une recherche dans le fichier réel (grep sur les noms de fonctions) a suffi à trancher chaque point avant d'écrire une seule ligne — la même discipline que pour toute proposition externe reçue sur ce projet.

« Pourquoi ce coup ? » — la seule pièce manquante, construite sur l'existant

evaluateBoard(color) décomposait déjà la position en 8 composantes (matériel, centre, cohésion, bord adverse, capture, mobilité, isolement adverse, danger d'éjection adverse) avant de les sommer en un seul nombre. La décomposition existait — seule la somme sortait de la fonction.

evaluateBoard(color, detail) ajoute un second paramètre optionnel : sans lui, comportement identique à avant (juste le total, tous les appels existants — minimax, quiescence — inchangés) ; avec detail=true, renvoie l'objet complet des 8 composantes.

calculerExplicationCoup(move, color) simule le coup avec applyMove/ undoMove — les mêmes fonctions déjà utilisées des milliers de fois par coup à l'intérieur de minimax, pas une nouvelle mécanique à risque — compare l'évaluation détaillée avant/après, annule proprement. Le delta obtenu est donc exactement ce qui a pesé dans la décision, jamais une estimation reconstruite séparément qui pourrait diverger de la vraie IA.

Calculée dans executeAIMove() avant que le coup choisi ne soit appliqué au plateau réel — la simulation a besoin de l'état d'avant-coup pour que la comparaison ait un sens.

formaterExplicationCoup() garde les 3 composantes les plus significatives par poids absolu — au-delà, la phrase devient illisible et noie le signal utile.

Un bug trouvé en marge, dans une fonctionnalité voisine

Le mode Coach existant (coachEnabled) sauvegarde son état dans localStorage mais ne le relit jamais au démarrage — le réglage ne survit donc pas à un rechargement de page, malgré l'appel à setItem. Pas corrigé ici (hors sujet du correctif en cours), mais le nouveau réglage aiExplainEnabled a été fait correctement dès le départ : restauré via getItem au chargement, avec synchronisation de l'apparence du bouton.

Vérification

750+ tests fonctionnels, dont un fichier dédié (test_ai_explain.js) : le mode détaillé de evaluateBoard reste rétrocompatible, le plateau est identique après simulation (comparaison canonique, insensible à l'ordre d'insertion des clés — une égalité de chaîne JSON brute aurait donné un faux négatif, delete puis réinsertion change l'ordre d'énumération sans changer les valeurs), le delta est réellement mesurable, la phrase est correctement triée et limitée à 3 composantes. Vérifié aussi par exécution réelle dans un navigateur headless : un vrai coup choisi par l'IA, une explication calculée, une bulle affichée et lue à l'écran.

Test des critères de KAAH

Depuis la v2.49. Les critères de KAAH (sumito, menace, fourchette, piège, compacité, cases, gain et perte selon le score) sont dans le moteur, éteints par défaut — voir Réflexion de l'IA. Les activer rend-il l'IA plus forte ? Ils ont un coût : chaque évaluation est plus lente, donc l'IA voit moins loin dans le même temps. Seul un match peut trancher.

Page Labo, encadré « Test : les critères de KAAH » :

  • Duels « IA actuelle + critères de KAAH » contre « IA actuelle seule » — le même duelGame que le Labo, dans un fil de calcul à part (ni le Labo ni une partie n'en sont gênés).
  • Par cycles de 4 parties sur la même ouverture : chaque version joue Noirs puis Blancs, et tient le rôle A puis B. L'avantage d'ouverture s'annule, et l'arbitrage des parties trop longues (fait avec l'évaluation du camp A) aussi.
  • Verdict SPRT avec les seuils du Labo (H0 = +0 Elo, H1 = +35 Elo, α = β = 5 %), après 16 parties au moins et en fin de cycle — sans ce minimum, une série de victoires au début annule la variance mesurée et le verdict tombait dès la 2ᵉ partie (trouvé par les tests). « Indécis » après 400 parties.
  • Rien n'est adopté automatiquement.
  • Limite : 600 ms par coup, 80 coups au plus — un régime de recherche courte. Le verdict porte sur lui, pas forcément sur les niveaux 8 à 10.

Labo v4 : des verdicts fiables, plusieurs parties à la fois, les critères de KAAH réglables

Depuis la v2.54. Revue du Labo d'auto-amélioration (le banc moteur contre moteur, page Labo) : ses verdicts ne tenaient pas.

Ce qui n'allait pas

Défaut Effet
Verdict compté partie par partie, minimum 8 parties, plafond 60 8 victoires de suite donnaient une variance mesurée nulle : verdict immédiat. Et 60 parties, c'est bien trop peu pour trancher : en simulation (≈ 30 % de nulles, le taux mesuré), 96 % des tests d'un mutant sans effet finissaient « indécis », et un mutant nettement meilleur (+70 Elo) n'était adopté que 14 fois sur 100
Parties trop longues arbitrées par l'évaluation du mutant le mutant arbitrait ses propres parties
SPSA : champion = θ à chaque itération (2 parties) les poids de l'IA changeaient sans aucune vérification
« Élo cumulé » = somme des estimations des tests adoptés chaque test adopté l'est parce qu'il a eu de la chance : la somme gonfle (malédiction du vainqueur) et ne baisse jamais
« ▶ revoir » le rejeu tirait l'ouverture une 2ᵉ fois puis rejouait les coups enregistrés, ouverture comprise : position fausse dès le 7ᵉ coup, captures différentes de la vraie partie
Réglages « Ouverture : demi-coups » et « fenêtre d'équilibre » affichés, jamais transmis au moteur (6 et 600 en dur)

Ce qui change

  • Paires d'ouvertures. Chaque ouverture tirée au sort est jouée deux fois, couleurs inversées. Le verdict compte des paires : 0, ½, 1, 1½ ou 2 points (« pentanomial »). L'avantage qu'une ouverture donne à une couleur s'annule dans la paire.
  • GSPRT pentanomial (l'approximation de Van den Bergh, celle de Fishtest) sur les moyennes de paires, avec un a priori de Jeffreys : ½ paire fictive dans chacune des 5 cases. 8 paires gagnées 2-0 ne suffisent plus (LLR 1,90 < 2,94) ; 11 suffisent. Plafond : 250 paires, puis « indécis ».
  • Même modèle simulé, mêmes 30 % de nulles : +70 Elo adopté plus de 99 fois sur 100 (≈ 140 parties), +35 Elo 68 fois, un mutant sans effet adopté à tort ≈ 4 fois sur 100 (le seuil α = 5 %), −35 Elo rejeté 99,9 fois sur 100.
  • Arbitrage par consensus (comme les bancs d'essai d'échecs) : à la limite de coups, captures égales, la victoire n'est donnée que si les deux évaluations, chacune avec ses poids, sont d'accord. Mesuré sur 40 vraies parties avec de petites mutations : les deux règles donnaient le même résultat. L'écart peut venir des grosses valeurs, comme celles des critères de KAAH.
  • Tri : les 3 mutants jouent les mêmes ouvertures (comparaison plus juste) ; la confirmation, elle, part sur des ouvertures neuves. Si aucun mutant n'atteint 50 % au tri, pas de confirmation : génération suivante.
  • SPSA vérifié : θ n'est plus jamais appliqué à l'IA pendant les itérations ; toutes les 50 itérations, un SPRT par paires le confronte au champion, et seule une adoption change l'IA. SPSA asynchrone (chaque itération part du θ du moment), comme les régleurs distribués.
  • Gain réel mesuré : après chaque adoption, le champion joue 25 paires contre les poids d'origine ; Elo ± marge à 95 %, courbe. Bouton « Mesurer maintenant ».
  • Plusieurs parties à la fois : un fil de calcul par partie, la moitié des cœurs (4 au plus), réglable de 1 à 8. Débit affiché. Une partie bloquée (chien de garde) remplace son fil et se rejoue ; trois de suite mettent en pause. Les résultats d'une phase déjà tranchée sont ignorés (numéro d'époque).
  • Critères de KAAH réglables : 16 poids au lieu de 8. Des mutants allument un critère à la valeur de KAAH (« sumito 0→20 ») puis l'ajustent ×1,5 ou ×0,6 ; SPSA les règle avec les autres (départ à la moitié de la valeur de KAAH, sinon θ− reste collé à 0). Case « Régler aussi les critères de KAAH ». Un critère adopté est utilisé par l'IA et apparaît dans le tableau « Réflexion de l'IA ».
  • Le test des critères de KAAH utilise les mêmes paires, le même verdict et les mêmes fils de calcul.

Ce que les parties réelles montrent

Mesuré sur des parties jouées par le moteur lui-même :

Régime Parties Nulles Décidées par 1 à 2 billes d'avance à la limite 6 éjections
Tri (350 ms/coup, 60 coups) 24 16 (67 %) 8 0
Confirmation (600 ms/coup, 80 coups) 16 5 (31 %) 10 1

Au tri, deux parties sur trois finissent sans écart de billes en 60 coups : le tri informe peu. Allonger ses parties le rendrait plus utile, au prix du temps.

Vérification

12 tests (section 49 de tests/engine.test.js) : statistiques par paires ; plusieurs fils en même temps, mêmes ouvertures au tri ; cycle complet tri → confirmation → adoption → bilan → génération suivante ; rejet ; SPSA sans toucher l’IA puis vérifié, et sa partie abandonnée rejouée ; mutants et réglages des critères de KAAH ; reprise d'un état de l'ancien Labo ; chien de garde ; arbitrage par consensus et rejeu exact, sur de vraies parties du moteur. Et un essai réel dans Chromium : 4 fils, 630 parties en deux minutes en réglages rapides, phases enchaînées, aucune erreur.

Clone this wiki locally