Pendu en python

Acnologiaf Messages postés 12 Statut Membre -  
Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   -

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.

8 réponses

  1. Utilisateur anonyme
     

    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
  2. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    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
  3. PierrotLeFou
     

    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
  4. Utilisateur anonyme
     

    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
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    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
  7. Utilisateur anonyme
     

    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
  8. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    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
  9. Phil_1857 Messages postés 1883 Date d'inscription   Statut Membre Dernière intervention   169
     

    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