Soit un jeu hypothétique :
type Joueurs = (Premier,Second);
type Mouvement = {type énuméré ou intervalle,suivant
le jeu };
var Mvmt : Mouvement;
(Mvmt définit un mouvement possible respectant les règles du
jeu).
procedure Jouer (Joueur: Joueurs; Mvmt: Mouvement);
{modifie la situation avec Mvmt}
procedure Defaire (Joueur: Joueurs; Mvmt: Mouvement);
{revient à la situation d'avant Mvmt}
procedure Possible(Joueur:Joueurs;
var
MvtPossibles:Liste;
var
Val:Valeur); La structure de la liste des mouvements possibles dépend fortement du jeu qui est simulé (jeu à base de pièces sur un damier, jeu de dés, jeu de cartes, etc...). On peut toutefois imaginer que des procédures annexes permettent de gérer cette liste et d'accéder à ses éléments.
Par exemple :
procedure PremierElement(
var MvtPossibles:Liste;
var Mvmt:Mouvement);
permet d'extraire le premier mouvement de la liste MvtPossibles (Mvmt <- car(MvtPossibles) et MvtPossibles <- cdr(MvtPossibles) ).
procedure ElementSuivant(
var MvtPossibles:Liste;
var Mvmt:Mouvement);
permet d'obtenir l'élément suivant (Mvmt <- car(MvtPossibles)
et MvtPossibles <- cdr(MvtPossibles)).
Function Taille
(MvtPossibles:Liste)
: integer;
détermine le nombre de mouvements contenu dans la liste.
Function Vide (MvtPossibles:Liste)
: boolean;
détermine si la liste contient encore des mouvements.
Une première ébauche d'une procédure de jeu selon la méthode Mi niMax peut être la suivante (en prenant beaucoup de liberté avec la syntaxe) :
procedure MiniMax (Profondeur : integer;
Joueur : Joueurs;
var Mvmt : Mouvement; var Val : Valeur);
{ cette procédure explore jusqu'à
"Profondeur" niveaux l'arbre de jeu :
elle donne comme résultat le mouvement
Mvmt pour le joueur et la valeur Val
associée à la situation actuelle. }
begin
Possible(Joueur,MvtPossibles,Val);
if MvtPossibles ne contient qu'un mouv.
then réponse = (Mvmt,Val)
else begin
for chaque mouvement possible do begin
jouer ce mouvement;
minimax (Profondeur-1,autre joueur,
...);
défaire ce mouvement
end; { for }
sélectionner la meilleure valeur pour
le Joueur parmi les valeurs produites
dans la boucle ci-dessus;
réponse := (Mvmt,Val);
end; { else }
end; { MiniMax }
A partir de cette ébauche, et avec les procédures de base définies avant, on peut proposer une formulation plus rigoureuse pour la procédure minimax.
procedure MiniMax (Profondeur : integer;
Joueur : Joueurs;
var Mvmt : Mouvement;
var Val : Valeur);
{ Pour l'algorithme qui suit, on suppose
que la situation du jeu est maintenu
globalement en dehors de la procédure }
const Infini = MaxInt;
var Adversaire : Joueurs;
MAdv: Mouvement; { mouvement de
l'adversaire }
VAdv: Valeur; {valeur associée au
mouvement de l'adversaire }
MvtPossibles: Liste;
{ mouvements possibles pour Joueur }
MEssai: Mouvement;
{ un mouvement possible à essayer }
begin { MiniMax }
Possible(Joueur,MvtPossibles,Val);
if Taille(MvtPossibles) <= 0 then
"forfait"
else if (Taille(MvtPossibles) = 1) or
(Profondeur = 0) then
PremierElement (MvtPossibles,Mvmt)
else begin
if Joueur = Premier then begin
Adversaire := Second;
Val := -Infini; {la plus petite }
end {valeur possible}
else begin
Adversaire := Premier;
Val := Infini; {la plus grande }
end; {valeur possible}
PremierElement (MvtPossibles,MEssai);
while not Vide(MvtPossibles) do begin
Jouer(Joueur, MEssai);
MiniMax(Profondeur-1, Adversaire,
MAdv, VAdv);
Defaire(Joueur, MEssai);
if (Joueur = Premier) and
(VAdv > Val) then begin
{max} Val := VAdv; Mvmt := MEssai;
end
else if (Joueur=Second) and
(VAdv < Val) then begin
{min} Val := VAdv; Mvmt := MEssai;
end;
ElementSuivant(MvtPossibles, MEssai)
end; { while }
end; { if }
end; { MiniMax }
Si l'on applique la méthode du MiniMax, on se rend vite compte qu'il n'est pas toujours nécessaire de parcourir la totalité de l'arbre de jeu pour trouver le chemin optimal : on "coupe" des branches que l'on sait inutiles. Ainsi, soit l'arbre de jeu de la figure 15.14,
Au niveau 0 la racine prend la valeur maximale des descendants,
au niveau 1 chaque noeud prend la valeur minimale des descendants,
au niveau 2 chaque noeud prend la valeur maximale des descendants,
au niveau 3 chaque noeud prend la valeur minimale des descendants,
etc.
Si l'on propage, selon l'algorithme du MiniMax, les valeurs de la fonction d'évaluation associée à chaque feuille, on obtient l'arbre de décision de la fi gure 15.15.
Fig. 15.14. Arbre de jeu avec valeur des situations terminales.
Fig. 15.15. Evaluation des situations non-terminales.
Les deux sous-arbres de la figure 15.15 qui ont été entourés
peuvent ne pas être évalués car :
C'est la méthode de l'élagage alpha-bêta. Les lettres grecques alpha et bêta sont souvent utilisées pour marquer les points d'élagage, alpha pour max et bêta pour min.
Table des
matières.
Site Hosting: Bronco