Chaque idée est mesurée sur le banc (labo/target/release/arena) contre la version gardée précédente, à temps égal. Une idée n'est gardée que si le banc la montre gagnante. Les versions gardées sont figées dans labo/versions/.
Commande type :
labo/target/release/arena --a "<candidate>" --b labo/versions/vN/play --budget 100 --games 600 --sprt 0,20 --concurrency 4
Les versions gardées et leurs mesures sont dans docs/versions.md.
| # | Idée | Résultat | Décision |
|---|---|---|---|
| 0 | Première évaluation (zone pesant 10) contre la maison, 700 ms chacun, 34 parties | 26 %, 9 défaites sur 12 au blocage | La plus grande zone décide souvent la partie : son poids croît désormais avec le remplissage (→ v1) |
| 1 | Gravité : une case vide coûte davantage par case vide sous elle (+½ case, +1 case par case vide dessous) | −30 Elo (435 parties), −89 Elo (172 parties) | Rejetée. Les cases sous un chemin sont remplies par l'un ou l'autre joueur, et la pénalité compte deux fois les cases d'un chemin vertical. |
| 2 | Même calcul que v1, mais 1,7× plus lent | −8 Elo (600 parties), dans le bruit | La vitesse n'est pas notre goulot : c'est l'évaluation. |
| 3 | Tempo 0 ou 700 (au lieu de 300) | −5 / −3 Elo (600 parties) | Sans effet, on garde 300. |
| 4 | Zone par case occupée : 1 ou 8 (au lieu de 3) | −13 Elo / +55 Elo (SPRT, 318 parties) | 8 gagne : la zone doit peser plus lourd. |
| 5 | Second axe : 30 ou 300 (au lieu de 100) | +8 Elo / +86 Elo (SPRT, 203 parties) | 300 gagne : menacer les deux axes à la fois est une arme. |
| 6 | Pousser plus loin et combiner, contre v1 | zone 8 + axe 600 : +88 · axe 300 : +86 · zone 15 : +57 · zone 8 + axe 300 : +56 · axe 600 : +47 | Écarts dans la marge d'erreur : finale directe. |
| 7 | Finale contre « axe 300 » | zone 8 + axe 600 : +30 (SPRT, 587 parties) · zone 8 + axe 300 : +29 · zone 15 + axe 300 : +10 | Zone 8 + second axe 600 → v2 |
| 8 | Largeur du chemin (poids 100 ou 300, plafond 8 ou 16) contre v2 | +15 / +11 / +10 Elo (800 parties chacun) ; cumul 51,7 % sur 2 400 parties, ≈ +12 Elo | Petit gain, réel mais modeste. Largeur 100 → v3. Elle coûte cher en calcul (0,7 M positions/s au lieu de 1,9) : à optimiser. |
| 9 | Banc de positions à valeur exacte (pêche de fins de partie résolues), calibré sur v1, v2 et v3 | 99,0 % / 99,5 % / 100 % de bons coups | Rejeté : l'examen est trop facile, les positions résolubles en 1 s sont déjà résolues par l'IA en 100 ms. Les duels restent l'outil principal. |
| 10 | Mur suspendu (idée de marmelab, recodée) : une case vide avec k cases vides dessous devient un mur pour l'axe vertical | k=3 : −400 (22 parties) · k=2 : −99 · k=4 : −123 · k=3 sur deux axes : −53 | Rejeté. La ligne du haut est presque toute suspendue en début de partie : l'axe vertical devient infranchissable, et notre IA perd l'arme des deux axes qui lui avait rapporté +86. |
| 11 | Réduction des coups tardifs (LMR) à partir du 2ᵉ, 3ᵉ ou 5ᵉ coup | −6 / +11 / +17 Elo (800 parties chacun) | Tendance positive (réduire moins est mieux), rien de prouvé. À confirmer sur le 5ᵉ coup. |
| 12 | Inspection du mur : une position évaluée 2 924 sans mur passe à 10 524 avec | Un axe « infranchissable » vaut 20 cases × 600 (poids du second axe) : falaise de 9 000 points | Hypothèse : effet de falaise, pas un bug. Test d'un plafond « axe mort = 10 », avec et sans mur, et du mur rejoué avec d'autres ouvertures. |
| 13 | Plafond « axe mort = 10 » · plafond + mur · mur seul (autres ouvertures) | +19 Elo (800) · −4 Elo (800) · −458 Elo (15, reproduit) | Hypothèse confirmée : la falaise causait le désastre du mur. Le mur adouci est neutre, on l'abandonne. Le plafond est une tendance positive. |
| 14 | Candidate v4 = plafond 10 + LMR dès le 5ᵉ coup, contre v3, SPRT [0, 15] jusqu'à 2 000 parties | −14 Elo [−34, +7] sur 1 125 parties | Rejetée : les +17 et +19 isolés étaient du bruit. Règle désormais : une idée doit passer le SPRT à elle seule, on n'empile pas des gains non prouvés. |
| 15 | Tri des coups par cases des plus courts chemins (les deux joueurs, les deux axes), à partir de la profondeur 2 | +24 Elo (SPRT, 1 424 parties). 15 à 25 % de positions examinées en moins à résultat égal. | Gardé → v4. Prédiction démentie : j'attendais quelques Elo, par la seule vitesse ; un meilleur ordre améliore aussi la qualité. |
| 16 | Menaces en bout de recherche (gain en un coup, prolongement si l'adversaire menace), déclenchées à 2, 3 ou 4 cases de la victoire | +1 Elo (2 000 parties) / −49 / −63 | Rejeté : la recherche (5 à 7 coups) voit déjà les gains en un coup, et la vérification coûte cher à chaque feuille. |
| 17 | Contrôle v4 contre la maison (200 ms, 400 parties) | 45,5 % (Elo −31) | v4 et v3 indiscernables contre la maison (marge ±35). |
| 18 | Réglage Texel : 6 000 parties de v4 contre elle-même (cœurs économes), 52 192 positions étiquetées par le résultat. Erreur de contrôle 0,183 (6 critères) → 0,173 (avec mobilité, réserve, grandes pièces) | Poids réglés : tempo ~1 300-1 475 (proche des 1 133 mesurés par marmelab), largeur ~340, second axe ~850-930, mobilité 219 par coup d'écart | Duels contre v4 : 6 poids de base réglés +12 (2 000 parties, non prouvé) ; 9 poids avec candidats +35 (SPRT, 849 parties) → v5. |
| 19 | Contrôle v5 contre la maison (200 ms, 400 parties) | 53,0 % (Elo +21) | Premier passage au-dessus de 50 % à temps égal. Deuxième tour Texel lancé sur des parties de v5. |
| 20 | Deuxième tour Texel (48 599 positions de v5) avec trois candidats : urgence (carré des distances), menace imminente, nombre de groupes | Erreur 0,178 → 0,175 ; groupes −657, urgence −166, menace imminente ≈ 0. Duel contre v5 : +38 (SPRT, 788 parties) | → v6 |
| 21 | Contrôle v6 contre la maison (200 ms, 400 parties) | 53,6 % (Elo +25) | Pas mieux que v5 malgré +38 en duel direct : troisième signe que les gains contre soi-même se transfèrent mal. Hypothèse : le réglage sur nos propres parties apprend à battre notre style. Piste : mêler des parties contre la maison aux données. |
| 22 | Troisième tour Texel sur données mêlées (48 643 positions de v6 contre elle-même + 39 786 contre la maison) | Erreur 0,166 → 0,163. Contre v6 : +8 (2 000 parties, non prouvé) ; contre la maison : 50,9 % (1 000 parties), moins bien que v6 (54,4 %) | Rejeté. Avec les critères actuels, le réglage semble plafonner : il faut de nouveaux critères. v6 reste la référence, et bat la maison à 54,4 % sur 3 000 parties (Elo +31 ± 12). |
| 23 | Critère « asphyxie » : pièces en réserve sans aucune place légale (adversaire moins soi) | Texel lui donne 1 406 par pièce. Test sur les poids de v6 + asphyxie seule | Contre v6 : −15 (SPRT, 1 036 parties) ; contre la maison : 51,6 % (moins bien que v6) |
| 24 | Poids de début et de fin de partie, mélangés selon le remplissage (deux poids par critère, réglés par Texel sur 189 220 positions) | Erreur de contrôle 0,170 → 0,167. Second axe 1 191 → 208, largeur 921 → ≈ 0, groupes −901 → ≈ 0, mobilité 117 → 450, asphyxie 201 → 1 774, tempo +2 678 → −1 951 (zugzwang en fin de partie). Contre v6 : −2 (2 000 parties) ; contre la maison : 52,8 % | Rejeté. Deuxième fois qu'une meilleure prédiction ne donne pas un meilleur jeu : la recherche compense déjà ces nuances, et l'asphyxie coûte du calcul. L'évaluation de v6 semble au plateau : les prochains gains viendront de la puissance de calcul (vitesse, multicœur, livre). |
| 25 | Vitesse, sans changer le jeu : banc à profondeur fixe (speed, 40 positions, profondeur 5) avec empreinte des coups et scores. Profil macOS : 45 % du temps dans le comptage des coups (mobilité), 24 % dans les plus courts chemins. |
4,06 s → 2,08 s (×1,95) à empreinte, nombre de positions et règles identiques (537 643 cas revérifiés). Places comptées une fois par forme pour les deux joueurs ; test de pose direct sur les hauteurs ; parcours de distance réutilisé pour la largeur ; zone et groupes en un passage. | → v7 (v6 deux fois plus rapide). Duel v7 contre v6 : +17 Elo (52,4 %, 2 000 parties). Doubler la vitesse vaut une quinzaine d'Elo à 100 ms. |
| 26 | Architecture Apple M4 (MacBook Air, sans ventilateur ; 4 cœurs rapides + 6 économes ; lignes de cache de 128 octets ; L2 16 Mo) et leçons du 100 Million Row Challenge (gagnant : tous les cœurs, tables précalculées, données compactées) | Chauffe : aucune dérive sur 6 passages, aucun avertissement thermique de macOS. Table de transposition compacte (16 octets par entrée, paquets de 128 octets) : même empreinte, pas de gain de vitesse visible, mémoire ÷ 4 (32 Mo). | Gardée pour le multicœur. |
| 27 | Multicœur (Lazy SMP) : fils partageant la table (sans verrou, vérification par XOR), décalage de profondeur d'un fil sur deux | Temps pour la profondeur 6 (20 positions) : 1 fil 4,22 s · 2 fils 3,24 s (×1,30) · 4 fils 2,87 s (×1,47) · 6 fils 3,03 s. Même empreinte. Duel 2 fils contre 1 fil (100 ms, 2 parties à la fois) : +23 Elo (SPRT, 1 511 parties) | Plus que le seul gain de vitesse (+17 pour ×2) : le partage de la table apporte en plus. → v8 (1 fil par défaut, LINKX_SEARCH_THREADS en tournoi). |
| 28 | Simulation du tournoi : v8 à 4,5 s et 4 fils contre la maison à 0,7 s (son budget réel), 2 parties à la fois | 62,3 % (Elo +87, [+39, +139]), 200 parties, 0 faute, 18 min | On bat nettement le maître dans les conditions de jeudi. Rendements décroissants : +31 à temps égal, seulement +56 de plus avec 6× le temps et 4 fils. On s'arrête souvent avant la fin du budget : piste « mieux utiliser le temps ». |
| 29 | Usage du temps : entamer une itération tant que moins de X % du budget est consommé ; dans une itération interrompue, garder tout coup qui bat celui de l'itération précédente | Contre v8, 2 000 parties chacun : 50 % → +9 ; 70 % → +18 ; 50 % avec l'ancienne règle de reprise → +13 | Signal cohérent mais aucun résultat prouvé seul, et le meilleur de trois est surestimé (malédiction du gagnant ; mêmes ouvertures pour les trois). Adopté comme probable → v9, à confirmer à temps long avec d'autres ouvertures. |
| 30 | Mesure pour le livre (plateau vide, 6 fils sur les cœurs économes) | Profondeur 6 : 1,6 s · 7 : 15 s · 8 : 43 s (alternance pair/impair) | La profondeur 9 ou 10 sur les 17 départs est faisable en une nuit. Générateur passé en profondeur fixe avec reprise. |
| 31 | Relecture « performance » (agent) et optimisations sans changement de jeu : voisinage à 8 en quatre décalages (A1), distance coupée à la réserve (A3), cache d'évaluation par fil de 1 Mo (A4) | Empreinte identique, règles revérifiées (537 643 cas). Cœurs rapides, 40 positions, profondeur 5 : v9 2,19 à 2,81 s → 1,59 s | Nouvelle base (≈ ×1,4 à 1,75). Quatre idées de recherche codées, désactivées par défaut, en duel contre elle : chemins hérités pour le tri (−5,5 % de nœuds à résultat égal), vieillissement de la table, déclin de l'historique, fenêtres d'aspiration. |
| 32 | Comparaison point par point avec le moteur de marmelab (agent, lecture seule) | Défaut trouvé : urgence (−166 × (distance² adverse − distance² propre)) + axe mort à 20 ⇒ adversaire bloqué (20) contre nous à 3 ≈ −20 000, contre 0 si l'adversaire est à 3. Un adversaire bloqué nous paraît pire qu'un adversaire menaçant. Leurs critères actifs qu'on n'a pas : zoneStall, caps (case posée sur une case adverse), bar3 (barre de 3 en réserve, 61 % à 1 s chez eux) ; leur mur suspendu marche avec un second axe à 94 et un axe mort à 10. Leur mobilité : mesurée nulle. | À faire : axe mort à 10 + réajustement Texel ; puis bar3, caps, zoneStall comme candidats ; puis mur suspendu avec le plafond corrigé. Nos matchs contre le maître se sont tous joués sans livre de notre côté. |
| — | Incident : deux matchs contre le maître lancés en double (file d'attente mal arrêtée) ont tourné en même temps et écrit dans le même journal | Chiffres partiels (58 %, 54 %) invalides | Match relancé seul. Leçon : attendre un processus par son nom exact (pgrep -x), jamais par un motif qui peut correspondre à la commande d'attente elle-même. |
| 33 | Match à temps égal : v8 (4,5 s, 4 fils, sans livre) contre le maître de marmelab (4,5 s, avec son livre à profondeur 9), 2 parties à la fois | 50,7 % (Elo +5), 200 parties | Égalité. À temps égal, notre avantage à 100 ms (+31) disparaît : son livre et sa recherche profonde compensent. Priorités : livre d'ouverture, correction du défaut d'urgence, efficacité de la recherche. |
| 34 | Relecture « bugs » (agent, lecture seule) | Aucun bug qui fasse perdre une partie avec les réglages par défaut (tours passés, arrêt au temps, attente des fils, livre et reflet vérifiés ; dépassement du budget ≤ ~10 ms). À corriger : historique jamais réduit sur un serveur qui enchaîne ~100 parties (débordement possible, biais des parties précédentes) ; entrées résolues (profondeur ≥ poses restantes) non réutilisées aux itérations suivantes ; même position écrasée par une entrée moins profonde ; table jamais vidée entre parties (activer le vieillissement pour le serveur) ; décalage de profondeur index % 2 inefficace au-delà de 2 fils ; fils auxiliaires recréés à chaque coup ; LMR : ne jamais réduire quand la profondeur couvre les poses restantes ; serveur : revérifier le coup du livre, compter l'attente dans la file. |
Corrections prévues demain matin, par ordre de gravité. |
| 35 | Duels de recherche contre la nouvelle base (2 000 parties chacun, 100 ms) | Chemins hérités : +13 · vieillissement de la table : +2 · déclin de l'historique + malus : +13 · aspiration ±1 300 : −43 (SPRT, 460 parties) | Aspiration rejetée : le score varie trop d'une itération à l'autre. Héritage et historique positifs mais non prouvés : à tester ensemble. |
| 36 | Corrections de la relecture, codées le soir (non encore validées en duel) : historique toujours divisé par deux et tueurs remis à zéro à chaque recherche ; entrées résolues réutilisées (depth.min(remaining)) ; même position non écrasée par une borne moins profonde de la même recherche ; vieillissement de la table et malus d'historique par défaut ; auxiliaires décalés de 1, 2, 1, 2… et gardés d'un coup à l'autre ; LMR interdite quand la profondeur couvre les poses restantes ; serveur : coup du livre revérifié, 8 fils de requêtes |
Empreinte identique à profondeur 5, −5 % de nœuds ; 6 parties à 4 fils sans faute | Duel de validation demain matin. |
| 37 | Trois relectures par agents (stratégie marmelab, gains d'Elo mesurés ailleurs, critique de notre méthode) | Élagage = plus gros gisement mesuré ailleurs (LMR ~208 Elo, LMP ~204 dans Stockfish). Critique : match à 4,5 s joué avec le défaut d'historique ; ouvertures du banc au hasard, peu réalistes ; SPRT [0, 15] trop peu sensible ; LMR rejetée à 100 ms. | Ouvertures du banc tirées parmi les 4 meilleurs coups d'une recherche courte ; SPRT [0, 10] ; tests d'élagage à 500 ms. |
| 38 | Réflexion pendant le tour adverse (joueur du banc : recherche de la position où l'adversaire a le trait, arrêtée à l'arrivée de la demande), 100 ms, 2 parties à la fois | 51,8 % (Elo +13), 2 000 parties | Positif ; à 100 ms la réflexion gagnée est très courte, le gain devrait croître en tournoi. À porter dans le serveur. |
| 39 | Référence : base corrigée (essai 36), 4,5 s et 4 fils, contre le maître 4,5 s, 400 parties sur ouvertures réalistes | 57,5 % (Elo +53) | Les corrections valaient ~+50 à temps long (v8 : 50,7 %). On bat le maître à temps égal. |
| 40 | Élagage à 500 ms, SPRT [0, 10] : LMR logarithmique (dès le 3ᵉ coup, r = ln d × ln i / 2, −1 si bon historique, jamais quand la profondeur couvre les poses restantes) · LMP (8 × profondeur) · les deux | LMR : +45 (SPRT, 864 parties) · LMP : −3 (1 500) · les deux : +36 | LMR adoptée → v10. LMP rejetée. La LMR avait été rejetée à tort à 100 ms (essais 11 et 14). |
| 41 | Livre : v10 atteint déjà en direct (4,5 s, 4 fils) la profondeur 8 à 9 sur les départs ; le livre de la nuit (profondeur 9, 248 positions, moteur v9) n'a donc plus d'avance | Départs recalculés avec v10 à profondeur 11 (9 à 52 s chacun sur 10 fils), réponses à profondeur 11 (~10 s chacune, reléguées sur les cœurs économes) ; du livre de la nuit, seules les 3 victoires prouvées sont gardées | Livre = départs 11 + réponses 11 au fil du calcul + victoires prouvées. |
| 42 | Réflexion pendant le tour adverse dans le serveur : une table partagée par toutes les requêtes, réflexion arrêtée à l'arrivée de toute requête, lancée seulement si aucune ne cherche | Test de bout en bout, conditions du tournoi (HTTP signé, 2 parties à la fois, v10 4 fils + livre 45 positions contre la maison à 0,7 s) : 29-4-1 (86,8 %), temps max 4,88 s (client) / 4,64 s (serveur), 0 faute, 22 coups du livre | Serveur prêt pour la vague. |
| 43 | Inscription et mise en ligne : ngrok (compte perso, domaine fixe tiringly-datolitic-lorinda.ngrok-free.dev), secret de signature, sonde OK (4 634 ms), qualification contre la maison (« The Missing Linkx », 1 177 Elo, 13ᵉ) menée sans faute. Budget ramené à 4,2 s (vu de la plateforme : ~4,4 s, marge ~1,6 s). |
L'IA est au classement (1 200, 0 partie) pour la vague de cette nuit. | Leçon : un compte ngrok d'organisation imposait une restriction d'IP (ERR_NGROK_3205). |
| 44 | Table de transposition de 512 Mo contre 32 Mo (500 ms, 1 fil) | −108 Elo (SPRT, 293 parties) | Rejeté. Sur le M4, la TLB couvre ~48 Mo (pages de 16 Ko, pas de grandes pages) : au-delà, chaque sonde aléatoire coûte un défaut de TLB. |
| 45 | Deux recherches simultanées : 4 + 4 fils contre 2 + 2 (recommandation de l'agent) | 4 + 4 atteint la même profondeur ou un niveau de plus dans chaque paire | On garde 4 fils par requête, même si une partie déborde sur les cœurs économes. |
| 46 | Coup réponse (réplique ayant réfuté le coup adverse précédent, après les tueurs), 500 ms | −3 Elo (3 000 parties) | Rejeté : le tri est déjà bon. |
| 47 | Extension des coups uniques (singular extensions : dès la profondeur 6, coup de table testé contre les autres à profondeur réduite, marge 1 000), 500 ms | +7 Elo (3 000 parties, non prouvé) | Écarté pour la vague ; à retester à temps long. |
| 48 | ProbCut (hors variante principale, dès la profondeur 5 : recherche réduite de 4 niveaux, coupure si elle dépasse la fenêtre d'une marge), 500 ms | Profondeur 7 : nœuds ÷ 2. Marge 2 000 : +25 (SPRT, 1 738 parties) ; marge 1 000 : +28 (SPRT, 1 541 parties) | Départage : marge 1 000 contre 2 000 → −18 (957 parties), on garde 2 000. À temps long (2 s, 2 fils) : 52,8 % (300) puis 55,3 % (300), soit |
| 49 | Axe mort LINKX_DEAD=8 contre 20 (v11, 500 ms) |
−4 Elo (2 500 parties) | Rejeté. |
| 50 | Mode positions fixes (LINKX_NODES) : la recherche s'arrête après N positions, indépendamment de la vitesse du cœur ; bancs reproductibles sur les 10 cœurs |
Empreinte identique quand le mode est coupé ; même N ⇒ même coup, même profondeur | Adopté pour les bancs. Limite : ne voit pas les changements de vitesse ; tout gain doit être confirmé au temps. Les cœurs économes restent ~4 fois plus lents (sous taskpolicy -b, fréquence minimale). |
| 51 | Coup nul (dès la profondeur 3, réduction 3, jamais au-delà de 50 cases remplies), 350 000 positions | −19 Elo (1 480 parties, SPRT) | Rejeté : à Linkx, jouer n'est pas toujours un avantage (zugzwang), même avant la fin de partie. |
| 52 | Élagage par l'évaluation statique (profondeur ≤ 2, marge 1 500 par niveau) · même jusqu'à la profondeur 3 | Profondeur 2 : +15 (3 000 parties, positions fixes), puis +9 [−4, +22] au temps (2 800 parties, 500 ms) · profondeur 3 : 0 (1 580 parties) | Non prouvé : écarté de la v12, à retester à temps long. |
| 53 | Déploiement sur le serveur de Julien (Ryzen 9 7900, 12 cœurs) : dépôt public camilleislasse/linkx-challenge (bot seul, étiquettes par version), Docker Compose, Traefik sur https://oro.multimod.ovh, secret hors dépôt. Répétition Mac (8788) contre serveur par HTTP signé, 2 parties à la fois |
66 parties : serveur 35 – Mac 31, 0 faute, temps max 4,26 s (réseau compris). Sonde de la plateforme : 4 354 ms | Adresse basculée sur la plateforme : la vague se joue depuis le serveur. Le Mac garde ngrok en secours. |
| 54 | Mesure sur le Ryzen (4 s par coup, 5 positions, seule / deux à la fois) : 6 ou 12 fils × table de 16, 32 ou 64 Mo. Grandes pages Linux : always |
12 fils : même profondeur (le décompte ne compte que le fil principal, il ne compare pas les fils). 64 Mo : +15 % de positions à deux recherches | On garde 6 fils ; table de 64 Mo pour le serveur. |
| 55 | Profileur (sample, samply, fonctions empêchées d'être fusionnées sur une copie) : placements_by_shape (mobilité) = 30 % du temps (95 essais de pose par évaluation) |
Places comptées par profils de relief (colonnes où chaque marche vaut celle de la pièce, en masques de bits), même méthode pour les coups légaux ; plus listes de coups réutilisées, tri sans allocation, groupes et couches non remis à zéro | ×1,6 à coups identiques (0,98 s → 0,62 s pour 1,5 M positions ; empreinte identique sur 6 positions ; 30 000 positions comparées à l'ancienne méthode). Puis groupes réutilisés sur place (le code machine montrait 680 octets remis à zéro et 2 × 1 360 octets recopiés par évaluation), hauteurs de pose précalculées, victoire testée seulement si les deux bords sont touchés : ×1,70. Au temps contre v11 (500 ms, version ×1,6) : +25 Elo [+7, +44], 1 400 parties. |
| 56 | Raccourcis tirés des règles : fin de partie jouée d'avance (zone qui dépasse tout ce que l'adversaire peut encore posséder, adversaire sans chemin possible) · table rangée par position ou son miroir | Le premier ne se déclenche jamais (0 sur 20 000 parties au hasard) : cases posées + réserve = 42 pour tout joueur, et aucune zone ne dépasse 42. Le second ne sert que si la racine est symétrique, cas déjà couverts par le livre | Abandonnés. Une vraie borne demanderait les zones encore agrandissables, utile seulement là où la recherche résout déjà tout. |
| 57 | Élagage statique et coups uniques retestés sur la version rapide (×1,97), 500 ms au temps / 600 000 positions | Élagage : +2 [−15, +19] (1 560 parties) ; coups uniques : −9 [−28, +11] (1 200 parties) | Écartés. Le gain de l'élagage sur v11 venait sans doute du calcul qu'il épargnait : la vitesse le rend inutile. LMR 150 : −11 (800 parties), écarté. |
| 58 | Déploiement de la v12 : dépôt réduit au seul bot (bot/, 23 fichiers ; labo/, docs/, reference/ restent en local), CLAUDE.md pour le Claude du serveur, compose.traefik.yaml, étiquettes par version. Julien passe en v12 |
Empreinte identique sur le serveur ; partie signée par Internet : max 4,43 s, 0 faute | En prod pour la vague. Leçon : ne rien pousser sur GitHub sans accord explicite (un commit poussé trop tôt a dû être retiré). |
| 59 | v13, gains à coups identiques : composantes du joueur qui pose déduites de celles du parent (+4 %), chute directe + relief par table (+3 %), profils sans boucle (+2 %) | ×2,2 sur v11 | Gardé en local. |
| 60 | Essais de vitesse sans effet ou négatifs : cache d'évaluation ×4 (plus lent : sort du cache du processeur), motifs de bas partagés entre orientations (plus lent), vérifications d'indice retirées (nul : déjà éliminées par le compilateur), test rapide « l'adversaire peut jouer » (nul), victoire testée depuis la pièce posée (nul), groupes atteints lus par les cases voisines (−8 %), deux parcours entrelacés (nul), union des voisinages pour sauter la boucle (nul) | — | Annulés. Il ne reste plus de travail inutile visible au profil : le parcours des chemins (28 %) et la recherche (22 %) sont du calcul utile. La suite passe par un changement d'algorithme (distances mises à jour au fil des coups) ou par l'Elo (tri, évaluation). |
| 61 | Verdict par paires (SPRT pentanomial, comme fishtest) : les deux parties d'une paire partent de la même ouverture, compter la paire retire le bruit de l'ouverture. Contrôle : 400 000 contre 100 000 positions | Verdict en 220 parties au lieu de 419 | Adopté par défaut dans l'arène (--trinomial pour l'ancien calcul). |
| 62 | Banc sur GitHub Actions (dépôt public : minutes gratuites, 20 machines de 4 cœurs, 6 h par tâche) : arène dans bench/, workflow « Banc » par matrice de réglages ; puis un réglage réparti sur plusieurs machines (ouvertures distinctes par --offset : à positions fixes, une même ouverture redonne la même partie) et verdict additionné |
Une machine ≈ 0,5 partie/s à 1,5 M positions, soit ~0,7 Mac ; 20 machines ≈ 15 Mac, sans chauffe | Adopté : le Mac reste libre pendant les bancs. |
| 63 | Arrêt anticipé mesuré sur 200 parties tracées (score de chaque coup) : issue prouvée seule, ou même camp au-delà d'un seuil pendant K coups | Prouvée seule : 1,8 % de temps épargné. Seuil 3 000 sur 4 coups : 14 %, 0 arrêt faux (les erreurs commencent à 2 000) | Adopté dans le banc (--adjudicate 3000). |
| 64 | Banc à joueurs dans un même processus (réglages propres à chaque fil) et cache d'évaluation partagé entre A et B | Parties identiques coup par coup (un fil) ; vitesse : 63 s partagé, 61 s non partagé, 58 s en processus séparés | Rejeté et retiré : chaque joueur retrouve déjà l'essentiel dans son propre cache. Au passage : le banc n'est pas reproductible d'un lancement à l'autre avec plusieurs fils (la table d'un joueur dépend des parties qu'il a enchaînées), sans effet sur les statistiques. |
| 65 | Premiers réglages au banc GitHub (v13, 1,5 M positions, par paires) | Aspiration 500 : −20 (360) · LMR dès le 2ᵉ coup : −9 (700) · LMR diviseur 225 : −14 (528) · LMR seulement hors chemins : −60 (257) · table sans vieillissement : −23 (364) | Tous rejetés. 15 autres en cours. |
| 66 | CI à chaque envoi : 14 tests, empreinte de jeu sur 6 positions (bot/tests/empreinte.tsv, mise à jour dans le commit qui change le jeu) et image Docker du serveur avec son empreinte |
Le contrôle d'empreinte rejette bien un réglage différent (6 écarts) | Adopté. |
| 67 | Le mode d'emploi du serveur devient DEPLOIEMENT.md (au lieu de CLAUDE.md, chargé d'office par tout Claude Code ouvert sur le dépôt, y compris le nôtre) ; le journal devient le README.md du dépôt, avec docs/versions.md |
— | À partir de la v13, Julien dit à son Claude : « lis DEPLOIEMENT.md ». |
| 68 | Vérification de la v13 en conditions de prod (serveur HTTP, 6 fils, table de 64 Mo, livre, requêtes signées), deux parties simultanées | 41 coups, max 4,21 s, profondeur jusqu'à 18, 0 panne, 0 coup de secours ; CI verte sur x86 (tests, empreinte, image Docker) | v13 étiquetée pour la vague du 1ᵉʳ octobre, si Julien la déploie avant minuit ; sinon la v12 joue. |