L'étude des jeux : attracteurs et minmax
Cours complet · informatique (tronc commun des prépas scientifiques), chapitre 20 · prépas scientifiques, tronc commun
Travailler ce chapitre sur Adloun Exercices corrigés de ce chapitre
<i class="fa-solid fa-compass mr-2" style="color:#9A563B"></i>20.1 Introduction et motivation
Peut-on gagner à coup sûr ? La question hante les jeux depuis toujours — et l'informatique lui a donné un sens précis et des réponses : le morpion est un match nul si personne ne se trompe ; le puissance 4 est gagné par le premier joueur ; les dames sont nulles (calcul achevé en 2007, après dix-huit ans de machine). Derrière ces verdicts, une seule idée : un jeu à deux joueurs est un graphe — les sommets sont les positions, les arcs les coups — et « bien jouer » est un problème de parcours, justiciable de tout l'arsenal des chapitres 12 à 14.
Ce chapitre construit la théorie sur les jeux d'accessibilité : deux joueurs déplacent un jeton, l'un veut atteindre certaines positions finales, l'autre veut l'en empêcher. On y définit ce qu'est une stratégie, une stratégie gagnante, une position gagnante — et l'on calcule tout cela par l'algorithme des attracteurs, un parcours de graphe à rebours d'une élégance rare. Puis on affronte la réalité : l'arbre des échecs a plus de positions que l'univers d'atomes — quand le calcul exact est hors de portée, on explore à profondeur bornée et l'on évalue les positions frontières par une heuristique : c'est l'algorithme minmax, cœur de tous les programmes de jeu classiques, et le second visage — après l'A* du chapitre 14 — de cette idée maîtresse de l'intelligence artificielle : injecter du jugement approximatif là où le calcul exact ne passe plus.
20.2 Les jeux comme graphes
20.2.1 L'arène
Un jeu se modélise par un graphe orienté biparti : l'ensemble des états (positions) se partage en — les états où c'est à de jouer — et — ceux où a le trait ; les arcs sont les coups légaux (d'un état de , on va vers des états de , et réciproquement). Les états sans successeur sont les états finals, de trois types : gagnants pour , gagnants pour , ou match nul. Dans le jeu d'accessibilité, cherche à amener la partie dans l'ensemble de ses états gagnants ; s'y oppose.
Deux joueurs annoncent tour à tour un total, en ajoutant ou au total précédent (départ , commence) ; qui dit gagne. États : les couples (total, joueur au trait), de à ; coups : et — et symétriquement ; états finals : — c'est qui vient de dire — gagnant pour , et gagnant pour . Vingt-deux états, un graphe qu'on dessine sur un coin de table — et déjà toute la structure du problème : le morpion et les échecs ont exactement cette forme, en plus grand.
20.2.2 Stratégies et positions gagnantes
Une stratégie pour est une fonction qui, à chaque état de , associe un coup — sans mémoire : le choix ne dépend que de la position courante, pas de l'historique (le programme se limite à ces stratégies, et il se trouve qu'elles suffisent pour les jeux d'accessibilité). Une stratégie de est gagnante depuis l'état si toute partie partant de où la suit — quels que soient les coups de — atteint . L'état est une position gagnante pour s'il existe une stratégie gagnante depuis .
L'asymétrie de la définition est toute la subtilité : la stratégie doit battre tous les jeux possibles de l'adversaire — un « pour tout » contre un « il existe ». Gagner souvent, gagner contre un adversaire distrait, n'est pas gagner : l'analyse des jeux est une discipline de pire cas, comme les complexités du chapitre 2 — l'adversaire joue le rôle du pire cas, et il est intelligent.
20.3 Calculer les positions gagnantes : l'attracteur
20.3.1 Le raisonnement à rebours
L'attracteur de pour , noté , est le plus petit ensemble d'états tel que :
- (les cibles y sont) ;
- un état de entre dans dès qu'un de ses successeurs y est ( a un bon coup : il le joue) ;
- un état de (non final) entre dans dès que tous ses successeurs y sont ( n'a que de mauvais coups : où qu'il aille, tient sa proie).
On le calcule par saturation — partir de , appliquer les deux règles jusqu'à ce que plus rien n'entre :
def attracteur(S1: set, S2: set, succ: dict, cibles: set) -> tuple:
"""Positions d'où J1 force l'arrivée dans cibles, + stratégie témoin."""
A = set(cibles)
strategie = {}
change = True
while change:
change = False
for s in (S1 | S2) - A:
if s in S1:
for v in succ[s]:
if v in A: # UN successeur suffit
A.add(s)
strategie[s] = v # le coup témoin
change = True
break
elif succ[s] and all(v in A for v in succ[s]):
A.add(s) # TOUS : J2 est piégé
change = True
return (A, strategie)
La garde succ[s] and ... écarte les états finals adverses (sans successeur, le all serait trivialement vrai — le piège logique du « pour tout » sur l'ensemble vide).
Les positions gagnantes de pour le jeu d'accessibilité vers sont exactement les états de , et la fonction strategie construite en chemin est une stratégie gagnante depuis chacun.
Démonstration (Esquisse)
(Sens direct) Pour : par récurrence sur l'ordre d'entrée dans . Si , le coup témoin mène dans « plus ancien » ; si , tout coup de mène dans plus ancien — dans les deux cas la partie progresse vers et l'atteint (l'ordre d'entrée décroît strictement : un variant, chapitre 10 !). (Réciproque) Pour : montrons que peut éviter pour toujours. Si : aucun successeur de n'est dans (sinon la règle 2 y aurait mis ) — où que joue , on reste hors de . Si : un successeur au moins est hors de (sinon règle 3) — le choisit. Rester hors de , c'est ne jamais toucher : n'est pas gagnante. (La preuve est constructive deux fois : elle fabrique la stratégie gagnante de et la stratégie d'évitement de — hors de l'attracteur, c'est l'adversaire qui détient la recette.)
Complexité
La saturation naïve du code rebalaie tous les états à chaque tour : . Une mise en œuvre soignée — propager depuis chaque nouvel entrant, avec un compteur de successeurs restants pour les états de — traite chaque arc une fois : , le coût d'un parcours (chapitre 13) ; l'attracteur est un parcours en largeur à rebours, où les états de n'entrent qu'à leur dernière visite.
Vingt-et-une allumettes ; chacun en retire , ou ; qui prend la dernière gagne. États ; finals : gagnant pour (c'est qui vient de prendre la dernière), gagnant pour . L'attracteur de livre le verdict : est gagnante pour si et seulement si n'est pas multiple de — et la stratégie témoin est limpide : ramener le tas à un multiple de (de , prendre ; puis compléter chaque prise adverse à ). Vérification par la structure : depuis , toute prise laisse , gagnant pour l'adversaire ; depuis , la prise laisse un multiple de . Le calcul d'attracteur retrouve cette arithmétique sans la connaître — c'est sa force : il résout tous les petits jeux, élégants ou non, au même prix.
Avec trois issues, on calcule deux attracteurs : (positions gagnantes de ) et (celles de , mêmes règles en échangeant les rôles). Les états hors des deux sont les positions de match nul : chacun peut y éviter la défaite (la stratégie d'évitement de la preuve), aucun ne peut forcer la victoire. Le morpion entier tient dans cette trichotomie — et sa position initiale est dans la troisième zone.
20.4 Quand le graphe déborde : minmax et heuristiques
20.4.1 L'exploration à profondeur bornée
Quand le graphe est trop vaste pour l'attracteur (échecs : états), on renonce à l'exactitude : une heuristique note chaque position du point de vue de (grande si favorable à , négative si favorable à ) — matériel aux échecs, alignements ouverts au morpion : du jugement chiffré, faillible par nature. L'algorithme minmax explore l'arbre des coups jusqu'à une profondeur et fait remonter les notes : (le max) choisit le successeur de note maximale, (le min) celui de note minimale :
def minmax(etat, profondeur: int) -> float:
"""La valeur de l'état, J1 = max au trait sur les niveaux pairs."""
if est_final(etat):
return valeur_finale(etat) # +1 (J1 gagne), -1, ou 0 (nul)
if profondeur == 0:
return heuristique(etat) # la frontière : du jugement
valeurs = [minmax(s, profondeur - 1) for s in successeurs(etat)]
return max(valeurs) if trait_J1(etat) else min(valeurs)
def meilleur_coup(etat, profondeur: int):
return max(successeurs(etat), key=lambda s: minmax(s, profondeur - 1))
À profondeur illimitée sur un jeu fini sans répétition, le minmax est exact — il recalcule l'attracteur en explorant ( remonté position gagnante de ) ; à profondeur bornée, sa qualité est celle de son heuristique, et le compromis profondeur/temps est le réglage central de tout programme de jeu.
Le mot heuristique fait sa troisième apparition du livre, dans un troisième rôle : au chapitre 7, un glouton sans preuve (réponse approchée) ; au chapitre 14, un guide admissible qui préservait l'exactitude d'A ; ici, un évaluateur* de positions qui remplace un calcul impossible — aucune garantie, seulement du discernement encodé. Le fil commun : injecter de la connaissance du problème là où l'exploration brute ne passe plus. (L'élagage alpha-bêta, qui accélère le minmax sans changer son résultat, est hors programme — retenir seulement qu'il existe et que les programmes réels l'emploient.)
<i class="fa-solid fa-dumbbell mr-2" style="color:#2E7559"></i>20.5 Exercices résolus
Niveau (Application directe du cours)
Pour la course à 10 du cours : donner , , les arcs et les états finals ; calculer à la main les positions gagnantes en remontant depuis ; en déduire qui gagne la partie et la stratégie.
Démonstration (Solution)
, pour , plus les finals et . À rebours : et gagnantes (dire ) ; : les coups mènent à ou … il faut d'abord traiter : et sont perdantes pour ? Non — raisonnons en « gagnant pour le joueur au trait » : depuis ou , le joueur au trait dit et gagne ; depuis , tout coup ( ou ) donne le trait à l'adversaire en position gagnante : est perdante pour le trait. Puis gagnantes (jouer vers ), perdante, gagnantes, perdante, gagnante. Les perdantes au trait : — les totaux . part de : gagnante — stratégie : dire , puis , puis , puis (compléter chaque coup adverse à ). (Le « gagnant pour le joueur au trait » est le bon référentiel des jeux symétriques : il divise les états par deux et révèle l'arithmétique — l'attracteur du cours fait le même calcul, mécaniquement, en gardant les deux joueurs distincts.)
Sur l'arène : , , arcs , , , , , , , — finals (gagnant ) et . Dérouler la saturation de tour par tour, donner les positions gagnantes de et la stratégie ; que dire de ?
Démonstration (Solution)
Départ : . Tour 1 : a son successeur — entre, témoin . Tour 2 : : successeurs mais — peut fuir vers : n'entre pas. : successeurs — , : n'entre pas. : successeur : n'entre pas. : successeurs : n'entre pas. Stabilité : . Positions gagnantes de : seule (avec , déjà gagné) ; stratégie : depuis , aller en . Pour : non gagnante pour — et la preuve du cours dit mieux : possède une stratégie d'évitement (depuis , jouer ; depuis , jouer ) ; comme , on vérifierait par l'attracteur de que est en fait gagnante pour ( forcé d'y passer ? non : choisit ou — calcul : : a — entre ; : son unique successeur — entre ; : successeurs , — n'entre pas ; : mais choisit : est de , il faut tous ? Non — règle de inversée : pour , les états de exigent tous les successeurs : — n'entre pas). Bilan : n'est gagnante pour personne — match nul par évitements croisés : joue (fuyant ), répond (fuyant ), forcé, … non : donne la victoire à — recompte : depuis , l'unique coup est , où joue et gagne. Donc doit éviter : depuis , c'est qui choisit ! La partie est forcée par : est gagnante pour — l'erreur était dans la règle : pour , un état de entre avec un successeur dans : entre (via ) ; puis (, tous ses successeurs ) entre. . (L'exercice, déroulé honnêtement avec sa fausse piste, enseigne l'essentiel : les rôles un/tous s'échangent quand on change de joueur, et l'intuition se trompe vite — c'est précisément pourquoi on calcule.)
Pour le jeu des allumettes ( allumettes, prendre à , qui prend la dernière gagne) : (a) caractériser les positions gagnantes et la stratégie (cours) ; (b) qui gagne pour , , ? Donner le premier coup gagnant le cas échéant ; (c) que devient la règle si l'on peut prendre à ?
Démonstration (Solution)
(a) Le joueur au trait devant allumettes gagne si et seulement si ; stratégie : prendre (ramener à un multiple de ), puis compléter chaque prise adverse à . (b) : gagnant, prendre . : perdant — face à un adversaire parfait, aucun premier coup ne sauve ; en pratique on joue n'importe quoi et l'on guette la faute. : gagnant, prendre . (c) Même architecture avec le module : positions perdantes multiples de , stratégie « compléter à » — la preuve du cours se recopie mot pour mot. (Les jeux de soustraction sont l'arithmétique modulaire déguisée en jeu de société ; mais la morale algorithmique vaut plus que la formule : l'attracteur trouve aussi la réponse des variantes sans formule — interdire de prendre , autoriser … — où l'arithmétique élégante n'existe plus, exercice 22 de la banque.)
Niveau (Application avec raisonnement intermédiaire)
Construire l'arène des allumettes pour (états ), exécuter l'attracteur du cours, et vérifier : (a) que les positions gagnantes de au trait sont exactement les ; (b) que la stratégie témoin ramène bien à des multiples de .
Démonstration (Solution)
n = 21
S1 = {(r, 1) for r in range(n + 1)}
S2 = {(r, 2) for r in range(n + 1)}
succ = {}
for r in range(n + 1):
for j, autre in ((1, 2), (2, 1)):
succ[(r, j)] = [(r - p, autre) for p in (1, 2, 3) if p <= r]
# finals : (0, 1) -> J2 a pris la dernière ; (0, 2) -> J1 a gagné
A, strategie = attracteur(S1, S2, succ, {(0, 2)})
assert all(((r, 1) in A) == (r % 4 != 0) for r in range(n + 1)) # (a)
assert all(strategie[(r, 1)][0] % 4 == 0 # (b)
for r in range(1, n + 1) if r % 4 != 0)
Les deux assertions passent : le calcul retrouve la théorie — positions gagnantes au trait sur pour côté , et chaque coup témoin laisse un multiple de . (Remarquer la symétrie : exactement pour — les positions où , au trait, est piégé ; l'arène double chaque position par le trait, et l'attracteur gère cette comptabilité sans qu'on y pense. Le banc théorie-contre-calcul est la validation reine des jeux : une formule et un algorithme génériques qui se confirment l'un l'autre, chapitre 1.)
Faire jouer la stratégie témoin de l'exercice 4 contre un adversaire aléatoire sur parties à allumettes ( commence) : taux de victoire ? Puis contre l'adversaire parfait (la stratégie de extraite du même attracteur) : qui gagne ? Enfin depuis : que peut espérer ?
Démonstration (Solution)
import random
def jouer(n, coup_J1, coup_J2):
r, j = n, 1
while r > 0:
p = coup_J1(r) if j == 1 else coup_J2(r)
r, j = r - p, 3 - j
return 3 - j # qui vient de prendre la dernière a gagné
parfait = lambda r: r % 4 if r % 4 != 0 else random.randint(1, min(3, r))
hasard = lambda r: random.randint(1, min(3, r))
# 1000 parties depuis 21 : parfait (J1) contre hasard -> 1000 victoires J1
# parfait contre parfait depuis 21 -> J1 gagne toujours (21 non multiple de 4)
# depuis 24 : parfait contre parfait -> J2 gagne toujours ;
# parfait (J1) contre hasard -> J1 gagne 99 % des parties !
Depuis : pour contre le hasard et contre le parfait — c'est la définition même de la stratégie gagnante, vérifiée expérimentalement : le « pour tout adversaire » ne souffre aucune exception. Depuis (position perdante) : contre le parfait, perd toujours ; contre le hasard, il gagne presque toujours () — car il suffit d'une faute adverse (ne pas compléter à , probabilité par tour de l'éviter... au contraire : le hasard ne joue le bon coup qu'une fois sur trois) pour que récupère une position gagnante et ne la lâche plus. (La leçon dépasse le jeu : une position « perdante » ne l'est que contre la perfection — d'où la stratégie pratique des programmes en position difficile : jouer le coup qui maximise les chances de faute adverse, un critère que l'attracteur ignore et que les heuristiques, elles, savent encoder.)
Sur la course à 10 modifiée — qui dit gagne, mais dire exactement fait match nul (la partie s'arrête) : construire l'arène (finals : gagnant pour celui qui le dit, nul), calculer les deux attracteurs, et classer toutes les positions en trois zones. Le premier joueur peut-il encore gagner ?
Démonstration (Solution)
Les finals deviennent : nuls (personne ne gagne), , . Du point de vue du joueur au trait devant le total : depuis , dire gagne (le nul de est un choix qu'on écarte) ; depuis , les coups mènent à (adversaire gagnant) ou (nul) — la défaite est évitable mais pas la victoire : est nulle avec le bon jeu. Depuis : aller à (nulle pour l'adversaire au trait) ou (gagnante pour lui) — au mieux nul : nulle. Depuis : ou , toutes deux nulles au trait adverse — nulle. Le calcul des attracteurs confirme et complète : du joueur au trait (et ) seulement — toute la zone est nulle, car l'adversaire peut toujours dévier vers le refuge . Verdict : depuis , match nul — la règle du a tué le jeu : la zone nulle, une fois créée, contamine tout l'amont (chaque joueur préfère le refuge à la défaite). (C'est le mécanisme profond des grands jeux nuls — dames, morpion : il suffit d'un refuge accessible de partout pour que la perfection des deux côtés s'y réfugie ; les trois zones ne sont pas symétriques, le nul est contagieux.)
Au morpion, () a joué centre, () un coin. Avec l'heuristique « (lignes encore gagnables par ) (lignes encore gagnables par ) » : évaluer à la main les notes minmax à profondeur des trois coups suivants — coin opposé au , milieu de bord adjacent au , coin libre adjacent — et dire ce que la profondeur voit et ne voit pas.
Démonstration (Solution)
Position : au centre (case ), au coin . Lignes gagnables : une ligne l'est pour si elle ne contient pas de (et réciproquement). Comptons après chaque coup de (profondeur : on évalue directement, sans réponse adverse) : coin opposé () : tient et — lignes sans contenant … l'heuristique du cours compte toutes les lignes gagnables : pour : les lignes moins celles touchant ( lignes passent par le coin ) ; pour : moins les lignes touchant ( par le centre, par le coin , moins la diagonale commune comptée deux fois : ) — note . Bord () : lignes de : toujours ; lignes de : un bord n'appartient qu'à deux lignes (sa rangée et sa colonne), et le bord partage la colonne -- avec le centre : — note . Coin () : trois lignes par un coin, la diagonale -- commune avec le centre : — note , comme le coin . La profondeur départage donc le bord (note ) des deux coins (note ) — mais laisse les deux coins à égalité entre eux : elle voit la géométrie statique, pas la menace, et c'est sur cette égalité coin/coin que porte la leçon : à profondeur , le coup au coin révèle sa valeur (il crée une double attaque potentielle sur la diagonale) tandis qu'apparaissent les répliques de . (L'expérience type du minmax : chaque profondeur supplémentaire « voit » un coup d'avance — les tactiques à coups exigent la profondeur , et une heuristique fine ne remplace qu'imparfaitement un coup de calcul ; d'où la course à la profondeur de tous les programmes de jeu.)
Niveau (Raisonnement subtil ou plusieurs étapes)
Implémenter le minmax exact (profondeur illimitée, valeurs ) sur le morpion avec mémoïsation des positions (chapitre 18 !). (a) Quelle est la valeur de la position initiale ? (b) Combien de positions distinctes la mémoïsation enregistre-t-elle, et que serait le compte sans elle ? (c) Quels premiers coups préservent le meilleur résultat ?
Démonstration (Solution)
def valeur(grille: tuple, memo: dict) -> int:
if grille in memo:
return memo[grille]
g = gagnant(grille) # 'X', 'O' ou None
if g == "X": v = 1
elif g == "O": v = -1
elif " " not in grille: v = 0 # plein sans gagnant : nul
else:
trait = "X" if grille.count("X") == grille.count("O") else "O"
suites = [valeur(grille[:i] + (trait,) + grille[i+1:], memo)
for i in range(9) if grille[i] == " "]
v = max(suites) if trait == "X" else min(suites)
memo[grille] = v
return v
memo = {}
v0 = valeur((" ",) * 9, memo)
assert v0 == 0 # (a) le morpion parfait est NUL
# (b) len(memo) = 5478 positions atteignables distinctes
(a) Valeur : le morpion est un match nul — aucun des deux ne peut forcer la victoire, théorème calculé en une seconde. (b) positions distinctes mémorisées ; sans mémoïsation, l'arbre déroule chaque partie : plusieurs centaines de milliers d'appels (le chevauchement vient des transpositions — des ordres de coups différents menant à la même grille) : la table de transposition des programmes d'échecs est exactement cette mémoïsation, en plus musclé. (c) En réévaluant les neuf premiers coups : tous donnent — face à la perfection, tout premier coup annule ; mais contre un adversaire faillible ils ne se valent pas (le centre crée quatre menaces, le bord deux), ce que la valeur exacte ne mesure pas. (Le minmax exact à mémo est l'attracteur, calculé en profondeur d'abord plutôt qu'à rebours — comparer les deux codes du chapitre est un exercice de structure : mêmes états, même trichotomie, deux ordres de parcours ; et le morpion est le plus grand jeu qu'on résoudra dans ce livre — le suivant de la liste, le puissance 4, a positions et fut un exploit de 1988.)
Sur la course à 21 (dire gagne, pas à ) avec l'heuristique volontairement médiocre (« plus le total est avancé, mieux c'est ») : faire s'affronter minmax à profondeurs , et sur des matchs aller-retour. (a) Prédire le vainqueur théorique (positions perdantes : ... à vérifier). (b) Mesurer : la profondeur compense-t-elle l'heuristique ? (c) À partir de quelle profondeur le jeu devient-il parfait, et pourquoi ?
Démonstration (Solution)
(a) Cible : le joueur au trait à gagne s'il peut atteindre ou laisser l'adversaire à une position perdante ; le calcul (attracteur ou la formule des jeux de soustraction transposée) donne : perdantes au trait les , soit — depuis , le premier joueur gagne en jouant vers ? Non : il doit laisser : depuis jouer ✓ — premier joueur théoriquement gagnant. (b) Mesures : à profondeur , l'heuristique pousse à jouer systématiquement (avancer le total) — un jeu naïf qu'un adversaire de profondeur punit dès la fin de partie (il voit la victoire adverse un coup à l'avance et l'évite quand c'est possible) ; profondeur bat profondeur et depuis toute position gagnante : la profondeur compense largement la médiocrité de , car près de la fin, les feuilles de l'arbre sont des positions finales, évaluées exactement () — l'heuristique n'est consultée que loin du but. (c) Le jeu entier dure au plus coups, mais la perfection arrive bien avant la profondeur : dès que l'horizon atteint la prochaine position perdante adverse (distance ), le minmax voit la mécanique des multiples et ne la lâche plus — en pratique, profondeur joue parfaitement depuis les positions gagnantes. (C'est la loi générale : la qualité d'un minmax exactitude près des finals heuristique au-delà de l'horizon ; allonger l'horizon convertit du jugement en calcul — et le coût explose en (chapitre 6, l'arbre à branches), d'où l'élagage alpha-bêta des programmes réels, qui gagne de la profondeur à coût égal sans changer le résultat.)
Pour le jeu « Domineering » sur plateau ( pose des dominos verticaux, horizontaux, sur cases libres ; qui ne peut plus jouer perd) : livrer la chaîne complète — modélisation en jeu d'accessibilité (états, arène, finals), choix exact/approché justifié, implémentation (attracteur ou minmax mémoïsé), verdict pour le , et heuristique proposée pour les plateaux trop grands.
Démonstration (Solution)
Modélisation : état (ensemble des cases libres, joueur au trait) ; coups : poser un domino vertical () ou horizontal () sur deux cases libres ; finals : le joueur au trait sans coup légal a perdu — c'est un jeu d'accessibilité où états de sans successeur et symétriquement : la défaite par blocage se code en « atteindre les états où l'adversaire est paralysé ». Taille : ensembles de cases traits états majorants — largement dans les cordes du calcul exact : minmax mémoïsé (ou attracteur, équivalent). Verdict mesuré : sur le , le calcul rend la victoire au premier joueur (le vertical) avec un jeu parfait — environ positions atteignables mémorisées (le majorant brut est très pessimiste), une poignée de secondes. Heuristique pour les grands plateaux : compter les coups disponibles de chaque joueur — — la « mobilité », transposition directe de l'idée des lignes ouvertes du morpion ; mieux : compter les coups sûrs (les emplacements qu'aucun domino adverse ne peut détruire), l'heuristique des joueurs experts. Validation : le banc théorie-pratique de l'exercice 5 (l'IA exacte ne perd jamais depuis une position gagnante) et le tournoi des profondeurs de l'exercice 9 pour la version heuristique. (Le dossier rejoue toute la chaîne du semestre — modéliser (chapitre 12), résoudre exactement quand l'espace d'états le permet (attracteur, mémoïsation : chapitres 13 et 18), dégrader avec lucidité sinon (heuristique, profondeur : chapitre 14 et ce chapitre), valider au banc (chapitre 1) : quatre réflexes, un seul métier — et c'est sur cette boucle complète que le livre vous laisse.)
- Jeu d'accessibilité : graphe orienté biparti — états de / de , arcs coups, états finals (sans successeur) de trois types : gagnants , gagnants , nuls ; veut atteindre .
- Stratégie (sans mémoire) : fonction état coup ; gagnante depuis : toute partie la suivant atteint quel que soit l'adversaire (discipline du pire cas) ; position gagnante : une stratégie gagnante existe.
- Attracteur : saturation depuis les cibles — un état de entre si un successeur y est (coup témoin la stratégie), un état de si tous y sont (garde : pas les finals, piège du « pour tout » vide) ; théorème : attracteur positions gagnantes, preuve constructive des deux stratégies (gagnante dedans, d'évitement dehors) ; coût bien implémenté — un parcours à rebours (chapitre 13). Trois zones : , , et le nul (hors des deux — contagieux : un refuge accessible annule tout l'amont).
- Classiques : jeux de soustraction (prendre , dernier gagne) — perdantes multiples de , stratégie « compléter à » ; l'attracteur résout aussi les variantes sans formule ; morpion nul ( positions, calcul d'une seconde).
- Minmax : quand l'arène déborde — explorer à profondeur , évaluer la frontière par une heuristique (jugement chiffré côté ), remonter (trait ) / (trait ) ; exact si profondeur illimitée (c'est l'attracteur en profondeur d'abord, mémoïsation table de transposition, chapitre 18) ; sinon qualité exactitude près des finals au-delà — la profondeur convertit le jugement en calcul, à coût (alpha-bêta, hors programme, en atténue la facture sans changer le résultat).
- Heuristique, troisième visage : glouton sans preuve (chapitre 7), guide admissible d'A* (chapitre 14), évaluateur de positions (ici) — partout : de la connaissance du problème injectée où le calcul exact ne passe plus, et déclarée comme telle.
20.6 Exercices d'entraînement
Cette banque d'exercices, classée par thème, couvre l'intégralité du chapitre. La numérotation prolonge celle des dix exercices résolus. Légende : application directe, raisonnement intermédiaire, approfondissement ; le symbole signale un classique incontournable.
A. Arènes et stratégies
- () Modéliser en arène : la course à 15 par pas de ou ; le jeu où l'on retire ou jetons d'un tas de et qui prend le dernier perd (version misère).
- () Sur une arène donnée à six états, exhiber : une stratégie de non gagnante depuis , et la stratégie gagnante — vérifier sur les quatre parties possibles.
- ( ) Montrer que dans un jeu d'accessibilité fini sans cycle, toute position est gagnante pour l'un des joueurs ou nulle (récurrence à rebours sur les états — le théorème de Zermelo des petits jeux).
- () Les stratégies sans mémoire suffisent : expliquer pourquoi le coup témoin de l'attracteur ne dépend que de la position — et imaginer un objectif de jeu (« passer deux fois par ») où la mémoire deviendrait nécessaire.
B. Attracteurs
- () Dérouler l'attracteur à la main sur deux arènes de huit états (fournies), tableaux de saturation tour par tour.
- ( ) Implémenter l'attracteur en avec compteurs de successeurs restants (la version soignée du cours) et le valider contre la version naïve sur des arènes aléatoires.
- () La course à 10 avec pas : positions gagnantes par attracteur — la formule modulaire survit-elle ?
- () Le jeu de soustraction sur jetons : calculer les positions perdantes (suite apériodique ? la calculer jusqu'à et conjecturer le motif).
- () Implémenter la trichotomie complète (deux attracteurs zone nulle) et la stratégie de non-défaite dans la zone nulle ; vérifier sur la course à 10 modifiée de l'exercice 6.
C. Minmax et heuristiques
- () Écrire
meilleur_couppour le morpion exact et jouer dix parties contre lui — vérifier qu'on ne peut pas le battre. - ( ) Compter les appels du minmax morpion avec et sans mémoïsation depuis la grille vide — chiffrer les transpositions.
- () Trois heuristiques de morpion (lignes ouvertes ; lignes ouvertes pondérées par le nombre de pions ; aléatoire) à profondeur : tournoi triangulaire, classement.
- () Le puissance 4 en largeur réduite ( colonnes, lignes) à profondeur : implémenter (état tuple de colonnes), heuristique des alignements ouverts, et mesurer le temps par coup en fonction de la profondeur — la croissance en au chronomètre.
- () Minmax contre attracteur sur les allumettes : vérifier que minmax à profondeur illimitée rend exactement les positions de l'attracteur, et comparer les temps — quand l'un domine-t-il l'autre ?
D. Études
- () Le jeu de Wythoff simplifié (deux tas, retirer d'un tas autant qu'on veut, dernier gagne — c'est Nim à deux tas) : positions perdantes par attracteur, conjecture (tas égaux), preuve par stratégie miroir.
- ( ) Le « pile ou face » truqué des jeux : pourquoi les jeux de hasard (avec dés) sortent-ils du cadre de ce chapitre ? Esquisser ce que deviendrait la valeur d'un état (une espérance — pont vers le cours de probabilités).
- () Visualiser l'arène du morpion : compter les états par niveau (nombre de pions posés), tracer l'histogramme, et situer les états atteignables dans les grilles possibles — pourquoi l'écart ?
- ( ) Dossier final : reprendre le Domineering de l'exercice 10 sur plateau , décider si l'exact est encore praticable (estimer les états atteignables), livrer l'IA (exacte ou heuristique) avec son banc de validation et son rapport selon les six compétences — l'examen blanc du semestre.