2
\$\begingroup\$

This is my hangman game code for my GCSE computer science coursework. It has been submitted but I was wondering if there is anyway to improve it.

import random
import time


#Variables holding different words for each difficulty
EASYWORDS = open("Easy.txt","r+")
words = []
for item in EASYWORDS:
    words.append(item.strip('\n'))
MEDWORDS = open("Med.txt","r+")
words = []
for item in MEDWORDS:
    words.append(item.strip('\n'))

HARDWORDS = open("Hard.txt","r+")
words = []
for item in HARDWORDS:
    words.append(item.strip('\n'))

INSANEWORDS = open("Insane.txt", "r+")
words = []
for item in INSANEWORDS:
    words.append(item.strip('\n'))
#Where the user picks a difficulty
def difficulty():

    print("easy\n")
    print("medium\n")
    print("hard\n")
    print("insane\n")

    menu=input("Welcome to Hangman, type in what difficulty you would like... ").lower()

    if menu == "hard" or menu == "h":

        hard()

    elif menu == "medium" or menu == "m" or menu =="med":

        med()

    elif menu == "easy" or menu == "e":

        easy()

    elif menu == "insane" or menu == "i":

        insane()

    else:   
        print("Please type in either hard, medium, easy or insane!")
        difficulty()


def difficulty2():

    print("Easy\n")
    print("Medium\n")
    print("Hard\n")
    print("Insane\n")
    print("Quit\n")

    menu=input("Welcome to Hangman, type in what difficulty you would like. Or would you like to quit the game?").lower()

    if menu == "hard" or menu == "h":

        hard()

    elif menu == "medium" or menu == "m" or menu =="med":

        med()

    elif menu == "easy" or menu == "e":

        easy()

    elif menu == "insane" or menu == "i":

        insane()

    elif menu == "quit" or "q":
        quit()

    else:   
        print("Please type in either hard, medium, easy or insane!")
        difficulty()



#if the user picked easy for their difficulty
def easy():
    global score 
    print ("\nStart guessing...")

    time.sleep(0.5)

    word = random.choice(words).lower()
    guesses = ''
    fails = 0
    while fails >= 0 and fails < 10:         
        failed = 0                
        for char in word:      
            if char in guesses:    
                print (char,)

            else:
                print ("_"),     
                failed += 1    
        if failed == 0:        
            print ("\nYou won, WELL DONE!")
            score = score + 1
            print ("your score is,", score)
            print ("the word was, ", word)
            difficultyEASY()

        guess = input("\nGuess a letter:").lower()
        while len(guess)==0:
            guess = input("\nTry again you muppet:").lower()
        guess = guess[0]
        guesses += guess 
        if guess not in word:
            fails += 1
            print ("\nWrong")

            if fails == 1:
                print ("You have", + fails, "fail....WATCH OUT!" )
            elif fails >= 2 and fails < 10:
                print ("You have", + fails, "fails....WATCH OUT!" )
            if fails == 10:
                print ("You Lose\n")
                print ("your score is, ", score)
                print ("the word was,", word)
                score = 0
                difficultyEASY()

#if the user picked medium for their difficulty
def med():
    global score 
    print ("\nStart guessing...")

    time.sleep(0.5)

    word = random.choice(words).lower()
    guesses = ''
    fails = 0
    while fails >= 0 and fails < 10:           
        failed = 0                
        for char in word:      
            if char in guesses:    
                print (char,)    

            else:
                print ("_"),     
                failed += 1    
        if failed == 0:        
            print ("\nYou won, WELL DONE!")
            score = score + 1
            print ("your score is,", score)
            difficultyMED()

        guess = input("\nGuess a letter:").lower()
        while len(guess)==0:
            guess = input("\nTry again you muppet:").lower()
        guess = guess[0]
        guesses += guess   
        if guess not in word:  
            fails += 1        
            print ("\nWrong")

            if fails == 1:
                print ("You have", + fails, "fail....WATCH OUT!" )
            elif fails >= 2 and fails < 10:
                print ("You have", + fails, "fails....WATCH OUT!" ) 
            if fails == 10:           
                print ("You Lose\n")
                print ("your score is, ", score)
                print ("the word was,", word)
                score = 0 
                difficultyMED()     

#if the user picked hard for their difficulty
def hard():
    global score  
    print ("\nStart guessing...")

    time.sleep(0.5)

    word = random.choice(words).lower()
    guesses = ''
    fails = 0
    while fails >= 0 and fails < 10:  #try to fix this         
        failed = 0                
        for char in word:      
            if char in guesses:    
                print (char,)    

            else:
                print ("_"),     
                failed += 1    
        if failed == 0:        
            print ("\nYou won, WELL DONE!")
            score = score + 1
            print ("your score is,", score)
            difficultyHARD()

        guess = input("\nGuess a letter:").lower()
        while len(guess)==0:
            guess = input("\nTry again you muppet:").lower()
        guess = guess[0]
        guesses += guess   
        if guess not in word:  
            fails += 1        
            print ("\nWrong")

            if fails == 1:
                print ("You have", + fails, "fail....WATCH OUT!" )
            elif fails >= 2 and fails < 10:
                print ("You have", + fails, "fails....WATCH OUT!" ) 
            if fails == 10:           
                print ("You Lose\n")
                print ("your score is, ", score)
                print ("the word was,", word)
                score = 0 
                difficultyHARD()


#if the user picked insane for their difficulty
def insane():
    global score  
    print ("This words may contain an apostrophe. \nStart guessing...")

    time.sleep(0.5)

    word = random.choice(words).lower()
    guesses = ''
    fails = 0
    while fails >= 0 and fails < 10:  #try to fix this         
        failed = 0                
        for char in word:      
            if char in guesses:    
                print (char,)    

            else:
                print ("_"),     
                failed += 1    
        if failed == 0:        
            print ("\nYou won, WELL DONE!")
            score = score + 1
            print ("your score is,", score)
            difficultyINSANE()

        guess = input("\nGuess a letter:").lower()
        while len(guess)==0:
            guess = input("\nTry again you muppet:").lower()
        guess = guess[0]
        guesses += guess   
        if guess not in word:  
            fails += 1        
            print ("\nWrong")

            if fails == 1:
                print ("You have", + fails, "fail....WATCH OUT!" )
            elif fails >= 2 and fails < 10:
                print ("You have", + fails, "fails....WATCH OUT!" ) 
            if fails == 10:           
                print ("You Lose\n")
                print ("your score is, ", score)
                print ("the word was,", word)
                score = 0 
                difficultyINSANE()


def start():

    Continue = input("Do you want to play hangman?").lower()
    while Continue in ["y", "ye", "yes", "yeah"]:
        name = input("What is your name? ")
        print ("Hello, " + name, "Time to play hangman! You have ten guesses to win!")
        print ("\n")
        time.sleep(1)
        difficulty()
    else:
        quit

#whether they want to try a diffirent difficulty or stay on easy

def difficultyEASY():
    diff = input("Do you want to change the difficulty?. Or quit the game? ")
    if diff == "yes" or difficulty =="y":
        difficulty2()
    elif diff == "no" or diff =="n":
        easy()

#whether they want to try a diffirent difficulty or stay on medium

def difficultyMED():
    diff = input("Do you want to change the difficulty?. Or quit the game? ")
    if diff == "yes" or difficulty =="y":
        difficulty2()
    elif diff == "no" or diff =="n":
        med()

#whether they want to try a diffirent difficulty or stay on hard

def difficultyHARD():
    diff = input("Do you want to change the difficulty?. Or quit the game? ")
    if diff == "yes" or difficulty =="y":
        difficulty2()
    elif diff == "no" or diff =="n":
        hard()

#whether they want to try a diffirent difficulty or stay on insane

def difficultyINSANE():
    diff = input("Do you want to change the difficulty?. Or quit the game? ")
    if diff == "yes" or difficulty =="y":
        difficulty2()
    elif diff == "no" or diff =="n":
        insane()

score = 0

start()
\$\endgroup\$
  • \$\begingroup\$ Please add an introductory paragraph. See the how-to-ask page in the help center to make the most out of Code Review \$\endgroup\$ – Stop ongoing harm to Monica Feb 5 '16 at 13:18
  • 3
    \$\begingroup\$ Your post is now semi-on-topic. The first part of your question is on-topic, but we do not write code for you here so we will not convert it to Tkinter for you. \$\endgroup\$ – SirPython Feb 5 '16 at 14:09
7
\$\begingroup\$

Input checking

The way you're currently checking input is clunky, hard to write, and hard to read. For example, you have the following chunk of code:

menu=input("Welcome to Hangman, type in what difficulty you would like... ").lower()

if menu == "hard" or menu == "h":

    hard()

elif menu == "medium" or menu == "m" or menu =="med":

    med()

elif menu == "easy" or menu == "e":

    easy()

elif menu == "insane" or menu == "i":

    insane()

else:   
    print("Please type in either hard, medium, easy or insane!")
    difficulty()

There are quite a few things that can be improved here, so let's start with the obvious. Rather than having multiple individual conditional expressions to check the value of a variable, simply create a list of all possible values and use the in operator to check the variable's value, like this, for example:

if menu in ["medium", "med", "m"]:
    med()

Next, I'd suggest that you add a .strip() call to the following line:

menu=input("Welcome to Hangman, type in what difficulty you would like... ").lower()

The .strip() function, when no arguments are specified, will remove leading and trailing whitespace. This means that a user can enter something like " med " without worrying that the program might reject their input. In addition, you could also consider using re.sub if you want to get rid of additional characters.


Building word lists

You've got a lot of repetition in the following chunk of code:

#Variables holding different words for each difficulty
EASYWORDS = open("Easy.txt","r+")
words = []
for item in EASYWORDS:
    words.append(item.strip('\n'))
MEDWORDS = open("Med.txt","r+")
words = []
for item in MEDWORDS:
    words.append(item.strip('\n'))

HARDWORDS = open("Hard.txt","r+")
words = []
for item in HARDWORDS:
    words.append(item.strip('\n'))

INSANEWORDS = open("Insane.txt", "r+")
words = []
for item in INSANEWORDS:
    words.append(item.strip('\n'))

The best way to do this would probably be to use generator expressions, and encapsulate it into a function, like this:

def build_word_list(word_file):
    words = [item.strip("\n") for item in word_file]
    return words

You can then use it like this, assuming you've already defined build_word_list:

EASYWORDS = open("Easy.txt","r+")
MEDWORDS = open("Med.txt","r+")
HARDWORDS = open("Hard.txt","r+")
INSANEWORDS = open("Insane.txt", "r+")

easy_words = build_word_list(EASYWORDS)
medium_words = build_word_list(MEDWORDS)
hard_words = build_word_list(HARDWORDS)
insane_words = build_word_list(INSANEWORDS)

I've also fixed a pretty large bug. You were creating only one word list, which meant that regardless of what difficulty you chose, you'd have words from all difficulties. Now there are separate word lists for each separate difficulty.


Creating a play function

The functions easy, med, hard and insane are all identical. There is no reason that you should be repeating yourself over and over again. To help prevent the repetition, create one simple play function with an argument named word_list. The signature for the play function should look like this:

def play(word_list): # Game logic goes here

You'd simply pass a word list, like easy_words or insane_words as the word_list argument, and then use the word_list argument in the function.


Misc. Nitpicks

There are quite a few things I want to nitpick, so get ready.

  • The difficulty2 function serves no purpose. It is identical in every way to difficulty. Any calls to difficulty2 in your code can just be changed to difficulty calls.
  • Similarly to the above nitpick, your difficultyEASY, difficultyMED, etc. functions are also virtually identical. Simply create one function named change_difficulty and you're set.
  • You need whitespace between your operators, and an introduction to PEP8, the official Python style guide.. Nobody wants to read code that looks like it was plucked straight out of a PPCG answer.
\$\endgroup\$
6
\$\begingroup\$

Word Storage

  1. Don't leave file handles open if you're done with them Each time you open() a file, it allocates operating system and interpreter resources (handles). If you're done with a file, close() it!

  2. You're actually just making ONE huge word list (EDIT: I see @Ethan Bierlein already pointed this out).

  3. (Again, as @Ethan Bierlein's answer goes to) You're repeating a LOT of similar code for your word lists. Ethan's generator is a good idea here (just don't forget to close() those file-handles!


(Almost) Total repetition of game logic

The functions easy, med, hard and insane are 99% similar (okay I didn't calculate an actual percentage, but you know what I mean). these can easily be accomplished with MUCH less code by making them more parameterised (i.e. taking an argument to a generated wordlist for difficulty).


Pythonic startup

Not that it's a huge deal for something like this, but if you want it to be more Pythonic, the last line:

main()

Should be put inside an if statement to ensure the script isn't being used as a module, etc:

if __name__=='__main__':
    main()

This simply ensures main is only called if we are the main script in the interpreter.


String concatenation

Also, not an * end of the world * thing, but (for example), the following line inside your start function:

print ("Hello, " + name, "Time to play hangman! You have ten guesses to win!")

Uses string concatenation inside print. This is generally bad practise in Python. Instead, you should be using format strings:

print ("Hello, %s, Time to play hangman! You have ten guesses to win!" % name)


Needless if statements (and more code repetition)

I'm not sure what the purpose of the following if/elif block is (as they both have exactly the same code in them:

       if fails == 1:
            print ("You have", + fails, "fail....WATCH OUT!" )
        elif fails >= 2 and fails < 10:
            print ("You have", + fails, "fails....WATCH OUT!" )
        if fails == 10:
...

But they appear in EACH of the (many) game play functions. This would much better be done with one if (and using a format string):

        if fails < 10:
            print ("You have %d fails....WATCH OUT!" % fails )
        else:
...

Also, note the slight logic difference here, the else is essentially all cases where fails is =>10, where as your code just tests ==10.

\$\endgroup\$
  • \$\begingroup\$ A little comment regarding string formatting: the % operator is deprecated in Python 3.x in favor of the string.format function, so that'd probably be worth mentioning. \$\endgroup\$ – Ethan Bierlein Feb 5 '16 at 17:24
  • 1
    \$\begingroup\$ @Ethan Bierlein True, I had assumed this was for Python 2.x. But yes, in 3 the string.format technique, as discussed here is preferred. \$\endgroup\$ – Tersosauros Feb 5 '16 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.