J’ai fait un exécutable Windows du jeu du pendu réalisé en Python, que vous pouvez trouver sur cette page.
Pou celles et ceux qui souhaitent savoir comment réaliser un tel jeu, voici la démarche que j’ai adoptée.
Le jeu du pendu en Python : le principe
Avant tout, il faut rappeler le principe du jeu. Un mot est choisi au hasard et le joueur doit le deviner en proposant des lettres.
Si la lettre proposée est présente dans le mot, elle s’affiche aux endroits adéquats; sinon, un élément du dessin apparaît.
Il y a 11 éléments sur le dessin. 4 éléments de la potence, 1 corde et 6 élément du pendu lui-même. La personne qui joue ne doit donc pas faire plus de 10 erreurs, la onzième lui étant fatale.
À travers ce principe, on voir alors se dessiner (sans jeu de mots) un semblant de script:
- Choisir au hasard un mot dans une liste.
- Mettre des underscores à la place des lettres.
- Tant que le mot n’est pas trouvé et tant que le nombre d’erreurs est inférieur strictement à 11, demander une lettre.
- Si la lettre est dans le mot, l’afficher aux bons endroits; sinon, incrémenter le nombre d’erreur d’une unité et dessiner un élément du dessin.
Le jeu du pendu : le script Python sans interface graphique
Il faut bien commencer par quelque chose. J’ai toujours commencé mes scripts par leur cœur, c’est-à-dire par ce qui définit réellement le programme.
Je vais donc suivre les points de l’algorithme naturel présenté précédemment.
Pour tout ce qui est programme avec interface graphique, j’ai l’habitude d’utiliser la Programmation Orientée Objet (POO). Cependant, pour simplifier les choses, je ne vais pas faire ça dans cette partie non graphique.
Choisir au hasard un mot dans une liste
Il nous faut une fonction qui retourne un mot en lettres majuscules, pris au hasard dans une liste.
J’ai récupéré sur la page http://www.pallier.org/liste-de-mots-francais.html, le fichier texte suivant :
Il contient 336 531 mots du français (encodés en utf-8) en minuscules. Tous ne sont pas bons à prendre. Ceux avec trait d’union ou ceux à moins de 5 lettres par exemple sont à exclure.
Il y a ici deux façons de raisonner :
- une liste de tous les mots qui nous intéressent (sans trait d’union, avec au moins 5 lettres) est construite;
- une ligne du fichier est choisie au hasard et on vérifie que le mot correspondant rentre dans nos critères.
Dans le programme que j’ai fait, j’ai opté pour la première solution. Cependant, je vais ici vous exposer la seconde, plus rapide.
Voici donc une fonction qui retourne un mot au hasard:
from random import choice from unidecode import unidecode def word(): f = open('mots.txt', 'r' , encoding = 'utf8') contenu = f.readlines() return unidecode( choice(contenu) ).upper().replace('\n','')
Je fais ici appel à deux modules :
- random, et sa fonction choice qui retourne pseudo-aléatoirement un élément de la liste contenu, qui n’est autre que la liste des mots contenus dans le fichier texte;
- unidecode, et sa fonction éponyme qui retourne la chaîne de caractères sans accents.
J’utilise ensuite la méthode upper() pour mettre en majuscules.
De plus, chaque ligne du fichier se termine par “\n”. J’ai donc utilisé la méthode replace() pour supprimer le “\n”.
Mettre des underscores à la place des lettres
On va ici écrire une fonction underscore(mot) retournant une chaîne de caractères où les lettres sont remplacées par des “_” (des underscores). Pour plus de lisibilité, on séparera les underscores avec une espace.
def underscore(mot): r = '_ ' * len( mot ) return r[:-1]
Définie ainsi, la fonction est simple. On répète le motif “_ ” autant de fois qu’il y a de lettres dans le mot. Ne pas oublier l’espace à la fin du motif.
Ensuite, cette chaîne est retournée sans le dernier caractère (qui est une espace et qui ne sert à rien).
Nous verrons plus loin que cette fonction devra être modifiée.
Saisie d’une lettre
def saisie(): lettre = input('Entrez une lettre : ') if len( lettre ) > 1 or ord(lettre) < 65 or ord(lettre) > 122: return saisie() else: return lettre.upper()
La fonction de saisie est simple : un simple input et on retourne la lettre saisie en majuscule. On fait tout de même une vérification afin de voir si la saisie ne contient qu’un caractère et si elle correspond à une lettre de l’alphabet (le “65” correspond au code ASCII de “A” et le “122” à celui de “z”).
La partie principale
On peut imaginer un début de script comme ceci :
mot_a_deviner = word() affichage = underscore( mot_a_deviner ) print( 'Mot à deviner : ' , affichage ) lettre = saisie() if lettre in mot_a_deviner:
Mais au moment de tester si la lettre est dans le mot, un dilemme se présente : que faire ? Il faut que l’affichage change en fonction de la lettre proposée. Nous devons donc changer la fonction underscore(). Elle doit recevoir non pas une lettre en argument, mais une liste de lettres (celles déjà proposées).
Cela donne un script comme ceci:
lettres_deja_proposees = [] mot_a_deviner = word() affichage = underscore( mot_a_deviner ) print( 'Mot à deviner : ' , affichage ) while '_' in affichage: lettre = saisie() if lettre not in lettres_deja_proposees: lettres_deja_proposees += [ lettre ] affichage = underscore( mot_a_deviner , lettres_deja_proposees ) print( 'Mot à deviner : ' , affichage )
en changeant la fonction underscore() ainsi :
def underscore(mot , L = []): r = '' for i in mot: if i in L: r += i + ' ' else: r += '_ ' return r[:-1]
Compter le nombre d’erreurs
Il nous reste en effet à mettre un peu de piment à tout ça en limitant le nombre d’erreurs à 11.
lettres_deja_proposees = [] mot_a_deviner = word() affichage = underscore( mot_a_deviner ) print( 'Mot à deviner : ' , affichage ) nb_erreurs = 0 while '_' in affichage and nb_erreurs < 11: lettre = saisie() if lettre not in lettres_deja_proposees: lettres_deja_proposees += [ lettre ] if lettre not in mot_a_deviner: nb_erreurs += 1 affichage = underscore( mot_a_deviner , lettres_deja_proposees ) print( '\nMot à deviner : ' , affichage , ' '*10 , 'Nombre d\'erreurs maximum :' , 11-nb_erreurs )
Le script complet du jeu du pendu en Python
from random import choice from unidecode import unidecode # un mot au hasard def word(): f = open('mots.txt', 'r' , encoding = 'utf8') contenu = f.readlines() return unidecode( choice(contenu) ).upper().replace('\n','') # remplacement par des underscores def underscore(mot , L = []): r = '' for i in mot: if i in L: r += i + ' ' else: r += '_ ' return r[:-1] # saisie d'une lettre def saisie(): lettre = input('Entrez une lettre : ') if len( lettre ) > 1 or ord(lettre) < 65 or ord(lettre) > 122: return saisie() else: return lettre.upper() # programme principal lettres_deja_proposees = [] mot_a_deviner = word() affichage = underscore( mot_a_deviner ) print( 'Mot à deviner : ' , affichage ) nb_erreurs = 0 while '_' in affichage and nb_erreurs < 11: lettre = saisie() if lettre not in lettres_deja_proposees: lettres_deja_proposees += [ lettre ] if lettre not in mot_a_deviner: nb_erreurs += 1 affichage = underscore( mot_a_deviner , lettres_deja_proposees ) print( '\nMot à deviner : ' , affichage , ' '*10 , 'Nombre d\'erreurs maximum :' , 11-nb_erreurs )
Interface graphique
Nous sommes tous d’accords pour dire que maintenant que nous avons vu l’essentiel, il serait intéressant d’avoir une interface plus sympathique.
J’utilise tkinter pour cela, car bien plus simple que d’autres modules graphiques comme QT5.
Comme mentionné en début d’article, j’utilise la POO : je considère que le jeu est un objet auquel j’attribue des méthodes.
Les abonné·e·s de mathweb.fr trouveront le script dans un fichier zip, contenant aussi le fichier texte ci-dessous:
Je ne parviens pas à trouver le fichier Zip du pendu en poo.
D’avance merci.
Il y a bien un fichier ZIP contenant le fichier source (recherchez à la ligne “2020-09-07”) sur la page indiquée.
PS : si vous souhaitez partager vos codes, merci d’utiliser un autre site que le mathweb (github par exemple). J’ai donc supprimé vos commentaires, qui étaient bien trop indigestes pour ce site (les commentaires ne sont pas un lieu pour y mettre des codes longs). Vous pouvez néanmoins mettre en commentaire un lien vers une page où vous mettriez vos codes.