18 - Projet Mastermind

Présentation du jeu

Le Mastermind est un jeu de logique pour deux joueurs, créé en 1970 par Mordecai Meirowitz. L’un des joueurs cache une suite de pions de couleur ; l’autre doit la retrouver, couleurs et ordre compris, en un nombre limité d’essais. À chaque essai, il reçoit des indices qui lui permettent d’éliminer des possibilités.

Plateau de Mastermind : en haut, le code secret jaune, rouge, vert, orange, caché au décodeur ; en dessous, trois essais. Essai 1 : bleu, noir, jaune, rouge, avec deux fiches blanches. Essai 2 : jaune, rouge, bleu, noir, avec deux fiches noires. Essai 3 : jaune, orange, rouge, noir, avec une fiche noire et deux fiches blanches.

Le jeu d’origine utilise 6 couleurs et des combinaisons de 4 pions, à trouver en 10 essais au plus. D’autres versions changent ces nombres : le « Super Mastermind » demande par exemple de trouver 5 pions en 12 essais, avec 8 couleurs.

Règles du jeu

Les deux joueurs ont des rôles différents :

  • le codificateur choisit la combinaison secrète et la place derrière un cache. Il a le droit d’utiliser plusieurs fois la même couleur ;
  • le décodeur propose une combinaison à chaque tour, en posant ses pions sur une nouvelle rangée du plateau.

Après chaque proposition, le codificateur répond avec de petites fiches posées à côté de la rangée :

  • une fiche noire pour chaque pion de la bonne couleur placé au bon endroit ;
  • une fiche blanche pour chaque pion d’une couleur présente dans le code, mais placé ailleurs ;
  • rien pour les pions dont la couleur n’est pas dans le code.

Les fiches ne disent pas à quels pions elles correspondent : c’est au décodeur de le déduire. Sur le plateau ci-dessus, le code est jaune, rouge, vert, orange. À l’essai 3, le jaune est à sa place (une fiche noire), l’orange et le rouge sont dans le code mais pas à leur place (deux fiches blanches), le noir n’y est pas.

La partie s’arrête quand le décodeur a reconstitué le code, ou quand il a utilisé toutes ses rangées sans le trouver.

Dans le programme demandé ci-dessous, l’ordinateur joue le codificateur, et la réponse est plus précise que dans le jeu en bois : elle indique, pion par pion, s’il est bien placé, mal placé ou absent.

Organisation du travail

  1. Le devoir maison de préparation (manipulation de listes, copie de liste, génération aléatoire sans répétition) entraîne les briques dont le projet a besoin.
  2. Télécharger le fichier de départ mastermind_a_faire.py : il contient les constantes, les prototypes des fonctions à écrire et les tests qui permettent de vérifier chaque fonction au fur et à mesure.
  3. Écrire les fonctions dans l’ordre demandé ci-dessous, en décommentant les tests correspondants après chaque fonction.
  4. En cas de blocage, consulter les indications , puis, si cela ne suffit pas, la fiche d’aide .

Le programme demandé

Constantes globales

Nous allons rendre le jeu du Mastermind plus général avec un nombre de couleurs, une longueur de la combinaison secrète et un nombre maximal de combinaisons à proposer paramétrables. Nous utiliserons pour cela les constantes suivantes.

  • Une liste nommée COULEURS contenant les couleurs possibles des pions. Exemple : COULEURS = ["J", "B", "R", "V", "O", "N"] correspond à la version du jeu avec 6 couleurs (jaune, bleu, rouge, vert, orange, noir).
  • Un entier nommé NB_PIONS qui donne le nombre de pions d’une combinaison. Dans la version normale du Mastermind NB_PIONS = 4 et dans le super Mastermind NB_PIONS = 5.
  • Un entier nommé NB_MAX_ESSAIS pour le nombre maximal de combinaisons à proposer. Dans la version normale du Mastermind NB_MAX_ESSAIS = 10 et dans le super Mastermind NB_MAX_ESSAIS = 12.
  • Trois constantes pour représenter les marques de pion bien placé, mal placé ou absent : SYMBOLE_BIEN_PLACE = "#", SYMBOLE_MAL_PLACE = "X", SYMBOLE_ABSENT = "0".

Fonction qui génère aléatoirement une combinaison secrète

Écrire une fonction Python nommée genere_combinaison_secrete() qui va générer aléatoirement une combinaison secrète de longueur NB_PIONS en prenant les couleurs des pions dans la liste COULEURS sans répétitions. La fonction renverra la combinaison sous la forme d’une liste.

Exemple : après combinaison_secrete = genere_combinaison_secrete(), la variable combinaison_secrete peut contenir ["J", "R", "V", "O"].

Fonction qui permet au joueur de saisir une proposition

Écrire une fonction Python nommée saisir_combinaison() qui permet au joueur de saisir une proposition de longueur NB_PIONS en prenant les couleurs des pions dans la liste COULEURS. La fonction renverra la proposition sous la forme d’une liste. Vous pourrez faire saisir les couleurs une par une, ou tout d’un coup. Vous rédigerez la documentation de cette fonction.

Fonction qui transforme une proposition (liste) en chaîne de caractères

Écrire une fonction Python nommée combi_to_str(combinaison) qui permet de convertir la proposition (liste) en une chaîne de caractères. Nous pourrons l’utiliser pour faire afficher la proposition ou la combinaison secrète.

Exemple : combi_to_str(["J", "R", "B", "N"]) doit renvoyer "JRBN".

Fonction qui compte le nombre d’occurrences d’un élément dans une liste

C’est un petit utilitaire qui peut toujours servir : écrire une fonction Python nommée nb_occurrences(element, combinaison) qui compte le nombre de fois où element apparaît dans la combinaison.

Exemples : nb_occurrences("J", ["J", "R", "J", "N"]) doit renvoyer 2 ; nb_occurrences("V", ["J", "R", "J", "N"]) doit renvoyer 0.

Fonction qui trouve l’indice d’un élément dans une liste

Encore un petit utilitaire qui peut toujours servir : écrire une fonction Python nommée trouve(element, combinaison) qui renvoie l’indice (le premier) de l’élément element dans la liste combinaison s’il est présent, et -1 sinon. Vous rédigerez la documentation de cette fonction.

Exemples : trouve("J", ["J", "R", "J", "N"]) doit renvoyer 0 ; trouve("V", ["J", "R", "J", "N"]) doit renvoyer -1.

Fonction qui analyse la proposition et la compare à la combinaison secrète

Écrire une fonction Python nommée evalue_proposition(proposition, secret) qui a pour paramètres une liste proposition qui contient la proposition d’un joueur et une liste secret qui contient la combinaison secrète. Cette fonction renverra une liste liste_reponse construite de manière à marquer les pions bien placés, mal placés et absents.

Exemples :

  • evalue_proposition(["J", "R", "B", "N"], ["J", "R", "V", "O"]) renverra la liste ["#", "#", "0", "0"] car « J » et « R » sont bien placés ;
  • evalue_proposition(["J", "O", "R", "N"], ["J", "R", "V", "O"]) renverra la liste ["#", "X", "X", "0"] car « J » est bien placé, et « O » et « R » sont mal placés.

Remarque. Pour éviter de recompter deux fois les mêmes pions (par exemple en bien placé puis en mal placé, ou lorsqu’il y a des répétitions, dans la proposition ou dans la combinaison), on pourra faire une copie de la proposition et une copie de la combinaison secrète et modifier ces copies au fur et à mesure du comptage pour éliminer les pions déjà comptés.

Fonction qui permet de jouer une manche entière de Mastermind

Écrire une fonction Python nommée manche_de_mastermind() qui permet de jouer une manche de Mastermind. L’ordinateur génère une combinaison secrète, puis, à chaque tour, demande à l’utilisateur de saisir une proposition, l’analyse et répond, jusqu’à ce que la manche soit terminée pour l’une des deux raisons possibles : le joueur a trouvé la combinaison, ou il a perdu car il a atteint son nombre maximum d’essais.

La fonction renverra le nombre d’essais tentés, cela pourra être utilisé en cas de comptabilisation des scores.

Approfondissements possibles

  • Sécuriser la fonction saisir_combinaison() : s’assurer qu’il y a le bon nombre de couleurs, que chaque élément est bien une couleur possible, etc.
  • Autoriser les répétitions dans la combinaison secrète. Pour pouvoir choisir l’une ou l’autre option, on peut définir une variable globale AVEC_REPETITION = True et la modifier au besoin. Modifier la fonction genere_combinaison_secrete() pour qu’elle prenne en compte cette variable globale, et s’assurer que evalue_proposition() supporte la possibilité d’une répétition dans la combinaison secrète.
  • Offrir deux modes pour le résultat de l’évaluation d’une proposition : un mode où l’on annonce globalement le nombre de bien placés et de mal placés sans préciser lesquels, et un mode où l’on précise pour chaque pion comme on vient de le faire. On peut définir une variable globale COMPTAGE_GLOBAL ; la fonction evalue_proposition() peut rester inchangée, mais il faudra modifier manche_de_mastermind() pour qu’elle affiche la réponse en fonction du mode de jeu.
  • Prévoir la possibilité d’enchaîner plusieurs manches et de comptabiliser les scores.
  • Écrire une fonction de menu qui permet de choisir le niveau de difficulté, et ainsi modifier les valeurs des constantes globales (COULEURS, NB_PIONS, NB_MAX_ESSAIS, et éventuellement COMPTAGE_GLOBAL et AVEC_REPETITION).
  • Si vraiment vous avez tout fait, envisager une aide au jeu par l’ordinateur. Il s’agit alors de déterminer toutes les combinaisons possibles, puis à chaque tour de jeu, de ne garder que celles qui donneraient bien la réponse obtenue pour la dernière proposition. On peut alors aider le joueur en lui affichant toutes les possibilités, ou en lui en conseillant une (au hasard) parmi les possibles.