Pendu en python

Fermé
Acnologiaf Messages postés 12 Date d'inscription samedi 21 janvier 2023 Statut Membre Dernière intervention 2 février 2025 - 30 juin 2023 à 13:12
Phil_1857 Messages postés 1872 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 - 6 juil. 2023 à 16:46

Bonjour, je cherche à programmer un pendu en python avec les débuts de codes suivantes:

def jeu():
    mot = "test"
    dev=[]
    n = str(len(mot))
    print("Le mot contient " + n + " lettres.")
    m = input("Quelle lettre ?")
    if m in mot:
        m = (mot.index(m))
        print(mot[m])
        dev.append(m + 1)
        print(dev)
        jeu()
    else:
        print("La lettre " + m + " n'est pas dans le mot.")
        jeu()

jeu()

Le problème se trouve dans le "m = (mot.index(m))" car il ne gère pas les lettres doubles, par exemple , si on rentre le mot "test", cette ligne retournera qu'il s'agit de la première lettre alors qu'il s'agit aussi de la quatrième 

Comment puis-je régler ce problème ?

Merci d'avance.

A voir également:

8 réponses

Utilisateur anonyme
30 juin 2023 à 13:37

Bonjour 

  • tu peux faire une boucle qui va regarder chaque lettre du mot
  • tu peux faire une boucle qui travaille sur la copie du mot, tu y mets tes lignes 7 à 12, puis dans la copie tu places ce qui reste du mot après l'index de la première occurrence 
  • tu peux utiliser les regex

0
Phil_1857 Messages postés 1872 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 168
Modifié le 30 juin 2023 à 13:56

Bonjour,

Moi, j'avais fait un truc du même genre avec enumerate:

display = ['_' for k in range(len(mot))]

while(not end):
    print(display)
    m= input('\nUne lettre : ')
    found = False

    if(m in mot):
        found = True
        inds = [ind for ind, value in enumerate(mot) if value == m]
        for ind in inds: #if m in mot ne suffit pas: il faut traiter les occurences multiples comme 2 e dans lycee
            if(display[ind] == '_'):
                display[ind] = m
            break

    if(not found):
        print("La lettre " + m + " n'est pas dans le mot.")
0
PierrotLeFou
30 juin 2023 à 14:07

Ce n'est pas une bonne idée d'assigner la valeur et la position d'une lettre à la même variable.
D'accord avec phil pour enumerate.
Ce n'est pas grave ici, mais un jeu récursif n'est pas conseillé. On pourrait déborder la pile.

0
Utilisateur anonyme
Modifié le 30 juin 2023 à 18:21

Alors oui la méthode de Phil est très belle.

Mais, s'agissant d'un exercice plutôt simple, sur lequel Acnologiaf peine un peu, je pense que c'est encore hors de sa portée.

Si j'étais prof et que l'on me ramène une solution que l'élève n'aurais pas pu faire lui-même, je lui mettrais une mauvaise note.

Concernant le côté récursif, avec en principe 26 récursions maximum (sauf si le joueur propose 2 fois la même lettre), il ne devrait pas y avoir de dépassement de pile.

Par contre, il va falloir veiller à sortir du mode récursif quand le mot est trouvé, et donc faire en sorte que le jeu sache que c'est gagné.

Ce qui n'est pas le cas pour le moment


0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Phil_1857 Messages postés 1872 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 168
Modifié le 1 juil. 2023 à 10:46

Bonjour,

Oui, c'est vrai que c'est peut-être hors de sa portée

Pour ce qui est de sortir de la boucle, je faisais ceci:

    if(mot == ''.join(display)):
        print('\nGagné en {} essais!'.format(nb_essais))
        end = True

Idem si le nb d'essais atteignait le nb maxi permis ( if(not found): ..... )

0
Utilisateur anonyme
1 juil. 2023 à 19:02

C'est au message de PierrotLeFou que je réagissais.

D'abord.

Ce n'est pas une bonne idée d'assigner la valeur et la position d'une lettre à la même variable.

C'est très juste donc je n'ai rien à redire.

Puis

D'accord avec phil pour enumerate

Sauf que ça n'est pas de son niveau, et là j'explique pourquoi, j'essaye de ne pas donner ce genre de réponse.

Et enfin 

Ce n'est pas grave ici, mais un jeu récursif n'est pas conseillé. On pourrait déborder la pile.

Je n'avais même pas fait attention au fait que la fonction était récursive, là bien vu (si je peux dire).

Mais contrairement à ce qu'il dit, c'est grave puisque le programme de Acnologiaf n'en sort jamais.


0
mamiemando Messages postés 33539 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 19 février 2025 7 828
Modifié le 6 juil. 2023 à 15:50

Bonjour,

Tout d'abord j'aimerais signaler que le pendu est un exercice qu'on voit régulièrement sur le forum donc une petite recherche préalable est toujours une bonne chose.

Préliminaires

Comme python est sensible à la casse (minuscule / majuscule), il est recommandé d'adopter une convention (par exemple ne travailler qu'avec des minuscules ou des majuscules). Dans ce qui suit je suppose qu'on a choisi de travailler avec des minuscules. Une fois cette convention choisie, on peut de manière systématiquement convertir les lettres proposées en minuscules, ce qui évite d'imposer cette contrainte au joueur.

Pour faire cette conversion, on peut utiliser la méthode lower (pour les minuscules) ou upper (pour les majuscules) :

mot = "SeCreT"
print(mot.lower())  # Affiche secret
print(mot.upper())  # Affiche SECRET

Retour à la question initiale

Je suppose ici que mot et propositions suivent la même convention (que des minuscules ou que des majuscules).

La manière la plus simple est de mémoriser les lettres proposées (variable propositions), puis au moment d'écrire un mot (variable mot), d'itérer sur chaque lettre de mot. Si la lettre courante a été proposée, on l'affiche, sinon on écrit _.

def offusquer_mot(mot: str, propositions: set) -> str:
    s = ""
    for a in mot:
        if a in propositions:
            s += a
        else:
            s += "_"
    return s

... qu'on écrirait plutôt ainsi si on connaît bien python :

def offusquer_mot(mot: str, propositions: set) -> str:
    return "".join(a if a in propositions else "_" for a in mot)

Qu'est ce qu'un set ?

Le type set correspond à un ensemble d'éléments distincts.

Dans la fonction précédente, on pourrait parfaitement ce contenter d'une liste (type list), cela n'empêche pas d'utiliser l'opérateur d'appartenance (in). Cependant, un set est plus efficace et plus pratique. En effet, on peut facilement vérifier si l'ensemble des proposition inclue toutes les lettres impliquées dans le mot à découvrir, ce que ne permettra pas une liste.

def tester_victoire(mot: str, propositions: set) -> bool:
    return set(mot) <= propositions

Si on rassemble tous ces éléments, voici à quoi peut ressembler le jeu :

def offusquer_mot(mot: str, propositions: set) -> str:
    s = ""
    for a in mot:
        if a in propositions:
            s += a
        else:
            s += "_"
    return s

def offusquer_mot(mot: str, propositions: set) -> str:
    return "".join(a if a in propositions else "_" for a in mot)

def tester_victoire(mot: str, propositions: set) -> bool:
    return set(mot) <= propositions

def saisir_lettre(message) -> str:
    while True:
        proposition = input(message)
        if len(proposition) != 1:
            print("Vous ne devez saisir qu'un caractère")
        elif not ('a' <= proposition.lower() <= 'z'):
            print(f"'{proposition}' n'est pas une lettre")
        else:
            break
    return proposition

def jeu(mot: str, nombre_tours: int = 10) -> bool:
    propositions = set()
    mot = mot.lower()
    for tour in range(1, nombre_tours + 1):
        proposition = saisir_lettre(
            f"[{tour}/{nombre_tours}] Saisir une lettre minuscule ? "
        )
        propositions.add(proposition.lower())
        print(offusquer_mot(mot, propositions))
        if tester_victoire(mot, propositions):
            print(f"Victoire, le mot était \"{mot}\"")
            return True
    print(f"Défaite, le mot était \"{mot}\"")
    return False

jeu("test")

Bonne chance

0
Phil_1857 Messages postés 1872 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 168
6 juil. 2023 à 16:46

Bonjour,

Une version en mode console mais avec un petit graphique:

import os
import random
import colorama
colorama.init()

POS = lambda x,y: '\033[{};{}H'.format(x,y) #"escape sequence" pour placer le curseur sur ligne/colonne données
failures_nb, tries_nb = 0, 0
end, found = False, True
display = []
sketch = {0:[5,50,'_'], 1:[5,52,'_'], 2:[5,51,'|'], 3:[4,51,'|'], 4:[3,51,'|'], 5:[2,51,'_'], 6:[2,52,'_'],
    7:[2,53,'_'], 8:[3,52,'/'], 9:[3,54,'|'], 10:[4,54,'o']}
words = ['voiture','ordinateur','poker','stylo','lycee','trousse','spatule', 'souris', 'menthe','seisme']

print('\n***** Jeu du pendu *****\n')
word = random.choice(words)

input('''Choix  d'un mot au hasard ... appuyer sur Entrée pour continuer''')
display = ['_' for k in range(len(word))]

os.system('cls')
print('\n***** Jeu du pendu *****')
while(not end):
    print('{}{}'.format(POS(3,1),' '.join(display)))
    letter = input('\nUne lettre : ')
    tries_nb += 1
    found = False

    if(letter in word):
        found = True
        inds = [ind for ind, value in enumerate(word) if value == letter]
        for ind in inds: #if letter in word ne suffit pas: il faut traiter les occurences multiples comme 2 e dans lycee
            if(display[ind] == '_'):
                display[ind] = letter
                break

    if(not found):
        failures_nb +=1 #lettre pas dans le mot: on commence a dessiner le pendu ...
        for i in range(failures_nb): print(POS(sketch[i][0],sketch[i][1])+sketch[i][2])

        if(failures_nb == len(sketch)):
            print('''{}Perdu ! C'était {}'''.format(POS(5,1),word))
            end = True

    if(word == ''.join(display)):
        print('{}{}\n\nGagné en {} essais!'.format(POS(3,1),' '.join(display),tries_nb))
        end = True
0