Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
434 views
in Technique[技术] by (71.8m points)

Hangman with Python. ( version: 3.9.1 )

So I was trying to create Hangman with Python and ran into a problem. The problems are as follows:

  1. The loop seems to be an infinite loop ( while loop ).
  2. Words with spaces are not concatenating in order for example "Strawberry Shakes" seems to be "Stwraberry Shaeks" or something like that.

I'm pretty new to python ( like a week or so ) and haven't yet grasped the language properly yet. I would appreciate any help. Thank you in advance.

The code goes like this:

import random 
word_list = {
    "Animals" : "ORANGUTAN",
    "Animals" : "GIRAFFE",
    "Animals" : "ELEPHANT",
    "Animals" : "CHEETAH",
    "Food & Drinks" : "ROASTED BEEF SANDWICH",
    "Food & Drinks" : "MAC AND CHEESE",
    "Food & Drinks" : "VIRGIN MOJITO",
    "Food & Drinks" : "STRAWBERRY SHAKE",
    "Brands" : "SAMSUNG",
    "Brands" : "APPLE",
    "Brands" : "CALVIN KLEIN",
    "Brands" : "JOCKEY" }

key_list = ["Animals", "Food & Drinks", "Brands"]

key_name = random.choice(key_list) 
guess_word = word_list.get(key_name)
 
print(f'{key_name} ({len(guess_word)} letter word)')

letter_list = [] 
answer = "" 
chances = 0 
already_inputted = ""

while answer.join(letter_list) != guess_word or chances < 5:

    index = 0
    guesses = input('Enter a letter as a guess: ')

    if already_inputted.__contains__(guesses):
        print('The letter is already guessed')

    elif guess_word.__contains__(guesses):
        for letter in guess_word:
            if letter == guesses:
                letter_list.insert(index, guesses)
            index += 1
    
    else:
        chances += 1

    already_inputted += guesses

    print(f'{letter_list}
chances = {5 - chances}
already guessed = {already_inputted}')

if chances == 5:
    print(f"You lost! The word was {guess_word}")

else:
    print("You win!")

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You had a really great start but had a few bugs here and there. I will go step by step and explain each one and finally provide you with the modified code. Btw, if I replace anything, I will comment it out so you can see what the difference is.

Variable Refactor

This is more a personal thing than a bug. When your user sends an input, you stored in a variable called guesses. I just changed it to guess because it makes more sense that way. Things like this don't affect your code but they do help make your code easier to read, and thus debug.

Fixing Jumbled Words*: Fixing letter_list

Whenever the player gets a letter right, you used the letter_list.insert(index, guess) to update the letters in the game. However, you initialized your list as an empty array []. When python uses the insert function, it tries its best to insert the letter at the right position. However, if the array is too small, then it just enters the element at the end of the array.

Here's an example (using the word STRAWBERRY SHAKE):

letters_list = ["T","R"]
letters_list.append(0, "S")    #letters_list = ["S", "T", "R"]
letters_list.append(11, "S")   #letters_list = ["S", "T", "R", "S"] because there are only three elements

See how it just added the letter? The solution, is to fill your list with empty "_"s and then replace the value when the user guesses correctly. Like this:

letter_list = ["_"]*len(guess_word)    #Creates dashes for however many letters the word has
...
elif guess_word.__contains__(guess):
    for letter in guess_word:
        if letter == guess:
            #Changed to update list value instead of insert
            #letter_list.insert(index, guess)
            letter_list[index] = guess
        index += 1

Interestingly, the dashes also make the game look nicer. Here is how it looks now:

Enter a letter as a guess: B
['_', '_', 'C', '_', 'E', '_']
chances = 0

Fixing the Infinite Loop: Adding a Counter and Fixing the While conditions

Counter Variable

To loop the program you started with while answer.join(letter_list) != guess_word or chances < 5. The issue with the answer.join part is that the order that a player enters the words might not be the same as the actual word itself. For example, if I guessed "JOCKEY" in this order: ['O', 'J', 'K', 'C', 'Y', 'E'], the program would compare the words "OJKCYE" and "JOCKEY" and claim that they are not the same.

To fix this, I added a counter variable called letters_left that keeps track of how many correct letters we need to guess in order to get solve the puzzle. Every time the user guesses a proper letter, I subtract letters_left by 1.

To create letters_left I used len(set(letters_left)). A set() in python is basically a list, but without any duplicates. This means that if I tried to make a set with the word "APPLE", it would just be {"A","P","L","E"}. Getting the length of that tells me how many unique letters there are. Here is how it all looks together:

letters_left = len(set(guess_word))
elif guess_word.__contains__(guess):
    ...
    #After the for loop:
    #Decrement counter of how many letters are left since we guessed one
    letters_left -= 1

Whenever letters_left == 0, that means the user guessed all the letters correctly!

Fixing the while conditions

So our new while loop needs to stop if letters_left is 0 or if chances is better than 5.

That should look like this:

while letters_left != 0 and chances < 5:

The reason why I used the and keyword instead of the or keyword is that I need both of these statements to be valid. That is, the game can only keep going if the user hasn't solved the puzzle AND still has chances. Setting it or means that the user could keep going if they ran out of chances, but still didn't get it. We don't want that.

Final Code

Here is the final code that runs perfectly on my machine. It has all of the original code and a few comments that I discussed earlier.

import random 

#Changed guess to guess bc it makes more sense

word_list = {
    "Animals" : "ORANGUTAN",
    "Animals" : "GIRAFFE",
    "Animals" : "ELEPHANT",
    "Animals" : "CHEETAH",
    "Food & Drinks" : "ROASTED BEEF SANDWICH",
    "Food & Drinks" : "MAC AND CHEESE",
    "Food & Drinks" : "VIRGIN MOJITO",
    "Food & Drinks" : "STRAWBERRY SHAKE",
    "Brands" : "SAMSUNG",
    "Brands" : "APPLE",
    "Brands" : "CALVIN KLEIN",
    "Brands" : "JOCKEY" }

key_list = ["Animals", "Food & Drinks", "Brands"]

key_name = random.choice(key_list) 
guess_word = word_list.get(key_name)

print(f'{key_name} ({len(guess_word)} letter word)')

letter_list = ["_"]*len(guess_word) 
#Added counter variable to keep track of how many letters are still needed
letters_left = len(set(guess_word))
answer = "" 
chances = 0 
already_inputted = ""

#Modifying while loop to check if counter is zero or if chances are bigger than 5
#Also used "and" instead of or because either condition needs to terminate
#while answer.join(letter_list) != guess_word or chances < 5:
while letters_left != 0 and chances < 5:
    print(letters_left)

    index = 0
    guess = input('Enter a letter as a guess: ')

    if already_inputted.__contains__(guess):
        print('The letter is already guessed')

    elif guess_word.__contains__(guess):
        for letter in guess_word:
            if letter == guess:
                #Changed to update list value instead of insert
                #letter_list.insert(index, guess)
                letter_list[index] = guess
            index += 1
        #Decrement counter of how many letters are left since we guessed one
        letters_left -= 1
    
    else:
        chances += 1

    already_inputted += guess

    print(f'{letter_list}
chances = {5 - chances}
already guessed = {already_inputted}')

if chances == 5:
    print(f"You lost! The word was {guess_word}")

else:
    print("You win!")

:)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...