Poker A rendre pour le 25 avril 0 Avant propos 0.1 Notation Les parties sans * sont obligatoires (ne rendez pas un projet qui ne contient pas toutes les fonctions sans *). Celles avec (*) sont moins faciles mais restent tout à fait faisables. Vous devez les faire si vous voulez obtenir la moyenne. Celles avec (**) sont difficiles et nécessitent de passer du temps dessus, mais vous avez normalement le niveau pour les faire. Les parties notées (***) sont très difficiles. Elles nécessitent un certain temps de réflexion et sont facultatives (Une bonne note peut être obtenue sans les faire). Les parties notées (****) sont au-delà du niveau attendu. Elles vous permettent de voir les différentes pistes permettant d aller plus loin. Mais en y passant du temps, vous devez pouvoir réussir à les faire. Les parties notées (*****) sont très au-delà du niveau attendu. Elles sont peu guidées et nécessitent une grosse réflexion personnelle. Elles ne sont à faire que si vous n avez pas eu de mal avec les questions précédentes. Les parties notées ( ) indiquent qu elles nécessitent d utiliser des outils qui ne sont pas au programme du cours. Elles ne sont pas nécessairement dures mais nécessitent de se documenter par soi-même, et sont donc facultatives. 0.2 Travail à plusieurs Vous pouvez travailler seul ou à deux. Si vous travaillez à deux, un meilleur résultat sera attendu. Si vous travaillez à deux et que vous vous répartissez le travail, indiquez sous chaque fonction si elle a été réalisée individuellement, et si oui, par qui. 0.3 Recommandation Commentez bien votre code. Indentez le code. Organisez votre code en fonction : Bien que l énoncé guide la construction du programme en le découpant déjà en fonctions (surtout dans les premières parties), n hésitez pas à redécouper des parties en plusieurs fonctions plus petites si le besoin s en fait sentir. Évitez au possible les variables globales. Les variables globales doivent être réservées aux informations nécessaires dans une grande partie du code en lecture, et qu on ne modifie jamais après leur première instanciation. A part ces cas très particuliers, n utilisez que des variables locales. Testez vos fonctions au fur et à mesure. N attendez pas la fin pour débugger votre code. Rendez un projet compilable et fonctionnel. Si certaines fonctions ne fonctionnent pas, indiquez-le clairement. Il vaut toujours mieux faire peu de fonctions qui marchent que beaucoup de fonctions qui ne marchent pas. Lorsque vous êtes perdu face à vos structures, faites un schéma des structures utilisées. Vous pouvez le rendre avec votre projet. 1
0.4 Rendu Envoyez votre code par mail dans une archive contenant votre/vos nom(s), le ou les fichiers de code (le code doit être compilable), un schéma des structures utilisées, un document texte indiquant si nécessaire comment votre programme doit être utilisé et quelles sont ses limites (quels sont les fonctions que vous avez eu le temps de coder et quels sont celles que vous n avez pas faites), un ou plusieurs fichier jeu que votre programme est capable d utiliser, et plusieurs exemples de code exécuté (Un copier-coller de ce que contient la console). Le sujet du mail doit contenir le nom de votre groupe. Le mail doit être envoyé à tisserant@lirmm.fr 0.5 Plan de travail Le but de ce TP noté est de faire un programme capable de jouer à une variante simplifiée de poker fermé. http://fr.wikipedia.org/wiki/poker_ferm%c3%a9 Dans cette version, chaque joueur a une main de 5 cartes. Nous allons commencer par une version simplifiée au maximum où chaque tour se déroule comme suit : Chaque joueur paye une mise de départ de 10.. Chaque joueur reçoit ses cinq cartes. Chaque joueur choisit simultanément si il se couche, ou si il mise 100 pour voir. Si les deux joueurs ont payé pour voir, ils montrent leurs cartes. Celui qui a la meilleure main ramasse la mise. Si un seul des joueurs a payé, il ramasse les mises. Si aucun des deux joueurs n a payé, leurs mises initiales de 10 leur sont rendues. La partie s arrête quand un joueur n a plus assez d argent (110) pour finir un tour. Les règles vont ensuite évoluer petit à petit tout au long du TP pour finir sur un jeu un peu plus intéressant. 0.6 Structures et Variables Voilà la structure principale que l on va manipuler : struct Carte{ int valeur; //1 à 13 int couleur; //1 à 4 Elle va nous servir pour construire les structures : struct Pioche{ struct Carte paquet[52]; int taille; //Nombre de cartes restant dans la pioche struct Joueur { struct Carte main[5]; int argent; 1 Les fonction de base Coder ces fonctions : void affichermain(carte c) qui affiche une carte. void affichermain(carte main[5]) qui affiche les cartes d une main. Pioche generepioche() qui renvoie une pioche contenant les 52 cartes (*). Pioche melangepioche(struct Pioche p) qui prend en paramètre une pioche et renvoie une pioche mélangée aléatoirement. (* ) Carte * generemain(struct Pioche * p) qui prend en paramètre une pioche, renvoie une main de 5 cartes, et les enlève de la pioche. 2
2 Combinaison dans une main 2.1 Carte la plus forte Faites une fonction qui renvoie le rang de la carte la plus forte de la main. 2.2 Carte identique Faites une fonction qui prend en paramètre une main et un entier représentant une valeur et renvoie le nombre de cartes de cette valeur dans la main. 2.3 Couleur Faites une fonction qui prend en paramètre une main et renvoie vrai si les 5 cartes sont de la même couleur. 2.4 Suite (*) Faites une fonction qui prend en paramètre une main et renvoie vrai si les 5 valeurs se suivent. 2.5 Combinaison dans une main (**) En utilisant les trois fonctions précédentes, faites une fonction qui prend en paramètre une main et renvoie un entier différent pour chaque combinaison (rien, paire, double paire, brelan, suite, couleur, main pleine, carré, Quinte flush). 2.6 La main la plus forte (**) Faites une fonction qui prend en entrée deux mains, et qui renvoie 1 si la première est plus forte que la deuxième, 0 sinon. Dans le cas où les deux mains contiennent une combinaison équivalente, on part du principe que c est la carte la plus forte qui gagne. On ne traitera pas les cas d égalité plus complexes. 3 interface 3.1 affichage Faites une fonction qui affiche la main du joueur, l argent qui lui reste, l argent qu il reste à son adversaire et lui demande si il veut miser ou se coucher. 3.2 jeu (* ) En utilisant les fonctions codées jusque là, construisez un programme capable de faire jouer un joueur contre une intelligence artificielle qui choisit aléatoirement de miser ou de se coucher, et qui relance des tours jusqu à ce qu un des deux joueurs ait moins de 110. 4 Les probabilités 4.1 Probabilités de victoire (**) Les probabilités de victoire au poker ne sont pas si faciles à calculer. Nous allons utiliser une solution un peu brutale qui consiste à générer toutes les mains possibles de l adversaire pour regarder le nombre de mains de puissance inférieure à la main courante. Faites une fonction qui prend en paramètre une pioche, une main, et renvoie une probabilité de victoire pour la main donnée en paramètre. 4.2 Première intelligence artificielle (**) Remplacez votre intelligence artificielle par une qui choisit de miser lorsque sa probabilité de victoire est supérieure à 50%. 3
5 Jeu à décision désynchronisée et apprentissage automatique Les règles proposées dans leur version simple posent un problème majeur : Les deux joueurs prennent leur décision de miser ou se coucher simultanément. Or, si cela est facile à émuler sur un programme, c est un peu moins facile en réalité. C est pour cela que dans la plupart des variantes de Poker, les joueurs misent les uns après les autres. Nous allons donc modifier le jeu pour que les joueurs misent l un après l autre. Un des deux joueurs va être considéré comme le donneur et va choisir de miser ou se coucher. Ensuite, le deuxième joueur va faire le même choix, mais en ayant connaissance du choix du premier. A chaque tour, l ordre de choix est inversé. 5.1 Changement de l interface (*) Faites évoluer votre programme pour tenir compte du changement de règles. 5.2 Apprentissage automatique (***) Lorsqu elle parle en premier, l intelligence artificielle n a pas besoin de changement, elle peut se contenter de jouer en fonction des probabilités. Mais lorsqu elle parle en deuxième, elle doit tenir compte du choix du premier joueur. Si le premier joueur s est couché, l IA doit choisir de miser. Si il ne s est pas couché, elle doit en tenir compte dans ses probabilités. L intelligence artificielle va donc mémoriser dans des tableaux (appelés victoire et défaite) le nombre de victoires et de défaites en fonction de la probabilité de victoire de sa main. Par exemple, si l intelligence artificielle perd une partie où elle estimait avoir 54% de victoire, elle va ajouter 1 au tableau contenant le nombre de défaites par probabilité dans toutes les cases inférieure ou égale à 54. Si elle estimait avoir 60% de chance de gagner et qu elle gagne, elle va ajouter 1 dans toutes les cases supérieur ou égal à 60 dans le tableau de victoire. 5.3 Utilisation de l apprentissage (***) Au fur et à mesure que les tableaux se remplissent, l IA peut les utiliser pour choisir de miser ou non. Elle possède donc une probabilité mathématique de gagner (calculé par la fonction proposé en partie 4.1 ) que l on va appeler PM, et une probabilité acquise au cours de l expérience, calculé pour une probabilité mathématique avec la formule : victoire[pm]+1/(victoire[pm]+defaite[pm]+2). Faites évoluer votre IA pour qu elle décide de miser ou se coucher en utilisant ces deux mesures. 6 Jeu avec relance Dans la plupart des variantes du Poker, les joueurs n ont pas une mise imposée mais peuvent miser ce qu ils veulent. De plus, ils peuvent choisir de ne pas se contenter de suivre (mettre la mise demandé par le premier joueur qui a misé), mais de relancer (miser plus, et forcer ainsi tous les joueurs à s aligner sur sa mise). Les cartes ne sont donc montrées que lorsque les deux joueurs ont misé la même somme. 6.1 Changement de l interface (*) Faites évoluer votre programme pour tenir compte du changement de règles. 6.2 Apprentissage automatique ( V2) (****) L idée est de garder la même stratégie que dans la partie précédente, mais en tenant compte de la taille de la mise. Il faut donc faire deux tableaux à deux dimensions qui contiennent le nombre de victoires et de défaites en fonction de la probabilité mathématique et de la mise de l adversaire. Vous devez discrétiser la mise, choisissez donc bien la taille de votre tableau. Si vous faites un tableau trop petit, votre information sera peu précise. Si le tableau est trop grand, vous mettrez plus de temps pour avoir une probabilité fiable pour chaque case. 6.3 Utilisation de l apprentissage ( V2) (****) Comme dans la partie précédente, vous devez modifier votre IA pour qu elle utilise les tableaux construits pour choisir si elle se couche ou non. Vous devez aussi lui faire choisir la taille de la mise en fonction de sa probabilité de victoire. 4
7 Jouer pour apprendre Lorsqu un joueur joue au Poker, il ne cherche pas juste à jouer de la manière la plus intéressante sur un coup donné, il cherche aussi à obtenir de l information sur la façon de jouer de son adversaire et ainsi pouvoir prendre de meilleures décisions dans les tours suivants. Il faut donc tenir compte de cette stratégie pour la confection de votre IA. 7.1 Optimisation de l apprentissage (*****) Prenez en compte ce paramètre de la connaissance que le programme a de son adversaire pour choisir comment jouer, de façon à lui permettre de remplir les zones les plus vides du tableau (celles où les probabilités sont donc les moins fiables). 7.2 Enregistrement des données apprises (***** ) Votre intelligence artificielle apprend des données à chaque partie qui correspondent à la façon de jouer de son adversaire. Mais ces données apprises peuvent aussi lui être utiles face à d autres adversaires, surtout en début de partie, lorsqu elle ne connaît pas encore le profil de cet adversaire. Faites une fonction qui stocke dans un fichier texte les données acquises au cours d une partie, et une autre qui charge ses données au lancement du programme, puis modifier l IA pour qu elle utilise ces données. 8 Changement de cartes (*****) Dans une vraie partie de Poker fermé à 5 cartes, les joueurs peuvent changer des cartes. http://fr.wikipedia. org/wiki/poker_ferm%c3%a9 Modifiez votre interface et votre intelligence artificielle pour tenir compte de ce point de règle. 5