Algo. et prog. 2 en
Logo de Python
Arnaud COUTURIER - Python 3.10

✏️ TP 10 - Jeu du pendu niv.1 ✔️

Dans les TP suivants on va créer le jeu du pendu:

Voici les critères:

  1. Permettre à l'utilisateur de gérer l'ensemble des mots:
    • voir l'ensemble des mots disponibles pour jouer
    • ajouter des nouveaux mots à l'ensemble existant. Un même mot ne peut être présent plusieurs fois dans l'ensemble.
    • suppression de mots de l'ensemble
  2. Les modifications de l'ensemble des mots doivent être persistantes, ce qui signifie qu'elles restent si on quitte et relance le programme.
  3. Lorsqu'on joue, on voit l'état d'avancement du "pendu" par un dessin.
  4. Tant que je le joueur est en vie et réussit, les mots lui sont proposés une seule fois chacun et dans un ordre aléatoire. Quand tous les mots ont été devinés, le joueur est déclaré vainqueur. Quand le joueur est pendu, il a perdu et revient automatiquement au menu principal.
  5. Le jeu garde en mémoire le meilleur score du joueur et l'affiche dans le menu principal, mais ce meilleur score n'est pas persistant.
  6. Certains messages (quand le joueur a perdu et gagné par exemple) sont affichés pendant un temps (2 ou 3 secondes), puis automatiquement effacés, et la logique du jeu se poursuit.
  7. Les majuscules doivent toujours être ignorées, c'est-à-dire:
    • insérer un nouveau mot en majuscule, l'enregistre quand même en minuscule
    • pendant le jeu, même si un mot contient des majuscules, si le joueur choisit la minuscule correspondate, ça fonctionne
    • pendant le jeu, même si un mot contient des majuscules, il est affiché en minuscules au joueur

Type set

Vous aurez besoin de lire la documentation concernant ce type de donnée.

Mode très difficile

Pour ceux qui veulent du challenge reproduisez le programme en utilisant votre propre façon de faire. Ne suivez pas les questions qui suivent, ne lisez rien de plus ci-dessous, ni dans les TP suivants.

Mode difficile

A ce niveau, faites par vous-même, mais vous pouvez vous aider des quelques pistes suivantes: (attention, une fois que vous les avez lues, le niveau "très difficile" ci-dessus devient en conséquence non jouable pour vous)

Vous aurez besoin de deux modules non vus en cours: time et random. Cherchez la doc de la fonction sleep() du module time ainsi que choice() dans le module random.

Vous pourriez aussi avoir besoin des méthodes rsplit() et lower() des str.

Vous pouvez passer d'une liste (type list) à un ensemble (type set) avec la fonction list() (qui est en fait le constructeur de la classe list), et inversement avec la fonction set(). Regardez dans la doc pour plus de détails.

Pour l'affichage des dessins du pendu, vous pouvez utiliser les triples quotes ("""), elles permettent d'écrire des commentaires sur plusieurs lignes, MAIS AUSSI des chaînes sur plusieurs lignes. Vous pouvez aussi utiliser certains caractères spéciaux pour former les dessins, sur Windows vous pouvez les avoir grâce à l'application intégrée "Table des caractères".

Mode normal

Faites toutes les questions dans l'ordre, jusqu'à la fin du dernier niveau (le 3). Voici ce que vous obtiendrez à la fin de ce niveau:

lorsque le joueur gagne

lorsque le joueur perd

Question 1

On va commencer par écrire quelques fonctions qui vont nous faciliter la vie lorsqu'on écrira le code de la logique du jeu en lui-même.

Écrire une fonction mot_est_deviné() qui va permettre de dire si oui ou non un mot est deviné, à partir de toutes les lettres qui ont été demandées par un jouer. La fonction prend 2 paramètres:

  1. un mot que le joueur est censé deviner, de type str
  2. un ensemble (donc de type set) de lettres (des str de longueur 1), qui correspond à toutes les lettres qu'un joueur aurait demandées. Pourquoi un ensemble plutôt qu'une liste? Pour éviter facilement les doublons, un set interdit les doublons.

La fonction retourne un bool: vrai si le mot a été entièrement deviné, c'est-à-dire toutes ses lettres ont été demandées par le joueur, faux sinon.

Testez que votre fonction fonctionne avec quelques appels.


					# Question 1
					def mot_est_deviné(mot_à_deviner, lettres_à_révéler_set):
						for lettre in mot_à_deviner:
							if lettre not in lettres_à_révéler_set:
								return False
						return True
				

Question 2

On a besoin d'une seconde fonction pour pouvoir facilement afficher les mots au joueur pendant le jeu. Chaque lettre du mot est soit:

  • cachée si le joueur n'a pas encore demandé la lettre en question. Une lettre cachée est affichée avec le caractère underscore "_".
  • soit est affichée si le joueur l'a demandée auparavant

Afficher un espace entre chaque lettre (cachée ou non) pour bien les différencier visuellement.

Ecrire la fonction afficher_mot(), qui prend les mêmes 2 paramètres que la fonction de la question précédente. Elle ne renvoie aucun résultat. Lorsqu'on l'appelle, elle affiche dans la console le mot avec les bonnes lettres révélées ou pas.

Testez que votre fonction fonctionne avec quelques appels.


					# Question 1
					def mot_est_deviné(mot_à_deviner, lettres_à_révéler_set):
						for lettre in mot_à_deviner:
							if lettre not in lettres_à_révéler_set:
								return False
						return True


					# Question 2
					def afficher_mot(mot_à_deviner, lettres_à_révéler_set):
						str_à_afficher = ""
						for lettre in mot_à_deviner:
							if lettre in lettres_à_révéler_set:
								str_à_afficher += lettre + " "
							else:
								str_à_afficher += "_ "
						print(str_à_afficher)
				

Question 3

Dans le contexte global, c'est-à-dire en dehors de toute fonction, on va écrire la logique du jeu: c'est-à-dire la boucle principale, son initialization avant qu'elle démarre et une éventuelle suite après la boucle:

  • Le jeu à deviner est toujours le même pour le moment.
  • Le joueur dispose de 3 essais, ce qui correspond à sa vie, chaque lettre demandée qui n'existe pas dans le mot lui enlève un essai.
  • Lorsque le nombre d'essais tombe à zéro, le joueur a perdu, le mot lui est révélé, et le programme se termine.
  • Lorsque le joueur a trouvé le mot, on le félicite, car il/elle a gagné, on affiche le mot entier et le programme se termine.

Stockez les lettres que le joueur demande dans un set, et utilisez les 2 fonctions précédentes pour vous aider.

Vérifiez que votre jeu fonctionne.


					# Question 1
					def mot_est_deviné(mot_à_deviner, lettres_à_révéler_set):
						for lettre in mot_à_deviner:
							if lettre not in lettres_à_révéler_set:
								return False
						return True


					# Question 2
					def afficher_mot(mot_à_deviner, lettres_à_révéler_set):
						str_à_afficher = ""
						for lettre in mot_à_deviner:
							if lettre in lettres_à_révéler_set:
								str_à_afficher += lettre + " "
							else:
								str_à_afficher += "_ "
						print(str_à_afficher)


					# Question 3
					mot_à_deviner = "bonjour"
					essais_restants = 3
					ensemble_lettres_à_révéler = set()
					# Tant que le mot en cours n'est pas deviné et que le joueur a encore des essais à jouer
					while not mot_est_deviné(mot_à_deviner, ensemble_lettres_à_révéler) and essais_restants > 0:
						afficher_mot(mot_à_deviner, ensemble_lettres_à_révéler)
						print("Vie restante:", essais_restants)
						lettre = input("Lettre: ")
						ensemble_lettres_à_révéler.add(lettre)
						if lettre not in mot_à_deviner:
							essais_restants -= 1

					if essais_restants <= 0:
						print("Perdu. Le mot est:", mot_à_deviner)
					else:
						print("Gagné! Le mot est:", mot_à_deviner)
				

Question 4

Maintenant que le jeu dans sa version la plus simple fonctionne, on va l'augmenter petit à petit pour le rendre intéressant.

On va commencer par proposer un mot (potentiellement) différent chaque fois que le jeu est lancé. Pour cela créez dans votre code, avant la boucle principale, un ensemble (et pas une liste!) qui contient tous les mots que le jeu peut proposer au joueur, pour commencer inutile d'en ajouter trop, 3 mots suffisent.

Puis avant de jouer, le mot à deviner doit être choisi au hasard parmis l'ensemble des mots potentiels. À part ça, le déroulement du jeu reste le même.

Comment choisir un mot au hasard? Vous avez la fonction choice() dans le module random. Malheureusement la fonction choice ne peut pas fonctionner sur un set, car elle a besoin d'une séquence, et les ensembles ne sont pas des séquences puisqu'il n'y a pas de notion d'ordre des éléments dans un ensemble. Néanmoins, vous pouvez facilement transformer un set en list en passant votre ensemble en paramètre de la fonction list(), et la liste qui contient les mêmes éléments que l'ensemble sera retournée en résultat.

Vérifiez que le mot change de façon aléatoire à chaque lancement du programme. Aléatoire ne signifie pas différent à chaque fois, il est donc possible que le même mot soit proposé plusieurs fois de suite. Plus il y a de mots possibles, et moins ils ont de chances de sortir 2 fois de suite.


					# Question 1
					def mot_est_deviné(mot_à_deviner, lettres_à_révéler_set):
						for lettre in mot_à_deviner:
							if lettre not in lettres_à_révéler_set:
								return False
						return True


					# Question 2
					def afficher_mot(mot_à_deviner, lettres_à_révéler_set):
						str_à_afficher = ""
						for lettre in mot_à_deviner:
							if lettre in lettres_à_révéler_set:
								str_à_afficher += lettre + " "
							else:
								str_à_afficher += "_ "
						print(str_à_afficher)


					# Question 4
					import random

					tous_les_mots = {"bonjour", "salut", "voiture"}
					mot_à_deviner = random.choice(list(tous_les_mots))
					essais_restants = 3
					ensemble_lettres_à_révéler = set()
					# Tant que le mot en cours n'est pas deviné et que le joueur a encore des essais à jouer
					while not mot_est_deviné(mot_à_deviner, ensemble_lettres_à_révéler) and essais_restants > 0:
						afficher_mot(mot_à_deviner, ensemble_lettres_à_révéler)
						print("Vie restante:", essais_restants)
						lettre = input("Lettre: ")
						ensemble_lettres_à_révéler.add(lettre)
						if lettre not in mot_à_deviner:
							essais_restants -= 1

					if essais_restants <= 0:
						print("Perdu. Le mot est:", mot_à_deviner)
					else:
						print("Gagné! Le mot est:", mot_à_deviner)