6
\$\begingroup\$

I created this version of Hangman in Python 3. Does anyone have any tips for optimization or improvement?

import random
HANGMAN = (
'''
-------+''',
'''
 +
 |
 |
 |
 |
 |
-------+''',
'''
 -----+
 |
 |
 |
 |
 |
-------+''',
'''
 -----+
 | |
 |
 |
 |
 |
-------+''',
'''
 -----+
 | |
 O |
 |
 |
 |
-------+''',
'''
 -----+
 | |
 O |
 | |
 |
 |
-------+''',
'''
 -----+
 | |
 O |
 /| |
 |
 |
-------+''',
'''
 -----+
 | |
 O |
 /|\ |
 |
 |
-------+''',
'''
 -----+
 | |
 O |
 /|\ |
 / |
 |
-------+''',
'''
 -----+
 | |
 O |
 /|\ |
 / \ |
 |
-------+''')
MAX = len(HANGMAN) - 1
WORDS = ('jazz', 'buzz', 'hajj', 'fuzz', 'jinx', 'jazzy', 'fuzzy', 'faffs', 'fizzy', 'jiffs', 'jazzed', 'buzzed', 'jazzes', 'faffed', 'fizzed', 'jazzing', 'buzzing', 'jazzier', 'faffing', 'fuzzing')
sizeHangman = 0
word = random.choice(WORDS)
hiddenWord = list('-' * len(word))
lettersGuessed = []
print('\tHANGMAN GAME\n\t\tBy Lewis Cornwall\n')
while sizeHangman < MAX:
 print('This is your hangman:' + HANGMAN[sizeHangman] + '\nThis is the word:\n' + ''.join(hiddenWord) + '\nThese are the letters you\'ve already guessed:\n' + str(lettersGuessed))
 guess = input('Guess a letter: ').lower()
 while guess in lettersGuessed:
 print('You\'ve already guessed that letter!')
 guess = input('Guess a letter: ').lower()
 if guess in word:
 print('Well done, "' + guess + '" is in my word!')
 for i in range(len(word)):
 if guess == word[i]:
 hiddenWord[i] = guess
 if hiddenWord.count('-') == 0:
 print('Congratulations! My word was ' + word + '!')
 input('Press <enter> to close.')
 quit()
 else:
 print('Unfortunately, "' + guess + '" is not in my word.')
 sizeHangman += 1
 lettersGuessed.append(guess)
print('This is your hangman: ' + HANGMAN[sizeHangman] + 'You\'ve been hanged! My word was actually ' + word + '.')
input('Press <enter> to close.')
Pimgd
22.5k5 gold badges68 silver badges144 bronze badges
asked Mar 9, 2013 at 21:43
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Not an optimization, but you could load your words from a - possibly encrypted - text file instead of having them in your raw code :) \$\endgroup\$ Commented Mar 11, 2013 at 13:22

3 Answers 3

7
\$\begingroup\$

You can avoid repeating guess = input('Guess a letter: ').lower() by changing the inner while loop to:

while True:
 guess = input('Guess a letter: ').lower()
 if guess in lettersGuessed:
 print('You\'ve already guessed that letter!')
 else:
 break

Instead of for i in range(len(word)) use:

for i, letter in enumerate(word):

You could also avoid indexing by i altogether by using a list comprehension. I'm not sure if this is as clear in this case, though.

hiddenWord = [guess if guess == letter else hidden for letter, hidden in zip(word, hiddenWord)]

Instead of hiddenWord.count('-') == 0 use:

'-' not in hiddenWord

The docs say quit() should not be used in programs. Your count('-') == 0 check is unnecessarily inside the for i loop. If you move it after the loop, you could use break to exit the main loop. You could add an else clause to the main with statement for dealing with the "You've been hanged" case. The main loop becomes:

while sizeHangman < MAX:
 print('This is your hangman:' + HANGMAN[sizeHangman] + '\nThis is the word:\n' + ''.join(hiddenWord) + '\nThese are the letters you\'ve already guessed:\n' + str(lettersGuessed))
 while True:
 guess = input('Guess a letter: ').lower()
 if guess in lettersGuessed:
 print('You\'ve already guessed that letter!')
 else:
 break
 if guess in word:
 print('Well done, "' + guess + '" is in my word!')
 for i, letter in enumerate(word):
 if guess == letter:
 hiddenWord[i] = guess
 if '-' not in hiddenWord:
 print('Congratulations! My word was ' + word + '!')
 break
 else:
 print('Unfortunately, "' + guess + '" is not in my word.')
 sizeHangman += 1
 lettersGuessed.append(guess)
else:
 print('This is your hangman: ' + HANGMAN[sizeHangman] + 'You\'ve been hanged! My word was actually ' + word + '.')
input('Press <enter> to close.')
answered Mar 11, 2013 at 13:36
\$\endgroup\$
3
\$\begingroup\$

Some ideas:

  • You might want to make sure that the guess is actually a single letter.

  • lettersGuessed should be a set, so membership tests (guess in lettersGuessed) is a constant time operation.

  • Similarly, you could store either the (correctly) guessed letters or the letters that still have to be (correctly) guessed in a set. For example:

    word = random.choice(WORDS)
    requiredGuesses = set(word)
    lettersGuessed = set()
    # then later
    if guess in lettersGuessed:
     print('You already guessed this')
    elif guess in requiredGuesses:
     print('Correct guess!')
     requiredGuesses.remove(guess)
     lettersGuessed.add(guess)
    else:
     print('Incorrect guess')
    

    This also makes the test if the whole word was guessed easier:

    if not requiredGuesses:
     print('You found the word')
    
  • Instead of keeping a hiddenWord which you keep adjusting whenever a correct guess is made, you could just create the hidden output on the fly:

    print(''.join('-' if l in requiredGuesses else l for l in word))
    
  • You might want to add a class for this game that encapsulates some of the game logic.

answered Dec 25, 2013 at 0:44
\$\endgroup\$
1
\$\begingroup\$

You should implement the ability to read words from a txt document. This can be done by:

f = open("wordlist.txt", 'w')
word_list.append(f.readlines())

this would allow you to have far bigger lists to choose from.

answered Dec 6, 2016 at 21:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.