How can I improve my gallows game code?

What tips would you give to improve this code of the gallows game in Python? In the Python "course" I'm doing I haven't learned how to use the string methods yet. It is a very simple gallows game, without graphical interface because I do not know how to do and with 5 words that I used to test. What do you think da to improve the code and make it 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
Author: Woss, 2018-09-12

1 answers

Displaying the word on screen

First, let's make 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)

This will display the word, except for characters that are not in tentativas, which will 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 will be the word you did well and did not have the what 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 the attempts he made:

tentativas = set()
erros = 0

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

For the loop, you don't have to create a variable just to be true always, you can directly use the True. Just as you do not need to print the "word" outside the loop, do it only inside it and do it only 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.')

See that I used the lower method 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 input from the user, this prevents you from having to do the same input twice in code.

At this point, we can already check whether the user won or not. This will occur 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 made a mistake, to then account for the errors.

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

And finally end the game when the user reach the six unsuccessful attempts.

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

It would be more or less like that...

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 smaller as its version, but considerably simpler and more readable.

As for using f-string to format a string instead of the % operator, read:

 3
Author: Woss, 2018-09-12 20:46:43