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()
-
\$\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\$janos– janos2016年02月05日 13:18:03 +00:00Commented Feb 5, 2016 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– SirPython2016年02月05日 14:09:06 +00:00Commented Feb 5, 2016 at 14:09
2 Answers 2
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 todifficulty
. Any calls todifficulty2
in your code can just be changed todifficulty
calls. - Similarly to the above nitpick, your
difficultyEASY
,difficultyMED
, etc. functions are also virtually identical. Simply create one function namedchange_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.
Word Storage
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!You're actually just making ONE huge word list (EDIT: I see @Ethan Bierlein already pointed this out).
(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.
-
\$\begingroup\$ A little comment regarding string formatting: the
%
operator is deprecated in Python 3.x in favor of thestring.format
function, so that'd probably be worth mentioning. \$\endgroup\$Ethan Bierlein– Ethan Bierlein2016年02月05日 17:24:12 +00:00Commented Feb 5, 2016 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– Tersosauros2016年02月05日 17:34:10 +00:00Commented Feb 5, 2016 at 17:34