To learn Python, I've been working through Learn Python the Hard Way, and to exercise my Python skills I wrote a little Python Hangman game (PyHangman - creative, right?):
#! /usr/bin/env python2.7
import sys, os, random
if sys.version_info.major != 2:
raw_input('This program requires Python 2.x to run.')
sys.exit(0)
class Gallows(object):
def __init__(self):
'''Visual of the game.'''
self.state = [
[
'\t _______ ',
'\t | | ',
'\t | ',
'\t | ',
'\t | ',
'\t | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t | ',
'\t | ',
'\t | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t | | ',
'\t | | ',
'\t | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t \| | ',
'\t | | ',
'\t | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t \|/ | ',
'\t | | ',
'\t | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t \|/ | ',
'\t | | ',
'\t / | ',
'\t________|_',
],
[
'\t _______ ',
'\t | | ',
'\t O | ',
'\t \|/ | ',
'\t | | ',
'\t / \\ | ',
'\t________|_',
]
]
def set_state(self, misses):
'''Sets the current visual being used.'''
image = ''
state = self.state[misses] # set state to the list of desired gallows image
# construct gallows image into str from list
for piece in state:
image += piece + '\n'
return image
class Wordlist(object):
def __init__(self):
'''Set the length of the wordlist.'''
self.numLines = sum(1 for line in open('test.txt'))
def new_word(self):
'''Choose a new word to be guessed.'''
stopNum = random.randint(0, self.numLines-1) # establish random number to be picked from list
# extract word from file
with open('test.txt') as file:
for x, line in enumerate(file):
if x == stopNum:
word = line.lower().strip() # remove endline characters
return word
def set_blanks(word):
'''Create blanks for each letter in the word.'''
blanks = []
for letter in word:
# Don't hide hyphens
if letter == '-':
blanks += '-'
else:
blanks += '_'
return blanks
def check_letter(word, guess, blanks, used, missed):
'''Check if guessed letter is in the word.'''
newWord = word
# If the user presses enter without entering a letter
if guess.isalpha() == False:
raw_input("You have to guess a letter, silly!")
# If the user inputs multiple letters at once
elif len(list(guess)) > 1:
raw_input("You can't guess more than one letter at a time, silly!")
# If the user inputs a letter they've already used
elif guess in used:
raw_input("You already tried that letter, silly!")
# replace the corresponding blank for each instance of guess in the word
elif guess in word:
for x in range(0, word.count(guess)):
blanks[newWord.find(guess)] = guess
newWord = newWord.replace(guess, '-', 1) # replace already checked letters with dashes
used += guess # add the guess to the used letter list
#If the guess is wrong
else:
missed = True
used += guess
return blanks, used, missed
def new_page():
'''Clears the window.'''
os.system('cls' if os.name == 'nt' else 'clear')
def reset(image, wordlist):
wrongGuesses = 0 # number of incorrect guesses
currentImg = image.set_state(wrongGuesses) # current state of the gallows
word = wordlist.new_word() # word to be guessed
blanks = set_blanks(word) # blanks which hide each letter of the word until guessed
used = [] # list of used letters
return wrongGuesses, currentImg, word, blanks, used
def play(image, currentImg, wrongGuesses, word, blanks, used):
missed = False
new_page()
print currentImg
for x in blanks:
print x,
print '\n'
for x in used:
print x,
print '\n'
guess = raw_input("Guess a letter: ")
blanks, used, missed = check_letter(word, guess.lower(), blanks, used, missed)
if missed == True and wrongGuesses < 6:
wrongGuesses += 1
currentImg = image.set_state(wrongGuesses)
play(image, currentImg, wrongGuesses, word, blanks, used)
elif missed == False and blanks != list(word) and wrongGuesses != 7:
play(image, currentImg, wrongGuesses, word, blanks, used)
elif blanks == list(word):
endgame('win', word)
else:
endgame('lose', word)
def endgame(result, word):
new_page()
if result != 'lose':
print "Congratulations, you win!"
print "You correctly guessed the word '%s'!" % word
else:
print "Nice try! Your word was '%s'." % word
while True:
play_again = raw_input("Play again? [y/n]")
if 'y' in play_again.lower():
return
elif 'n' in play_again.lower():
sys.exit(0)
else:
print "Huh?"
def main():
image = Gallows()
wordlist = Wordlist()
new_page()
print("\nWelcome to Hangman!")
print("Guess the word before the man is hung and you win!")
raw_input("\n\t---Enter to Continue---\n")
new_page()
while True:
misses, currentImg, word, blanks, used = reset(image, wordlist)
play(image, currentImg, misses, word, blanks, used)
if __name__ == '__main__':
main()
So what do you all think? This is the second iteration of the program, as the first one was a mess, but I think I've got it all worked out a bit better now.
One of the things that I still think is messy is how I had the game loop after you guessed a letter, as it simply calls itself again. Is there a better way to do that?
Any tips on making my code more pythonic is appreciated!