Vous devrez utiliser l'interface TPLab pour envoyer vos TP aux encadrants de TP.
La note ne valide pas seulement le résultat de votre programme, mais également son style :
Vérifiez ces points avant de demander à votre intervenant de valider votre code.
Travailler avec :
Pour ouvrir un fichier fichier.txt
en lecture, il suffit de faire
f = open("fichier.txt")
Ceci permet d'initialiser un objet de type "fichier". (Si le fichier n'existe pas, l'expression open("fichier.txt")
provoque une erreur.
On peut récupérer une ligne d'un fichier texte avec f.readline()
. Des appels successifs à cette méthode permettent de récupérer des lignes successives.
Attention : lorsqu'il n'y a plus de lignes dans le fichier, la méthode f.readline
renvoie la chaîne de caractères vide. Dans tous les autres cas, la chaîne de caractères contient un saut de ligne ('\n'
) final. Pour supprimer ce saut de ligne, ainsi que tous les autres caractères blancs (espaces ou tabulations) en début ou fin de ligne, il faut utiliser la méthode "strip
" :
>>> f = open("test.txt")
>>> premiere_ligne = f.readline()
>>> premiere_ligne = premiere_ligne.strip()
Utilisez la fonction open
et la méthode readline
avec une boucle while
pour compter le nombre de lignes dans un fichier texte.
Vous pouvez par exemple utiliser le fichier littre.txt qui contient exactement 73192 lignes.
Si vous êtes sous Windows et que vous avez des problèmes avec les accents, il est possible de spécifier l'encodage des accents lorsque vous ouvrez le fichier. Il suffit de remplacer la ligne
f = open("littre.txt")
par
f = open("littre.txt", encoding="UTF-8")
Les dictionnaires ressemblent un peu aux tableaux, mais les cases ne sont pas numérotées par des entiers. Par exemple :
jours = { 'janvier': 31, 'février': 28, 'mars':31, 'avril':30, 'mai':31, 'juin':30, 'juillet':31, 'aout':31, 'septembre':30, 'octobre':31, 'novembre':30, 'decembre':31 }
On peut accéder à une case de deux manières :
jours["janvier"]
,
get
: jours.get("janvier")
.
L'intérêt de la méthode get
est que l'on peut préciser une valeur à utiliser si la case n'existe pas. (La première méthode provoque une erreur si la case n'existe pas, et la seconde renvoie None
si la case n'existe pas et que l'on n'a pas préciser de valeur par défaut.) Par exemple :
>>> print(jours["january"]) Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'january' >>> print(jours.get("january")) None >>> print(jours.get("january", 0)) 0
Écrivez une fonction nb_jours
qui prend en argument une liste de mois (des chaînes de caractères) et renvoie le nombre de jours total de ces mois. Si un mois est invalide, on ne compte pas de jours :
>>> print(nb_jours([])) 0 >>> print(nb_jours(['mars', 'avril'])) 61 >>> print(nb_jours(['mars', 'april'])) 31 >>> print(nb_jours(['avril', 'février', 'novembre', 'octobre', 'aout', 'mai', 'juillet', 'janvier', 'juin', 'mars', 'septembre', 'decembre'])) 365
Le but du jeu du pendu est de découvrir un mot en devinant ses lettres. L'objectif de ce TP est de pouvoir jouer contre l'ordinateur. Pour cela, on va partir d'un fichier qui contient tous les mots du célèbre dictionnaire d'Émile Littré.
Pour les questions qui suivent, vous pourrez utiliser le fichier littre.txt qui contient les 73192 mots du dictionnaire « Littré ». Ce fichier contient un mot par ligne, et en voici un extrait:
ABAQUE ABAS ABASOURDI ABASOURDIR ABAT ABATAGE ABATANT ABATELLEMENT ABATIS ABATTABLE
La première étape consiste à récupérer tous les mots du dictionnaire. Compléter le code de la fonction "lire_mots
" qui prend le nom du fichier en paramètre.
def lire_mots(fichier): """fonction qui récupère la liste des mots dans un fichier paramètre - fichier, de type chaîne de caractère : nom du fichier contenant les mots (un par ligne) retour : liste de chaîne de caractères """ ...
Pour ajouter des valeurs dans une liste, il est beaucoup plus rapide de faire
liste.append(nouvelle_valeur)
plutôt que
liste = liste + [nouvelle_valeur]
La raison est que dans le second cas, la liste est recopiée. Comme nous allons récupérer les 70000 mots du Littré, la différence entre les deux variantes serait (très) visible.
Pendant une partie, on représentera le mot par une liste de caractères. Sa taille sera le nombre de lettres du mots à trouver, et les lettres inconnues seront remplacées par le caractère "_
".
Remarque : pour éviter de tester les minuscules / majuscules, vous pouvez toujours convertir un caractère (ou une chaîne de caractères) en majuscules avec
c = c.upper()
Écrivez la fonction test_lettre
:
def test_lettre(mot, etat, c): """fonction qui vérifie si une lettre apparait dans un mot, et lorque c'est le cas, ajoute les lettres correspondantes dans l'état. paramètres : - mot, de type chaîne de caractères, - etat, de type liste de caractères : les lettres inconnues sont représentées par des '_'. Cette liste a la même longueur que le paramètre mot, - c, de type caractère : la lettre proposée. retour : "True" si la lettre est présente dans le mot, et False sinon. L'état est mis à jour en remplaçant les "_" correspondant à la lettre trouvée. """ ...
Pour ceci, le plus simple est de parcourir les caractères de la chaîne mot
:
c
passé en argument, on continue
c
passé en argument, le test réussit (la fonction devra donc renvoyer True
) et on remplace le '_'
correspondant dans la liste etat
.
Attention, comme le mot peut contenir plusieurs fois la même lettre, il ne faut pas s'areter à la première occurence de c
qu'on trouve !
Voici un exemple d'execution :
mot = "CANARI" etat = [ "C", "_", "_", "_", "R", "I"] if test_lettre(mot, etat, "a"): print("Bravo !") else: print("Dommage...") print("mot :", " ".join(etat))
devra afficher
Bravo ! mot : C A _ A R I
On peut maintenant écrire une première version du jeu du pendu :
etat
" avec des "_
",
Pour tirer un mot au hasard, il suffit de récuperer la liste de tous les mots, et de tirer un numéro de case au hasard avec la fonction randint
. N'oubliez pas de faire un
from random import randint
Voici un exemple de partie :
>>> pendu_version1("littre.txt") _ _ _ _ _ _ _ _ Vous pouvez faire encore 8 erreurs. Entrez une lettre, suivie d'un saut de ligne : e Dommage... _ _ _ _ _ _ _ _ Vous pouvez faire encore 7 erreurs. Entrez une lettre, suivie d'un saut de ligne : a Bravo ! _ A _ _ A _ _ _ Vous pouvez faire encore 7 erreurs. Entrez une lettre, suivie d'un saut de ligne : l Dommage... _ A _ _ A _ _ _ Vous pouvez faire encore 6 erreurs. Entrez une lettre, suivie d'un saut de ligne : ... ... Perdu... Le mot secret était 'RAMPANT'.
Écrivez la procédure pendu_version1
. Cette procédure prend en argument le nombre maximal d'erreurs autorisées. Si cette valeur n'est pas donnée, votre procédure utilisera la valeur par défaut de 8
.
La partie précédente ne prenait pas les accents en compte : si la lettre proposée est "e
", il faut en fait vérifier si le mot contient des "é
", "è
", "ê
" ou "ë
". D'autre part, le français contient deux lettre doubles : le "æ
" et le "œ
. Lorsque la lettre proposée est "e
", il faut donc aussi vérifier si le mot contient des "æ" ou "œ".
Pour gérer tout ça, nous allons utiliser un dictionnaire qui associe aux caractères ASCII les caractères accentués correspondants.
correspondance = { 'A': 'AÀÄÂÆ', 'C': 'CÇ', 'E': 'EÊÈÉËÆŒ', 'I': 'IÎÏ', 'O': 'OÔÖŒ', 'U': 'UÙÜÛ' }
Notez en particulier que les lettres doubles ont deux lettres correspondantes.
Écrivez une fonction test_lettre_version2
qui prend les accents et lettres doubles en compte.
Pour ceci, il suffit de modifier la fonction test_lettre
en modifiant le test qui vérifie si le ième caractère de mot
est égal à c
en un test qui vérifie si le ième caractère du mot apparait dans la chaîne contenant toutes les variantes du c
. (Attention, certains caractères n'ont aucune variante et n'apparaissent donc pas dans le dictionnaire correspondance
.)
Voici un exemple d'execution :
mot = "DÉSŒUVRER" etat = [ "D", "_", "_", "_", "_", "V", "R", "_" , "R" ] if test_lettre(mot, etat, "e"): print("Bravo !") else: print("Dommage...") print("mot :", " ".join(etat))
devra afficher
Bravo ! mot : D É _ Œ _ V R E R
Programmez maintenant la procédure pendu_version2
similaire à pendu_version1
, mais qui prend les accents et lettres doubles en compte.
Votre procédure pendu_version2
est identique à votre procédure pendu_version1
, sauf qu'elle utilise test_lettre_version2
...
Nous allons améliorer la version précédente du jeu en ajoutant :
>>> pendu_version3("littre.txt") _ _ _ _ _ _ _ _ Vous pouvez faire encore 8 erreurs. Il y a encore 11595 mots possibles... Entrez une lettre, suivie d'un saut de ligne : e Bravo ! É _ _ _ _ _ _ E Vous pouvez faire encore 8 erreurs. Il y a encore 196 mots possibles... Entrez une lettre, suivie d'un saut de ligne : a Bravo ! É _ _ _ _ A _ E Vous pouvez faire encore 8 erreurs. Il y a encore 46 mots possibles... Entrez une lettre, suivie d'un saut de ligne : l Dommage... É _ _ _ _ A _ E Vous pouvez faire encore 7 erreurs. Il y a encore 46 mots possibles... Entrez une lettre, suivie d'un saut de ligne : p Bravo ! É _ _ _ P A _ E Vous pouvez faire encore 7 erreurs. Il y a encore 5 mots possibles... Entrez une lettre, suivie d'un saut de ligne : e Vous avez déjà proposé cette lettre... É _ _ _ P A _ E Vous pouvez faire encore 7 erreurs. Il y a encore 5 mots possibles... Entrez une lettre, suivie d'un saut de ligne : e Vous avez déjà proposé cette lettre... ... Perdu... Le mot secret était 'ÉTOUPAGE'.
Commencez par écrire la fonction :
def mots_nb_lettres(mots, n): """fonction qui renvoie la liste des chaînes d'une taille donnée dans une liste paramètres : - mots, de type liste de chaînes de caractères - n, de type entier retour : liste de chaînes de caractères: tous les éléments de mots qui ont la taille n """
Cette fonction vous permettra de savoir combien de mots sont possible au début d'une partie de pendu : il suffit de garder les mots de même taille que le mot secret.
Écrivez la procédure pendu_version3
et testez la. N'oubliez pas de
Note : pour pouvoir compter le nombre de mots restants qui sont compatibles avec les lettres devinées, il est conseillé d'écrire des fonctions auxiliaires :
def contient_lettre(mot, c): """fonction qui renvoie True ou False suivant qu'une chaîne contient un caractère. paramètres : - mot, de type chaîne de caractères - c, de type caractère retour : booléen """ .... def mots_sans_lettre(mots, c): """fonction qui renvoie la liste des éléments d'une liste contenant un caractère donné paramètres : - mots, de type liste de chaînes de caractères - c, de type caractère retour : liste de chaîne de caractères """ ... def mots_avec_lettre(mots, c): """fonction qui renvoie la liste des éléments d'une liste qui ne contiennent pas un caractère donné paramètres : - mots, de type liste de chaînes de caractères - c, de type caractère retour : liste de chaîne de caractères """ ...
Ces fonctions vous permettront de mettre à jours la liste des mots possible suivant que la lettre proposée était présente ou pas dans le mot secret.
Il serait possible de faire une version graphique du jeu du pendu afin de pouvoir réellement dessiner le pendu. Pour faire plus simple, nous allons faire une version en "ASCII art". Voici un exemple de partie possible :
-------------- | | | | | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ _ _ _ Vous pouvez faire encore 7 erreurs. Il y a encore 10232 mots possibles... Entrez une lettre, suivie d'un saut de ligne : a Dommage... -------------- | | | | | | | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ _ _ _ Vous pouvez faire encore 6 erreurs. Il y a encore 5037 mots possibles... Entrez une lettre, suivie d'un saut de ligne : e Bravo ! -------------- | | | | | | | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ É _ É Vous pouvez faire encore 6 erreurs. Il y a encore 28 mots possibles... Entrez une lettre, suivie d'un saut de ligne : l Dommage... -------------- | | | | | / \ | \_/ | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ É _ É Vous pouvez faire encore 5 erreurs. Il y a encore 26 mots possibles... Entrez une lettre, suivie d'un saut de ligne : t Dommage... -------------- | | | | | / \ | \_/ | | | | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ É _ É Vous pouvez faire encore 4 erreurs. Il y a encore 17 mots possibles... Entrez une lettre, suivie d'un saut de ligne : p Dommage... -------------- | | | | | / \ | \_/ | |__ | | | | | /|\ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ _ _ _ _ É _ É Vous pouvez faire encore 3 erreurs. Il y a encore 9 mots possibles... ... ...
Pour pouvoir afficher le pendu, nous allons utiliser une fonction auxiliaire :
def affiche_pendu(n=10): """procédure qui affiche le pendu en fonction du nombre d'erreurs paramètre : - n, de type entier """
Une manière de faire est d'initialiser deux chaînes de caractères : (notez le r
précédent les trois guillemets : il permet de ne pas avoir besoin d'échapper les caractères \
présents dans les chaînes)
pendu_final = r""" -------------- | | | | | / \ | \_/ | __|__ | | | | | / \ /|\ / \ / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ """ pendu_numero = r""" -------------- | 1 | 1 | 2 2 | 222 | 55344 | 3 | 3 | 6 7 /|\ 6 7 / | \ / | \ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ """
La première contient les caractère que l'on doit afficher, et la seconde (de même taille) indique quels caractères doivent être affichés pour un nombre d'erreurs données :
2
, 3
, 4
, 5
, 6
ou 7
,
6
ou 7
,
Écrivez la procédure affiche_pendu
ainsi que la procédure pendu_version4(dictionnaire)
correspondante. (Le nombre d'erreurs autorisées est forcément 7.)
Lorsqu'on dessine le pendu, le nombre d'erreurs maximal est forcément 7. On peut modifier ceci en commençant à dessiner la potence.
Écrivez un procédure affiche_pendu
qui permet de commencer à afficher la potence.
Écrivez une procédure pendu_version5(dictionnaire, nb_erreurs)
correspondante qui permet de choisir un nombre d'erreurs maximal compris entre 7 (on ne dessine que le pendu) et 11 (on dessine les différents morceaux de la potence).