Approche probabiliste


Dans les jeux déterministes où le nombre de coups possibles de chaque joueur est très faible et diminue après chaque coup joué (comme le morpion par exemple), il est possible de développer entièrement l'arbre de jeu de chaque situation. On peut donc connaitre, à chaque moment de la partie, les coups menant avec certitude à la victoire, la défaite ou à une partie nulle.

Pour les jeux plus complexes, comme les échecs, cela reste toujours possible en théorie (chaque situation reste décidable comme nous l'avons montré) , mais en pratique cela demanderait un temps de calcul tellement énorme que l'on peut dire que c'est totalement irréalisable.

Il est pourtant possible de réaliser des programmes de jeu très efficaces dans des jeux complexes, comme le prouve les performances actuelles des ordinateurs au jeu d'échecs.

Pour y arriver, il faut accepter l'incertitude. On ne cherche plus systématiquement à savoir quel est le coup qui permet de gagner à coup sur, mais plus modestement, à trouver le coup qui donne le plus de chance à mener à la victoire.

Nous allons donc prendre à présent une approche probabiliste. Comme nous ne pouvons pas prévoir exactement le déroulement optimal d'une partie à partir d'une situation de jeu donnée, nous allons considérer qu'il s'agit d'une expérience aléatoire à trois issues (victoire, partie nulle ou défaite). Nous allons définir l'espérance de gain d'une situation et chercher le coup menant à la plus grande espérance de gain.

D'autre part, nous allons renoncer à développer entièrement l'arbre de jeu de chaque situation analysée. Au lieu de cela, nous nous contenterons de le développer jusqu'à une certaine profondeur maximale. Autrement dit, le programme va "réfléchir" un certain nombre de coups à l'avance. Pas plus de quatre coups à l'avance par exemple.

Le programme du super morpion est basé sur cette approche probabiliste. Lorsque vous l'exécutez en mode explicatif, un tableau s'affiche au dessus du jeu:

Pmax-NAE-Hr-Super-Morpion.jpg, 15kB

La profondeur maximale de recherche est indiquée dans la colonne Pmax. Vous constaterez qu'elle est variable. Elle augmente lorsque le nombre de coups possibles (cases vides) diminue.

Le nombre d'alternatives explorées est indiqué dans la colonne NAE

La colonne Hr quand à elle indique la valeur heuristique de la situation de jeu. Nous reviendrons la dessus plus loin. Ce nombre donne une indication sur l'espérance de gain du joueur. Une valeur positive (respectivement négative) signifie en principe que les chances de gain de l'utilisateur sont plus importantes (respectivement plus faibles) que celles de l'ordinateur. Pour une valeur nulle, les chances sont égales.

En cochant la case Prouver, vous pouvez obtenir la valeur heuristique d'un coup particulier en cliquant sur la case correspondante. Il s'agit plus précisemment d'une évaluation de la valeur heuristique de la situation pour l'ordinateur, lorsque l'utilisateur aura joué ce coup.

Vous constaterez ainsi que les cases indiquées en jaunes sont celles qui minimise la valeur heuristique de la situation de jeu de l'ordinateur.

Tout ceci est basé sur un algorithme récursif connu appelé Négamax.

Dans la partie exercices, vous trouverez un exercice sur le jeu Puissance4. Dans cet exercice, vous aurez à implémenter l'algorithme Negamax en vous basant sur la définition de la valeur d'une situation telle qu'elle est définie plus loin.

Pour faire cet excercice, vous n'aurez pas forcement besoin de lire la section très mathématique démontrant l'optimatilité de Négamax.

Espérance de gain d'une situation

Soit S une situation de jeu et J le joueur ayant le trait dans cette situation.

On peut associer à S une variable aléatoire G à trois valeurs: 1, 0 ou -1.

G vaut 1 (respectivement 0, -1) si le jeu se termine par une victoire de J (respectivement partie nulle, défaite de J).

Avec cette modélisation, l'espérance de G est donc un nombre situé entre -1 et 1. Plus précisément

  E(G)= -1 × P(G=-1) + 0 × P(G=0) + 1 × P(G=1) = P(G=1) - P(G=-1)

L'espérance de gain est donc la différence entre la probabilité de victoire de J et la probabilité de défaite de J.

Pour ne pas trop alourdir les notations, nous définirons l'espérance de gain de la situation S, notée E(S) comme l'espérance de gain de G.

Si S n'est pas une feuille de l'arbre de jeu, elle possède M fils:

Dans les situations F1,F1, ..., FM, le trait est à l'adversaire de J.

Supposons que J connaisse les espérances de gain E(F1), E(F1), ..., E(FM).

Dans ce cas, il choisira de jouer le coup donnant une espérance de gain minimale à son adversaire. Soit FK, un des fils réalisant l'espérance de gain minimale. Soit vK, la probabilité de victoire de l'adversaire dans cette situation et soit dK, sa probabilité de défaite. On a

E(FK) = vK - dK

Mais dans cette même situation FK, la probabilité de victoire de J est dK et sa probabilité de défaite est vK. Son espérance de gain est donc

dK - vK = -E(FK)

On en déduit que si J choisit bien le coup donnant une espérance de gain minimale à son adversaire, alors son espérance de gain dans la situation S est l'opposée du minimum des espérances de F1,F1, ..., FM:

E(S) = - Min ( E(F1), E(F2), ..., E(FM) )

En développant un arbre de jeu tronqué d'une situation, nous pouvons donc calculer récursivement son espérance de gain à condition que les espérances de gain des feuilles de l'arbre soient connues.

La figure suivante illustre ceci pour un arbre de profondeur 2. Le ou les meilleurs coups à jouer son indiqués en vert.

Si nous pouvions connaitre l'espérance de gain des feuilles nous aurions donc un moyen de trouver le meilleur coup à jouer dans n'importe quelle situation.

Malheureusement, le calcul théorique de l'espérance de gain d'une situation de jeu est un problème extrèmement complexe (pour ne pas dire impossible à résoudre !).

Valeur d'une situation

Pour contourner cette difficulté, nous allons associer une valeur numérique à une situation quelconque de l'arbre de jeu en supposant que l'espérance de gain dépende d'une manière optimale de cette valeur (nous verrons plus loin comment).

Commencons par définir la valeur d'une feuille de l'arbre. Dans un arbre de jeu tronqué, il y a deux catégories de feuilles: celles qui représentent des situations de fin de partie. Ce sont les feuilles terminales. Les autres résultent de la troncature de l'arbre de jeu. Elles représentent les situations où la partie n'est pas finie et telles que la profondeur maximale de recherche a été atteinte.

Pour une feuille terminale, il y a deux possibilités :

Pour une feuille non terminale, on fera un calcul. Le résultat de ce calcul est la valeur heuristique de la situation. On s'arrange pour qu'elle soit toujours strictement comprise entre -Vmax et Vmax. Nous la noterons VH.

La manière de calculer cette valeur heuristique est totalement dépendante du type de jeu. Il n'est donc pas possible ici d'en donner une définition générale. Pour vous donner une idée, nous donnerons plus loin deux exemples d'heuristiques: un exemple pour le jeu d'échec, puis un exemple pour le super morpion.

Voyons à présent comment définir la valeur d'un noeud interne. Un noeud interne possède M fils.

Preuve-Decid-Par-Recurrence.jpg, 25kB

La valeur de la situation S, noté V(S) est définie par:

V(S) = - Min ( V(F1), V(F2), ..., V(FM) )

V(F1), V(F2), ..., V(FM) sont les valeurs respectives des situations F1, F2, ..., FM.

Notez que si la valeur d'un des fils est -Vmax, alors celle de S sera Vmax. Cela représente la situation où J possède un coup gagnant (le coup menant à ce fils). Sa victoire est donc certaine.

Cette manière de définir la valeur d'une situation à partir de ses fils conduit à l'algorithme connu sous le nom de Négamax qui est lui même une variante de l'algorithme du Minimax de Von Neumann.

Pour comprendre l'origine du nom Négamax, il faut voir que l'opposé du minimum d'un ensemble de nombre est égale au maximum des opposés de ces nombres. Donc, on aurait très bien pu définir V(S) par:

V(S) = Max ( -V(F1), -V(F2), ..., -V(FM) )

Une remarque importante: lorsque toutes les feuilles de l'arbre de jeu tronqué sont terminales et de valeur non nulles (donc Vmax ou -Vmax), Négamax peut prédire avec certitude la défaite ou la victoire du joueur ayant le trait.

La valeur zéro ne donne pas d'information certaine, car on ne peut pas distinguer un zéro provenant d'une valeur heuristique nulle d'un zéro provenant d'une situation de partie nulle.

Optimalité de l'algorithme Negamax

Avec cette définition de la valeur d'une situation, on peut montrer que si la valeur heuristique d'une situation vérifie les hypothèses suivantes :

alors choisir le coup conduisant à une situation de valeur minimale pour l'adversaire revient exactement au même que choisir le coup conduisant à une espérance de gain minimale pour l'adversaire.

En voici, la preuve:

Soit S un noeud interne de l'arbre de jeu et ses fils F1,F1, ..., FM.

Il s'agit de démontrer que l'espérance de gain d'un fils de valeur minimale est forcément minimale.

Soit FK un tel fils. On a

V(FK) = Min ( V(F1), V(F2), ..., V(FM) )

Il faut montrer que cela implique

E(FK) = Min ( E(F1), E(F2), ..., E(FM) )

La preuve est basée sur l'existence d'une fonction φ qui associe une espérance à toute valeur d'une situation de jeu.

Soit H l'ensemble des valeurs heuristiques de toutes les situations de jeu possibles. Nous pouvons définir φ sur H ∪ {-Vmax; Vmax} à valeurs dans [-1;1] de la manière suivante:

Notez que d'après la manière dont nous avons définit l'espérance de gain d'une situation φ(v) est forcément dans l'intervalle [-1;1].

Nous allons à présent montrer que la fonction φ, vérifie les propriétés suivantes:

Preuve que φ(0)=0

D'après l'hypothèse (H4), il existe une situation de jeu S0 telle que VH(S0)=0. On a donc VH(S0) = - VH(S0).

D'après l'hypothèse (H3), cela implique E(S0) = - E(S0) et donc E(S0)=0. Donc, d'après la définition de φ, φ(0)=0.

Preuve que φ est croissante

Soit v1, v2 deux éléments de H ∪ {-Vmax; Vmax} tels que v1 ≤ v2. Montrons que l'on a nécessairement φ(v1) ≤ φ(v2).

Ici, nous allons distinguer quatre cas:

  1. v1=-Vmax et v2=Vmax
    Par définition φ(-Vmax)=-1 et φ(Vmax)=1. On a donc bien
    φ(v1) ≤ φ(v2).
  2. v1=-Vmax et v2 ∈ H
    Comme φ(-Vmax)=-1 et φ(v2) ∈ [-1;1], on a forcément φ(v1) ≤ φ(v2).
  3. v1 ∈ H et v2=Vmax
    Comme φ(v1) ∈ [-1;1] et φ(Vmax)=1 et , on a forcément φ(v1) ≤ φ(v2).
  4. v1 ∈ H et v2 ∈ H
    Dans ce cas, il existe une situation de jeu S1 telle que VH(S1)= v1
    et une situation de jeu S2 telle que VH(S2)= v2.
    Donc par la définition de la fonction φ on a

    φ(v1) = E(S1) et φ(v2) = E(S2).

    Donc v1 ≤ v2 équivaut à VH(S1) ≤ VH(S2)
    Mais d'après l'hypothèse (H1), ceci implique E(S1) ≤ E(S2)
    et par conséquent φ(v1) ≤ φ(v2)
Preuve que φ est impaire

Soit v1 et v2 deux éléments de H ∪ {-Vmax; Vmax}, tels que v1 = -v2. Montrons que φ(v1) = -φ(v2).

On a trois possibilités:

  1. v1=-Vmax et v2=Vmax
    Par définition, φ(v1)=-1 et φ(v2)=1. On a donc bien φ(v1) = -φ(v2)
  2. v2=-Vmax et v1=Vmax
    Par définition, φ(v2)=-1 et φ(v1)=1. On a donc bien φ(v1) = -φ(v2)
  3. v1 ∈ H et v2 ∈ H
    Dans ce cas, il existe une situation de jeu S1 telle que VH(S1)= v1
    et une situation de jeu S2 telle que VH(S2)= v2.
    Donc v1 = -v2 équivaut à VH(S1)= - VH(S2). D'après (H3), cela implique
    E(S1) = - E(S2) et par conséquent φ(v1) = -φ(v2)
Preuve de la propriété P4

Il s'agit de montrer que φ(V(S))=E(S) , pour toute situation de jeu S d'un arbre de jeu.

Nous allons démontrer cette propriété par récurrence.

Initialisation: montrons que la la propriété est vraie lorsque S est une feuille de l'arbre de jeu.

Si la feuille est terminale sa valeur est -Vmax ou 0. Sinon, c'est une valeur de H différente de 0 et de -Vmax. La valeur Vmax, n'est pas possible.

Nous distinguons ici trois cas:

  1. V(S)=-Vmax: d'après la définition de la valeur d'une situation, cela signifie que le joueur ayant le trait a perdu. On a donc E(S)=-1, qui est bien égal à φ(V(S)).
  2. V(S)=0:

    • Si S est terminale, on a une situation de partie nulle et dans ce cas E(S)=0. On a donc bien φ(V(S)) = E(S).
    • Si S n'est pas terminale, on a VH(S)=0. On a donc VH(S)= -VH(S) D'après l'hypothèse (H3), cela implique E(S)=-E(S) et par conséquent E(S)=0. Donc φ(V(S)) = E(S).

  3. V(S) ∈ H et V(S)≠0: dans ce cas, V(S)=VH(S) et par définition de φ, φ(V(S)) = E(S).

A présent, montrons que si P4 est vraie pour toute situation dont l'arbre de jeu est de profondeur inférieure où égale à N, alors elle est nécessairement vraie pour toute situation dont l'arbre de jeu est de profondeur inférieure où égale à N+1.

Soit S, une situation dont l'arbre de jeu est de profondeur N+1 (N ≥ 0). S possède M fils dont les arbres de jeu sont de profondeur inférieure ou égale à N.

Preuve-Decid-Par-Recurrence.jpg, 25kB

Par définition de la valeur d'une situation:

V(S) = -Min ( V(F1), V(F2), ..., V(FM) )

Par hypothèse de récurrence φ(V(Fi)) = E(Fi) pour i = 1,2,...,M.

D'autre part, E(S) = -Min ( E(F1), E(F2), ..., E(FM) ) et donc
E(S) = -Min ( φ(V(F1)), φ(V(F2)), ..., φ(V(FM)) ).

Mais comme φ est croissante

Min ( φ(V(F1)), φ(V(F2)), ..., φ(V(FM)) ) = φ(Min(V(F1),V(F2),..., V(FM)))

Donc

E(S)= -φ(Min(V(F1),V(F2),..., V(FM)))

Comme φ est impaire

E(S)=
-φ(Min(V(F1),V(F2),..., V(FM))) = φ(-Min(V(F1),V(F2),..., V(FM)))
= φ(V(S))

Revenons à présent à notre objectif initial, qui était de prouver l'implication

V(FK)=Min(V(F1), V(F2), ..., V(FM))E(FK)=Min(E(F1), E(F2), ..., E(FM))

Nous partons de

V(FK)=Min(V(F1), V(F2), ..., V(FM))

En appliquant φ à chaque coté de l'égalité

φ(V(FK))= φ(Min(V(F1), V(F2), ..., V(FM)))

D'après la propriété (P4):

E(FK)= φ(Min(V(F1), V(F2), ..., V(FM)))

Mais comme φ est croissante :

E(FK)= Min(φ(V(F1)), φ(V(F2)), ..., φ(V(FM)))

et en appliquant encore une fois la propriété (P4):

E(FK)=Min(E(F1), E(F2), ..., E(FM))

Exemples d'heuristiques

Exemple 1: Heuristique pour le jeu d'échec

Une manière assez rudimentaire d'évaluer une situation de jeu aux échecs est de baser le calcul sur la valeur des pièces de chaque joueur. Une autre manière plus élaborée, serait d'intégrer la position des pièces dans le calcul. Mais le critère positionnel est plus délicat à évaluer. Notre objectif étant simplement de faire ressortir quelques principes à travers un exemple, nous nous contenterons ici du critère matériel (la valeur des pièces).

Les valeurs officiellement acceptées des pièces sont les suivantes: la dame vaut 9 points, la tour 5 points, le fou et le cavalier 3 points et le pion 1 point. Le roi n'est pas pris en compte dans le calcul, car il est toujours présent.

On pourrait calculer la valeur heuristique d'une situation en soustrayant le nombre de points de A du nombre de points de J. Cela nous donnerait, le calcul suivant:

VH = 9(DJ - DA)+5(TJ - TA)+3(FJ - FA) +3(CJ - CA)+(PJ - PA)

où :

Il nous faut ensuite choisir une valeur pour Vmax de telle manière que -Vmax < VH < Vmax.

Il suffit de trouver un majorant très grossier de la valeur heuristique. Il faut tenir compte ici de la règle de transformation du pion. Lorsqu'un pion atteint la dernière ligne, il peut être transformé en une autre pièce (au choix dame, tour, fou ou cavalier). J peut donc théoriquement posséder au maximum 9 dames, 10 tours, 10 fous, 10 cavaliers et 8 pions. Dans la réalité, il est impossible de réaliser tout ces maximum simultanément, mais peu importe, puisque nous cherchons simplement un majorant. D'autre part A aura au minimum 0 points, s'il ne lui reste que le roi.

Cela nous donne:

VH ≤ 9 ×9+ 5×10 + 3×10 + 3×10 + 8 = 199

On peut donc prendre par exemple Vmax = 200. Une situation de jeu de valeur 200 représentera dans ce cas la situation de mat de A ou autrement dit, la victoire de J. Inversement, Une situation de jeu de valeur -200 représentera la situation de mat de J ou autrement dit, la victoire de A.


Exemple 2: Heuristique pour le super morpion

Au super morpion, on peut définir la valeur heuristique d'une situation à partir de la présence de deux types de motifs permettant potentiellement de réaliser un alignement de trois symboles identiques (croix ou rond). Les motifs de type 1 permettent de réaliser un alignement de trois symboles en un coup et ceux de type 2, en deux coups.

Voici, les douze motifs de type 1 pour les ronds. Si les ronds jouent la case vide, ils gagnent un alignement:

Alignt-Potentiel-Un-Coup.jpg, 64kB
Motifs de type 1

et voici les douze motifs de type 2 pour les ronds. Si les ronds jouent les deux cases vides, ils gagnent un alignement:

Alignt-Potentiel-Deux-Coups.jpg, 51kB
Motifs de type 2

Les motifs de type 1 sont beaucoup plus dangereux que ceux de type 2. Il faut donc leur donner un poids plus important dans le calcul de l'heuristique. Il faut également tenir compte du nombre d'alignements déjà réalisé, par chaque joueur.

Voici une manière de tenir compte de tout cela dans le calcul de VH

VH = K2 ((A3J+M1J) - (A3A+M1A)) + M2J - M2A

où :

Comme dans le cas du jeu d'échec, pour définir la valeur de Vmax, on s'arrange pour que -Vmax < VH < Vmax, Ici on pourra prendre

Vmax = K2 K1 + K2 = K2(K1 + 1)

K1 est un majorant de (A3J+M1J) - (A3A+M1A).