简体   繁体   中英

Can't Break Out of While Loop

I wrote the following python code. It takes a list of English words I found on the internet and makes them a list so that I can use them for hangman. Well my problem is that every time I run this program and successfully guess the word, it doesn't break out of the while loop. It just keeps going. I can't figure out why for the life of me. Anyone have any clue as to why it isn't printing the final message to the winner?

import random

words = []

lettersGuessed = []

isGuessed = 0



wordFile = open(r'C:\Users\Sarah\PycharmProjects\hangman\words.txt')

for word in wordFile:
    words.append(word.rstrip(wordFile.readline()))


mysteryWord = random.choice(words)

while len(mysteryWord) <= 1:
    mysteryWord = random.choice(words)

for letter in mysteryWord:
    print("?", end = "")
print("\n")

def isWon():
    #win conditions
    count = 0
    for letter in mysteryWord:
        if letter in lettersGuessed:
            count += 1

        if count == len(mysteryWord):
            isGuessed = 1



count = 0

while isGuessed == 0:


    guess = input("Guess a letter \n")

    if guess.upper() or guess.lower() in mysteryWord:
        lettersGuessed.append(guess)
        for letter in mysteryWord:
            if letter in lettersGuessed:
                print(letter, end ='')
            else:
                print("?", end = '')
    print("\n")
    count = 0
    isWon()
    if isGuessed == 1:
        break

print("Congratulations, you correctly guessed ", mysteryWord)

The immediate issue is that isWon() is not setting isGuessed regardless of the input. If you guess with the string "foo" then

lettersGuessed.append(guess)

will make lettersGuessed a list with one item, which is a string. I think what you were trying to do was

lettersGuessed.extend(list(guess))

Which will add each letter in guess to the lettersGuessed list.

Two points also worth mentioning:

  • isWon() will consider the game won if you guess an anagram of the word in in questions eg "oof" will be considered a correct solution if the word is "foo"
  • words.append(word.rstrip(wordFile.readline())) is reading every even line of the input file, and adding it to the words list after removing any characters it has in common with the following word. You want to do words.append(word.strip()) instead.

isGuessed in your top-level code and isGuessed in isWon function are two different variables. A function is a separate namespace (else a function using a variable with common name like i would wreak havoc in other code).

This can be solved by a global declaration, but it's a very bad style. Same applies to variables like mysteryWord and lettersGuessed .

Instead, you should return the value from the isWon function:

def isWon(mysteryWord, lettersGuessed):
   # do your counting...
   return isGuessed

# main code
victory = False
while not victory:
   # ...
   victory = isWon(mysteryWord, lettersGuessed)
   # you don't even need the if ... break statement

BTW your check for all letters being guessed can be made a one-liner:

def isWon(mysteryWord, lettersGuessed):
    return set(lettersGuessed) == set(mysteryWord)

It's all about scope. isGuessed used in isWon() is define in the local scope. If you want to affect isGuessed declared in the global scope you will have to either pass it to isWon() as a parameter or use the global keyword before modifying isGuessed . See below:

def isWon():
#win conditions
count = 0
for letter in mysteryWord:
    if letter in lettersGuessed:
        count += 1

    if count == len(mysteryWord):
        global isGuessed
        isGuessed = 1    

Output with this change:

python3 test.py
?????

Guess a letter
1
?????

Guess a letter
2
?????

Guess a letter
3
????3

Guess a letter
4t
????3

Guess a letter
t
t??t3

Guess a letter
e
te?t3

Guess a letter
s
test3

Congratulations, you correctly guessed  test3

You're trying to communicate using the global variable is_guessed , but the isWon function doesn't gave a global is_guessed line, so it is setting a variable local to isWon named is_guessed rather than the global variable.

My suggestion would be, rather than adding global is_guessed to isWon() , to return either True or False from isWon() (based on whether or not the user has won) and use that to end the loop.

Here is an alternative version of your code:

import random

words = []
with open(r'C:\Users\Sarah\PycharmProjects\hangman\words.txt') as wordFile:
    for word in wordFile:           # assuming one word per line
        words.append(word.strip())  # iterating a file reads one line per iteration

mysteryWord = random.choice(words)
mysteryLetters = set(mysteryWord.lower())
lettersGuessed = set()

def isWon():
    return mysteryLetters == (lettersGuessed & mysteryLetters)

while not isWon():
    for letter in mysteryWord:
        if letter in lettersGuessed:
            print(letter, end ='')
        else:
            print("?", end = '')
    print()

    guess = input("Guess a letter \n")[:1].lower()

    if guess in mysteryWord:
        lettersGuessed.add(guess)

print("Congratulations, you correctly guessed ", mysteryWord)

Well, I know that my answer is a little late but here's my solution:

#!/usr/bin/env python3

import random

word_file_name = "/usr/share/dict/canadian-english"

with open(word_file_name) as word_file:
    # I'm assuming your input file has one word per line and that
    # you want to keep only words that has more than one letter
    words = [word.rstrip() for word in word_file if len(word) > 1]

mystery_word = random.choice(words)

# Using sets helps to remove duplicate letters and eases membership tests 
letters_mystery = set(mystery_word.upper())
letters_guessed = set()

not_guessed = True

while not_guessed:
    # We create a list with all the letters found or not
    letters_to_show = [letter if letter.upper() in letters_guessed else "?"
                       for letter in mystery_word]
    # We join them before printing them
    print("".join(letters_to_show), "\n")

    guess_received = input("Guess a letter :")
    if guess_received.strip():
        # We only keep the first letter received
        guess_kept = guess_received[0].upper()

        if guess_kept in letters_mystery:
            letters_guessed.add(guess_kept)

    # We determine if we need to continue
    not_guessed = letters_guessed != letters_mystery

print("Congratulations, you correctly guessed", mystery_word)

Key points:

  • A list comprehension is used to put the words in a list
  • Sets are used to keep a group of letters without duplicates.
  • A conditional expression is used to choose if a letter will be shown or or a ?
  • Truth testing can be used to simplify the verification of certain information
  • You are using expressions like isGuessed == 1 like in C where True equals 1 and False equals 0. In Python, a variable can be a boolean. You can use it directly in a if statement

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM