views:

143

answers:

3

Just getting into python, and so I decided to make a hangman game. Works good, but I was wondering if there was any kind of optimizations I could make or ways to clean up the code. Also, if anyone could recommend a project that I could do next that'd be cool.

import sys
import codecs
import random

def printInterface(lst, attempts):
    """ Prints user interface which includes:
            - hangman drawing
            - word updater """

    for update in lst:
        print (update, end = '')

    if attempts == 1:
        print ("\n\n\n\n\n\n\n\n\n\n\n\t\t    _____________")
    elif attempts == 2:
        print ("""          
                          |
                          | 
                          |
                          |
                          |
                          |
                          |
                          |
                          |
                    ______|______""")
    elif attempts == 3:
        print ("""
            ______          
                  |
                  | 
                  |
                  |
                  |
                  |
                  |
                  |
                  |
            ______|______""")
    elif attempts == 4:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
                  |
                  |
                  |
                  |
                  |
                  |
            ______|______""")
    elif attempts == 5:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
           |      |
           |      |
           |      |
                  |
                  |
                  |
            ______|______""")
    elif attempts == 6:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
           |      |
          /|      |
           |      |
                  |
                  |
                  |
            ______|______""")
    elif attempts == 7:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
           |      |
          /|\     |
           |      |
                  |
                  |
                  |
            ______|______""")
    elif attempts == 8:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
           |      |
          /|\     |
           |      |
          /       |
                  |
                  |
            ______|______""")
    elif attempts == 9:
        print ("""
            ______
           |      |
           |      | 
         (x_X)    |
           |      |
          /|\     |
           |      |
          / \     |
                  |
                  |
            ______|______""")

def main():
    try:
        wordlist = codecs.open("words.txt", "r")
    except Exception as ex:
        print (ex)
        print ("\n**Could not open file!**\n")
        sys.exit(0)

    rand = random.randint(1,5)
    i = 0

    for word in wordlist:
        i+=1
        if i == rand:
            break
    word = word.strip()
    wordlist.close()

    lst = []
    for h in word:
        lst.append('_ ')

    attempts = 0    
    printInterface(lst,attempts) 

    while True:
        guess = input("Guess a letter: ").strip()

        i = 0
        for letters in lst:
            if guess not in word:
                print ("No '{0}' in the word, try again!".format(guess))
                attempts += 1
                break
            if guess in word[i] and lst[i] == "_ ":
                lst[i] = (guess + ' ')
            i+=1

        printInterface(lst,attempts)

        x = lst.count('_ ')
        if x == 0:
            print ("You win!")
            break
        elif attempts == 9:
            print ("You suck! You iz ded!")
            break

if __name__ == '__main__':
    while True:
        main()
        again = input("Would you like to play again? (y/n):  ").strip()
        if again.lower() == "n":
            sys.exit(1)
        print ('\n')
+5  A: 

I didn't try the code, but here's some random tips:

  • Try to format your code accordingly to PEP 8 (use i += 1 instead of i+=1). PEP 8 is the standard style guide for Python.

  • Use

    lst = ['_ '] * len(word)
    

    instead of the for-loop.

  • Use enumerate as in:

    for i, word in enumerate(wordlist)
    

    instead of manually keeping track of i in the loop.

  • The default mode for opening files is 'r', there's no need to specify it. Are you using codecs.open instead of the built-in open in order to get Unicode strings back? Also, try to catch a more specific exception that Exception -- probably IOError.

Martin Geisler
When I try to use: lst = '_ ' * len(word), I get the error "string index out of range." I know what that means, but I don't know how to fix it with your code. Also, just a quick question on enumerate... can you make it count more than +1? Like +2 +3 or maybe even *2 *3?
Justen
Ah, my bad: lst is a list of '_ ' pieces. I'll update the answer. And no, enumerate can only count in steps of one. I'll add a link to its documentation.
Martin Geisler
Btw, if it wasn't clear: "x" * 5 gives the string "xxxxx", whereas ["x"] * 5 gives the list ["x", "x", "x", "x", "x"]. Your code expects the latter.
Martin Geisler
+2  A: 

I would use list instead of if .. else statement in printInterface.

Piotr Czapla
Good idea: put the cute ASCII art pictures into a list and simply print `hangman[attemps]`.
Martin Geisler
Is there no switch equivalent in python? I couldn't find anything in the ebook I have, so just wondering
Justen
Nope, there is no switch. You can sometimes simulate it using a dict or list.
Martin Geisler
There is no switch because it is faster and more flexible to use dict instead. ex: {val1:func1, val2:func2}.get(curr_val, default_func)();
Piotr Czapla
+2  A: 

First idea: ASCII art

The things special to Python are regular expression syntax and range() function, as well as [xxx for yyy in zzz] array filler.

    import re

    def ascii_art(attempt):
        return re.sub(r'\d', '', re.sub('[0{0}].' \
            .format(''.join([str(e) for e in range(attempt + 1, 10)])), ' ', """
                3_3_3_3_3_3_
               4|      2|
               4|      2| 
             4(4x4_4X4)    2|
               5|      2|
              6/5|7\     2|
               5|      2|
              8/ 9\     2|
                      2|
                      2|
                1_1_1_1_1_1_1|1_1_1_1_1_1_
    """))

    for i in range(1, 10): 
        print(ascii_art(i))

Second idea: loops

Use enumerate for word reading loop. Use

for attempt in range(1, 10):
    # inside main loop
    ...
print ('you suck!')

as the main loop. Operator break should be used with care and not as replacement for for!

Unless I miss something, the structure of

    for letters in lst:
        if guess not in word:
            ...
            break
        if guess in word[i]:
            ...

will be more transparent as

    if guess not in word:
             ...
    else:
         index = word.find (guess)
         ...
ilya n.