Projet d’Informatique Algorithme MinMax en théorie des jeux Contact : [email protected] 4 septembre 2008 1 La stratégie du MinMax 1.1 Contexte général Ce projet se propose de se familiariser avec un algorithme classique d’intelligence artificielle appelé algorithme MinMax. Cet algorithme est utilisé pour les jeux à deux joueurs, décrit en théorie des jeux comme étant à information complète et à somme nulle. C’est le cas notamment des échecs, des dames, de l’othello, du puissance 4, et en règle générale de beaucoup de jeu de plateau à deux joueurs. → Recherche Bibliographique : Qu’est ce qu’un jeu à information complète ? A somme nulle ? Trouver des exemples de jeux ne satisfaisant pas ces critères. Quelles peuvent être les méthodes utilisées pour faire jouer un ordinateur à de tels jeux ? 1.2 1.2.1 Idée générale de l’algorithme MinMax Notations On notera dans toute la suite J1 et J2 les deux joueurs, et l’idée de l’algorithme est ici énoncée indépendemment du type de jeu pourvu que chaque joueur n’ait, à chaque tour, qu’un nombre fini de coups possibles. On appelle configuration et on notera θ une description complète de l’état de la partie à un instant donné : situation du jeu, mais aussi qui doit jouer, et eventuellement comment (temps imparti, historique des coups, ...). θ dépend bien évidemment du type de jeu : – Pour un morpion, c’est simplement l’état de la grille (croix et ronds déjà joués) ainsi que l’information “C’est à J1/2 de jouer” – Pour un jeu d’échec, ce sera la position de toutes les pièces sur l’échéquier, l’information “C’est à J1/2 de jouer”, mais aussi un historique des positions pour éviter les situations sans issues, et éventuellement le temps de jeu restant par joueur (en cas de partie chronométrée). 1 On suppose également que l’on dispose d’une fonction d’évaluation Φ qui associe à toute configuration θ une valeur numérique réelle. Φ(θ) quantifie la certitude de gagner, étant donner l’état θ de la partie : plus la valeur rendue par Φ est grande, plus la situation θ est favorable. Le but de toute partie est donc, pour un joueur, de maximiser sa propre fonction d’évaluation et de minimiser celle de l’autre. D’où l’idée et le nom de l’algorithme MinMax. 1.2.2 Coeur de l’algorithme Supposons que le jeu soit dans la situation θ, et que J1 ait à jouer un coup parmi n coups possibles pour amener le jeu dans une nouvelle situation θi avec i ∈ [1, .., n], comme expliqué sur la figure 1. Si J1 joue un coup qui θ J1 joue θ1 θn θi J2 joue θ1,1 θ1,α1 θi,1 θ1,αi θn,1 θn,αn Fig. 1 – Schéma conceptuel du MinMax, expliqué pour un seul niveau d’analyse (i.e sur deux coups) le mène dans la situation particulière θi , alors J2 , s’il joue intelligement, va chercher à minimiser la fonction d’évaluation de J1 au coup suivant, c’est à dire qu’il cherchera, parmi les αi coups à jouer à partir de θi , à choisir θi,j telle que Φ(θi,j ) soit minimale. J1 à donc interêt à choisir le coup qui va maximiser ce minimum, et donc de jouer la situation θi telle que : Φ(θi ) = max min Φ(θi,j ) i∈[1,n] j∈[1,αi ] 1.3 (1) Recursivité Ce que nous venons de décrire sur un niveau d’analyse (2 coups), peut être appliqué de façon récursive sur plusieurs niveaux. En effet, comme le montre la figure 1 le déroulement d’une partie peut être vu comme un arbre : – La racine (le sommet de l’arbre) correspond à l’état initial du jeu. – Les noeuds à profondeurs paire correspondent aux noeuds où J1 doit jouer, alors que c’est à J2 de jouer aux noeuds de profondeurs impaires. 2 – Chaque arc correspond à un coup joué et associe un état du jeu à la profondeur – Aux feuilles, tout en bas de l’arbre, se trouvent les fins de parties. – Un chemin complet, allant de la racine à une feuille, décrit une partie possible On a peut alors étendre l’algorithme, noté F , en le faisant calculer le meilleur coup à jouer sur n niveaux, de la façon suivante : si θ est une feuille de l’arbre Φ(θ) F (θ) = maxi∈[1,n] F (θi ) si θ est un noeud joueur avec fils θ1,..,n (2) mini∈[1,n] F (θi ) si θ est un noeud opposant avec fils θ1,..,n La récurrence peut être stoppée au bout de n niveaux, afin de jouer le coup qui, après avoir analysé tous les coups possibles dans une profondeur 2n (car un niveau d’analyse est toujours un coup du joueur J1 et la réponse de J2 ), va être le plus favorable. 2 2.1 Application au jeu de Nim Principe du jeu de Nim Le jeu de Nim (aussi appelé jeu des allumettes), est un jeu où sont disposées sur le plateau N allumettes, par groupe de k. Chaque joueur peut prendre autant d’allumettes qu’il le souhaite dans un groupe, puis c’est à l’autre de jouer. Le joueur qui prend la dernière allumette à gagné. Fig. 2 – Exemple de jeu de Nim avec 20 allumettes, réparties en 4 tas de 5 2.2 Exemple pratique Sans rien coder, juste au papier et au stylo, vous réfléchirez aux principe du MinMax récursif dans le cadre du jeu de Nim, comme détaillé sur la figure 3. Quelle est la fonction d’évaluation Φ pour un tel jeu ? Vous construirez, sur une feuille, un exemple de partie en développant l’arbre de tous les coups possibles et en indiquant la valeur de Φ en chaque noeud pour un départ avec deux tas de 3 et 2 allumettes. Il est important de bien comprendre comment l’algorithme opère avant d’aller plus loin, n’hésitez pas à me contacter si vous avez des questions. 3 Fig. 3 – Exemple de l’algorithme du MinMax appliqué au jeu de nim dans une situation avec 2 tas comportant respectivement 2 et 1 allumettes. On a l’arbre des coups ainsi que la valeur de Φ pour chaque configuration. L’algorithme est déroulé sur 2 niveaux d’analyses (4 coups), et l’on constate que le coup à jouer, pour le joueur 1, est de ne prendre qu’une allumette pour laisser deux tas de deux. 2.3 Travail demandé Vous fournirez un code ***commenté*** (en C ou autre) permettant, avec une interface graphique basique en mode console, de jouer au jeu de Nim à deux ou seul contre l’ordinateur. Les contraintes à respecter sont les suivantes : → Le choix du nombre d’allumette et de groupes devra être configurable. Par défaut, on restera sur la version de la Figure 2 (4 groupes de 5), → On devra pouvoir choisir le type de jeu voulu (jeu à 2 ou jeu seul contre l’ordinateur). → On devra pouvoir choisir quel joueur va commencer la partie, J1 ou J2 → Contre l’ordinateur, on envisagera plusieurs niveaux de difficultés : Aléatoire L’ordinateur joue au hasard Facile MinMax sur un niveau Moyen MinMax sur cinq niveaux Difficile MinMax sur dix niveaux Imbattable ? (facultatif, voir dernière section) 2.4 Quelques pistes pour le code Les indications données ici ne sont là qu’à titre informatif et il n’est donc pas obligatoire de les suivre au pieds de la lettre. Réfléchissez juste bien à votre code avant de vous lancer, et aux différentes fonctions qui vont être 4 nécessaires. Vous pouvez commencer par coder d’abord le jeu dans sa version 2 joueurs humains, utilisant a priori des fonctions telles que : – config partie() → affiche un menu permettant de selectionner le nombre de groupe et d’allumettes – affiche plateau(θ) → affiche la configuration θ du jeu sur la console – coups possibles(θ) → retourne, pour une configuration θ, tous les coups jouables possibles. Si un joueur veut jouer un coup qui n’est pas dans cette liste, le coup doit être interdit. – joue coup(θ, humain) → joue un coup possible dans la configuration θ, avec un booléen humain définissant si le coup est joué par un humain (auquel cas on doit prévoir une méthode de saisie du coup), ou par l’ordinateur (via MinMax). Pour ce qui est de la partie intelligence artificielle, via le MinMax, vous aurez besoin de fonctions telles que : – config level() → affiche un menu pour choisir le niveau de l’IA. – eval coup(θ) → évalue la valeur de Φ pour une configuration. (On supposera que Φ est à valeur dans [0, 1], rendant 0 pour un défaite et 1 pour une victoire). – minmax(θ) → calcule le coup à jouer par minmax pour un seul niveau d’analyse (2 coups). – minmax n(θ,n) calcule le coup à jouer par minmax pour une anaylse sur 2n coups. 3 Pour aller plus loin Dans cette section, vous trouverez différentes pistes pour continuer le projet. Vous pouvez les explorer dans l’ordre que vous voulez, en fonction du temps que vous voulez leur accorder. Toutes font appel à des recherches actives de votre part, mais je reste disponible pour toutes vos questions. L’algorithme MinMax, de par sa construction, est donc un algorithme exhaustif qui construit l’arbre de toutes les configurations du jeu (pour une profondeur d’analyse fixée) et choisit, a chaque coup, celui qui va minimiser les chances de gagner de l’adversaire. Néanmoins, la construction d’un tel arbre n’est pas possible dans tous les cas car lorsque trop de branches sont possibles, les temps de calculs deviennent prohibitifs ! Pour s’en convaincre, vous pouvez tester la réactivité de votre programme quand le nombre d’allumette devient grand et/ou que la profondeur de l’analyse du MinMax augmente. → Recherche Bibliographique : Quelles sont les stratégies envisagées pour faire face à ce problème ? Expliquer moi rapidement les intêrets de 5 ce que l’on appelle l’élagage alpha-beta. Que pourrait-on envisager d’autre comme stratégies pour réduire l’exploration de tous les coups possibles ? Dans le cas précis du jeu de Nim, n’y a-t-il pas une stratégie de jeu optimale ? Essayer, si vous avez le temps, de mettre en oeuvre une telle technique d’optimisation afin de pouvoir rendre votre programme réellement imbattable et rapide quelle que soit la complexité de départ. Vous pouvez aussi essayer de vous lancer dans une interface graphique du jeu, à vous de voir. 3.1 Compte-rendu Ce travail n’est important que dans la façon dont vous l’aborderez. Il est important que vous fassiez quelques recherches par vous même sur l’algorithme, que vous en compreniez son fonctionnement et ses limites. Un compte rendu intermédiaire sera attendu à mi parcours donc pensez à essayer de rédiger votre rapport en même temps que votre code. Dans le rapport, on trouvera une explication des fonctions importantes, une justification des structures de données mises en place pour représenter l’état du jeu, etc... Pas la peine de me recopier le code, vous me joindrez les fichiers en annexe. Pour l’évaluation, seront prises en compte la clareté du rapport et du code, ainsi que les éventuelles optimisations apportées à l’algorithme MinMax si vous en avez eut le temps. Un tournoi de Nim entre vos programmes pourra être envisagé si tout le monde à finit à temps. Rappel pour le code : L’explication, avec des mots, et les commentaires du code sont aussi important que le code lui même. 6