Bonjour tout le monde !
Je développe depuis plusieurs mois un jeu de type `jeu à damier` se jouant tour par tour à deux joueurs.
Voici le principe du jeu :
Sur un plateau de type matrice (8*8 cases) se situe des cases rouges appartenant à un joueur et des cases vertes appartenant à son adversaire , des cases impénétrables et des
cases pénétrables . Chacun leurs tours les joueurs ont la possibilité avec la case de leur couleur respective de leur choix de se dupliquer sur une case directement voisine (sur l'horizontale , la verticale et la diagonale) si celle-ci est
pénétrables ou se déplacer sur une case voisine à une case (la voisine de la voisine horizontal ou verticale mais pas diagonale) , si la case du joueur est alors voisine avec une case du joueur adverse la case du joueur adverse est 'contaminée'
et devient de la couleur du joueur . Le jeu se termine lorsque le plateau est rempli ou lorsqu'un joueur à aucune possibilité ou si un joueur n'a plus de cases (elles se sont toutes faites contaminées).
Ce n'est pas trés grave si vous n'avez pas tout saisi , je vous présente à présent le probléme !
C'est le parfait jeu pour appliquer l'algorithme MinMax de Van Neumann dans le butd'avoir une Intelligence Artificielle qui puisse jouer contre un joueur humain.
Voici à présent ma classe MinMax qui est sensé gérer l'IA . (Aprés instanciation j'appel la méthode DecisionMinMax() avec les paramétres demandés pour faire fonctionner la machine :p) :
EXEMPLE1:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 class MinMax(object): '''Gestion de l'IA avec l'Algorithme minmax''' def __init__(self,plateau,joueur,adversaire): '''plateau : plateau de jeu sur lequel nous effectuons toutes nos simulations , il nous donne la situation actuel du jeu . MAX_H : seuil qui nous servira dans les fonctions de calcul joueur,adversaire :Nous sert de comparaison pour la méthode Adversaire ''' self.plateau=plateau self.MAX_H = 10000 self.joueur=joueur self.adversaire=adversaire ############################################### #LES METHODES SUIVANTES FONCTIONNENT .######### def Adversaire(self,j): '''Retourne l'adversaire du joueur j''' def evaluation(self,joueur): '''Retourne la différence de score entre le joueur courant et l'adversaire - sert à evaluer la qualité d'un coup''' def AppliqueCoup(self,joueur,case) '''Propage un coup à la case case et retourne les cases modifiées par le coup''' def AnnuleCoup(self,joueur,case,casesModif) '''Annule un coup appliqué à la case case et annule les casesModif''' def CoupsPremierPossibles(self,joueur) '''Retourne un tableau donnant toutes les cases appartenant à joueur''' def CoupsSecondPossibles(self,coupPremier) '''Retourne toutes les cases qui seront jouables si l'on clique sur la case coupPremier''' ############################################### def DecisionMinMax (self,joueur,p) : '''Décide du meilleur coup à jouer par le joueur j dans la situation Début Pour chaque coup de CoupJouables(e,j) faire valeur[coup] = ValeurMinMax(Applique(coup,e),J,false) Fin pour retourner (coup tel que valeur[coup] est maximale) Fin''' coups=self.CoupsPremierPossibles(joueur) max=-64 if not coups: meilleurCoup=[False,False] else: for case in coups : coupSecond=self.CoupsSecondPossibles(case) for c in coupSecond : val=self.AppliqueCoup(joueur,c) #On applique le coup if (self.ValeurMinMax(joueur,False,p)>max): meilleurCoup=[case,c] self.AnnuleCoup(joueur,c,val) #On annule le coup return meilleurCoup def ValeurMinMax (self,j,EstUnEtatMax,pmax) : '''{ Calcule la valeur de e pour le joueur J selon que e EstUnEtatMax ou pas et pmax la profondeur maximale } Début Si PartieGagnante(e,J) Alors retourner(+ValMax) Sinon Si PartiePerdante(e,J) Alors retourner(-ValMax) Sinon Si PartieNulle(e,J) Alors retourner(0) Sinon Si pmax=0 Alors retourner h(s,J) Sinon vals = vide Pour s parmi les successeurs de e faire ajouter ValeurMinMax(s,J,not(EstUnEtatMax),pmax-1)) à vals Fin pour Si EstUnEtatMax Alors retourner(maximum de vals) Sinon retourner(minimum de vals) Fin si Fin si Fin si Fin si Fin ''' #CAS 1 : FIN DE PARTIE if self.plateau.fini(self.Adversaire(j).getScore()): #Si la partie est finie if self.evaluation(j)>0: #Si le joueur a gagné r=+self.VAL_MAX elif self.evaluation(j)<0: #Si le joueur a perdu r=-self.VAL_MAX else: #égalité entre les deux joueurs r=0 #CAS 2 : PROFONDEUR 0 elif pmax==0: #Si la profondeur est de 0 : anticipation d'aucun coup - on joue le meilleur coup du moment return self.evaluation(j) #On retourn directement la différence de score entre l'Ordinateur et le joueur #CAS 3 : PROFONDEUR >0 else : vals = [] coups=self.CoupsPremierPossibles(j) for case in coups : coupSecond=self.CoupsSecondPossibles(case) for c in coupSecond : val=self.AppliqueCoup(j,c) #On applique le coup vals.append(self.ValeurMinMax(j,not(EstUnEtatMax),pmax-1)) self.AnnuleCoup(j,c,val) #On annule le coup vals.sort() #Je tri la liste vals par valeur croissantt if (EstUnEtatMax): r=vals[len(vals)-1] else: r=vals[0] return r
J'ai maintenant modifié les méthodes DecisionMinmax() & ValeurMinMax de cette manière :
EXEMPLE2:
Voici le constat :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 def ValeurMinMax(self,j,profondeur,EstMax) : '''Evalue une situation de jeu pour le joueur j suivant l'algorithme MinMax EstMax= évaluation du maximum (meilleur coup de notre part ) et pas une évaluation du minimum (meilleur coup de l'adversaire) ''' #CAS 1 : FIN DE PARTIE if self.plateau.fini(self.Adversaire(j).getScore()): #Si la partie est finie if self.evaluation(j)>0: #Si le joueur a gagné return self.MAX_H-self.Adversaire(j).getScore() elif self.evaluation(j)<0: #Si le joueur a perdu return -self.MAX_H+j.getScore() else: #égalité entre l'ordinateur et l'adversaire return 0 #CAS 2 : PROFONDEUR 0 elif profondeur==0: #Si la profondeur est de 0 : anticipation d'aucun coup - on joue le meilleur coup du moment return self.evaluation(j) #On retourne directement la différence de score entre l'Ordinateur et le joueur #CAS 3 : CALCUL D'UN NOEUD MAX elif EstMax: #Si on est en mode max: je calcul le meilleur coup de ma part coups=self.CoupsPremierPossibles(j) if not(coups): return self.ValeurMinMax(j,profondeur-1,False) else: bscore = -(self.MAX_H+1) for case in coups: coupSecond=self.CoupsSecondPossibles(case) for c in coupSecond : app=self.AppliqueCoup(j,c) score = self.ValeurMinMax(j,profondeur-1,False); if score > bscore: bscore = score self.AnnuleCoup(j,c,app) return bscore #CAS 3 : CALCUL D'UN NOEUF MIN else: coups=self.CoupsPremierPossibles(self.Adversaire(j)) if not(coups): return self.ValeurMinMax(j,profondeur-1,True) else: bscore = +(self.MAX_H+1) for case in coups: coupSecond=self.CoupsSecondPossibles(case) for c in coupSecond : app=self.AppliqueCoup(self.Adversaire(j),c) score = self.ValeurMinMax(j,profondeur-1,False); if score<bscore: bscore = score self.AnnuleCoup(self.Adversaire(j),c,app) return bscore def DecisionMinMax(self,profondeur,j) : '''Décider du coup à jouer en appliquant l'algorithme MinMax''' #La profondeur ne peut être inférieure à 1 if (profondeur<1): profondeur=1 S = -(self.MAX_H+1) coups=self.CoupsPremierPossibles(j) if not(coups): return self.ValeurMinMax(j,profondeur-1,True) else: meilleurCoup=[False,False] for case in coups: coupSecond=self.CoupsSecondPossibles(case) for c in coupSecond : app=self.AppliqueCoup(j,c) score = self.ValeurMinMax(j,profondeur-1,False) if (score > S) or ((score == S) and (random.randint(0,2)==1)): meilleurCoup=[case,c] S=score self.AnnuleCoup(j,c,app) return meilleurCoup #NOTRE SAINT GRAAL
EXEMPLE1 :
L'algorithme joue pas les coups attendues , ne fait aucune duplication uniquement un unique déplacement de case .
EXEMPLE2 :
Avec une profondeur de 1 l'algorithme marche bien , même trés bien .
Cependant , avec une profondeur supérieur le programme ne joue pas les coups attendues , en totale incohérence avec leniveau demandé .
Autrement dit le #CAS 2 de la méthode ValeurMinMax() de l'exemple 2 fonctionne mais le #CAS 3 et #CAS 4 fonctionnent mal. J'aimerais que vous m'éclairiez pour résoudre mon
problème .
Pour réaliser l'algorithme j'ai pris exemple sur le code de Fabien Torre dans l'exemple 1.
Dans l'exemple 2 j'ai utilisé un algorithme fait par ____ avec son programme Piotellino (qui marche) .
Merci beaucoup pour votre aide .
Partager