How can I improve my hangman game code?

Asked

Viewed 839 times

0

What tips would you give to improve this code of the Python hangman game? In the "course" I’m doing Python I haven’t learned to use string methods yet. It’s a very simple hangman game, with no graphical interface because I don’t know how to do and with 5 words that I used to test. What do you think makes the code better and more compact? Thank you

from random import choice

def imprime(letra, pl):
    #imprime como está o resultado do jogo. Exemplo: c _ _ c l e _ _
    impressao = ''
    for i in range(len(palavra)):
        if palavra[i] not in pl:
            impressao += "%s "%palavra[i]
        else:
            impressao += '_ '
    return impressao

#palavras pré-definidas
palavras = ['chiclete', 'arroz', 'banana', 'feijao', 'nutella']

#escolhe a palavra do jogo
palavra = choice(palavras)

erros = 0
pl = []
#adiciona todas as letras da palavra a uma lista 'pl'
for i in range(len(palavra)):
    pl.append(palavra[i])

#imprime a quantidade de letras da palavra
print("A palavra é: %s"%('_ '*len(palavra)))
print("")
jogo = True
tentativas = []

while jogo:

    letra = input("Digite uma letra ou palavra: ")
    #o usuario digita uma letra ou palavra
    if letra == palavra:
        #verifica se o jogador acertou a palavra, caso sim encerra o programa
        print("Você ganhou. A palavra era %s"%palavra)
        break

    #verifica se a letra escolhida ainda não havia sido escolhida pelo usuario
    while letra in tentativas:
        letra = input("Você já tentou essa letra ou palavra. Digite novamente: ")
    tentativas.append(letra)

    if letra in palavra:
        #se o usuario acertou uma letra, ela é removida da lista 'pl'.
        for i in range(palavra.count(letra)):
            pl.remove(letra)
    else:
        erros += 1
        #se o usuario errar a letra ou palavra, é contabilizado um erro. Com 6 erros o usuario é derrotado.
        if erros == 6:
            print("Você errou pela 6ª vez. Fim de jogo")
            print("Você perdeu")
            break

        print("Você errou pela %iª vez. Tente de novo!"%erros)
    print("A palavra é: ",imprime(letra, pl))
    print("")

    if len(pl) == 0:
        #se a lista 'pl' possuir 0 elementos, então o usuario ganhou
        print("Você ganhou!")
        break
  • for i in range(len(palavra)) you can replace with for letra in palavra and use only letra in place of palavra[i]

  • worked out, thanks.

  • If you can do that with the methods of string, there is the method lower() for that reason.

  • Anderson Carlos, if I’m going to use variables defined outside the function within a function but I’m not going to modify them, do I need to input these variables anyway? For example, in the function "print" I did not modify any variable I called, it was necessary to put it? The variable 'pl', for example

1 answer

3

Displaying the word on the screen

First, let’s do the function that displays the word on the screen, along with the underscores in the letters that should not be displayed. For this, we can do:

def exibir(palavra, tentativas):
    caracteres = (letra if letra in tentativas else '_' for letra in palavra)
    return ' '.join(caracteres)

Thus, the word will be displayed, except for the characters that nay are in tentativas, which shall be replaced by an underscore, _.

exibir('woss', [])  # _ _ _ _
exibir('woss', ['s'])  # _ _ s s
exibir('woss', ['s', 'w'])  # w _ s s
exibir('woss', ['s', 'w', 'o'])  # w o s s

Drawing the word

The draw part which word you did well and have nothing to change:

from random import choice

palavras = ['chiclete', 'arroz', 'banana', 'feijao', 'nutella']
palavra = choice(palavras)

Game logic

We start by defining the amount of user errors and attempts it has made:

tentativas = set()
erros = 0

At this point, I used tentativas as a set, because it will not make sense to have duplicate attempts and the set has optimizations in its access and search in relation to the list. At this point it’s almost like micro-optimization, but there’s a tip for you to study.

For the loop, you don’t need to create a variable just to be true forever, you can use direct the True. As well as you don’t need to print the "word" out of the loop, just do it inside it and just do it once.

while True:
    print('A palavra atual é:', exibir(palavra, tentativas))

    while True:
        tentativa = input('Digite uma letra ou palavra: ').lower()
        if tentativa not in tentativas:
            tentativas.add(tentativa)
            break
        print('Você já fez essa tentativa.')

Note that I used the method lower of string to convert the user input to lowercase always, so we don’t have to worry about it and I used another infinite loop to check the user input, this prevents you from having to do the same input twice in the code.

At this point, we can already check whether the user won or not. This will happen when the word no longer has the character _ or when the user enters the entire word correctly:

if '_' not in exibir(palavra, tentativas) or tentativa == palavra:
    print('Você venceu')
    break

But if the user did not win, we must check if he at least hit a letter or missed, to then count the errors.

if tentativa not in palavra:
    print(f'Você errou! Só te restam {5-erros} tentativas')
    erros += 1

And, finally, finish the game when the user reaches the six unsuccessful attempts.

if erros == 6:
    print('Você perdeu!')
    break

It would look something like this...

from random import choice

def exibir(palavra, tentativas):
    caracteres = (letra if letra in tentativas else '_' for letra in palavra)
    return ' '.join(caracteres)

palavras = ['chiclete', 'arroz', 'banana', 'feijao', 'nutella']
palavra = choice(palavras)

tentativas = set()
erros = 0

while True:
    print('A palavra atual é:', exibir(palavra, tentativas))

    while True:
        tentativa = input('Digite uma letra ou palavra: ').lower()
        if tentativa not in tentativas:
            tentativas.add(tentativa)
            break
        print('Você já fez essa tentativa.')

    if '_' not in exibir(palavra, tentativas) or tentativa == palavra:
        print('Você venceu')
        break

    if tentativa not in palavra:
        print(f'Você errou! Só te restam {5-erros} tentativas')
        erros += 1

    if erros == 6:
        print('Você perdeu!')
        break

See working on Repl.it

Not as minor as its version, but considerably simpler and readable.

Regarding the use of f-string to format a string instead of the operator %, read:

  • Thank you. I don’t understand what Join is for. I also didn’t know it was possible to do a for like this: characters = (letter if letter in attempts Else '_' for letter in word) Thank you very much for the help

  • @Brunoamaral the join unites the values of a sequence in a string using the character as a separator. For example: '+'.join(['1', '2', '3']) would return '1+2+3'.

  • Can you explain this line to me? I still don’t understand this: characters = (letter if letter in attempts Else '_' for letter in word)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.