17
\$\begingroup\$

I just started learning about Python at school and decided to start this little project with the basic knowledge I have. Most of the code is pretty lengthy and I know there are probably more efficient ways of doing it so Im looking for any improvements and tips that will help my code.

#Python Game - Hangman
#Imports
import random
import string
import sys
#Custom Functions
def Lives(Incorrect): #This function tells the player how many lives they have left when called
 LivesLeft = IncorrectLimit - Incorrect
 print("You have", LivesLeft, "lives left.")
def PicNo(Incorrect): #This function prints the hangman picture to the corresponding incorrect guesses
 if Incorrect == 1: 
 print(Pic1)
 if Incorrect == 2:
 print(Pic2)
 if Incorrect == 3:
 print(Pic3)
 if Incorrect == 4:
 print(Pic4)
 if Incorrect == 5:
 print(Pic5)
 if Incorrect == 6:
 print(Pic6)
 if Incorrect == 7:
 print(Pic7)
def Hint(Incorrect, WordChoice): #This function prints a hint when the player gets down to their last two guesses
 if Incorrect == 6:
 WordChoice = list(WordChoice)
 WordHint = random.choice(WordChoice)
 WordChoice = "".join(WordChoice)
 print("Hint - the word contains the letter: ", WordHint)
#Constants
List1 = ["fable","surf","english","paris","flower","laptop","sand","classroom", "blonde", "star", "blue", "hat", "snow", "tennis", "gate", "palm","internet","bricks", "bird", "mountain", "crate", "jumper", "whiteboard", "teacher", "table", "paving", "vehicle", "roundabout", "grass", "window", "cat", "dog", "bag", "bycicle", "jewellery", "headphones"] #These are all the words that can possibly be taken
IncorrectLimit = 7 #The number of guesses a player can get incorrect
Infinity = 9999999999999999999999999999999999 #An amount set for for loops
Pic1 = ('''
 +---+
 | |
 |
 |
 |
 |
=========''')
Pic2 = ('''
 +---+
 | |
 O |
 |
 |
 |
=========''')
Pic3 = ('''
 +---+
 | |
 O |
 | |
 |
 |
=========''')
Pic4 = ('''
 +---+
 | |
 O |
 /| |
 |
 |
=========''')
Pic5 = ('''
 +---+
 | |
 O |
 /|\ |
 |
 |
=========''')
Pic6 = ('''
 +---+
 | |
 O |
 /|\ |
 / |
 |
=========''')
Pic7 = ('''
 +---+
 | |
 O |
 /|\ |
 / \ |
 |
=========''') #The hangman pictures
#Variables
Incorrect = 0 #The incorrect count starts at 0
List2 = [] #List2 starts empty
#Start - Menu
print("PYTHON HANGMAN") #Startup title and menu
print("Coded by - -\n")
input("Press \"Enter\" to start a game." + "\n")
#GAME START
#Processing
for i in range(Infinity):
 WordChoice = (random.choice(List1)) #Randomly chooses a word from List 1
 LetterCount = len(WordChoice) #Returns the amount of letters in the chosen word
 print("<-----[NEW GAME]----->\n")
 print("The word is", LetterCount, "letters long.") #Prints the letter count of the word
 if LetterCount == 1: #Prints the 'mystery' words length with underscores and spaces
 L = ("_")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 2:
 L = ("__")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 3:
 L = ("___")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 4:
 L = ("____")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 5:
 L = ("_____")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 6:
 L = ("______")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 7:
 L = ("_______")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 8:
 L = ("________")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 9:
 L = ("_________")
 print(L.replace("", " ")[1: -1], "\n")
 if LetterCount == 10:
 L = ("__________")
 print(L.replace("", " ")[1: -1], "\n")
 GuessList = list(L) #Sets the chosen mystery underscore string to a list
 LivesLeft = IncorrectLimit - Incorrect #Calculates the lives left
 for i in range(Infinity): #Loops the following indented code
 if GuessList == WordChoice:
 break
 Hint(Incorrect, WordChoice) #The hint custom function
 for i in range(Infinity): #Loops the guessing process
 Guess1 = input("Guess a letter: ") #The players letter guess
 GuessLength = len(Guess1)
 if GuessLength > 1:
 print("Please enter only one letter.") #Repeats the guessing process if there is more than one letter
 elif Guess1 == "":
 print("Please enter a letter.") #Repeats the guessing process if there is not input
 else:
 break
 Guess1 = Guess1.lower() #Turns the input into a lowercase string
 List2.append(Guess1) #Adds the guess to List2
 if WordChoice.find(Guess1) >= 0: #A boolean that finds if the guess is contained in the word
 GuessList = list(GuessList) #Sets GuessList to a list
 for x, y in enumerate(WordChoice): #Replaces the underscore from GuessList with the correct corresponding letter 
 if Guess1 == y:
 GuessList[x] = y
 print("The letter", Guess1.upper(), "was correct.") #Prints a message telling the player they were correct
 GuessList = "".join(GuessList) #Sets GuessList back to a string
 else:
 Incorrect += 1 #Increases Incorrect up 1 everytime the player is incorrect
 print("Incorrect.")
 GuessList = "".join(GuessList) #Sets GuessList back to a string
 PicNo(Incorrect) #The PicNo custom function
 Lives(Incorrect) #The Lives custom function
 List2 = "".join(List2) #Sets List2 to a string
 print("Guessed Letters: ",List2.upper()) #Prints the players guessed letters
 List2 = list(List2) #Sets List2 back to a list
 List2.append(", ") #Adds a comma and space to List2 for formatting
 print(GuessList.replace("", " ")[1: -1], "\n") #Prints the GuessList with spaces
 if GuessList == WordChoice: #Determines if the player has won the game
 print("Well done, you guessed the correct word!")
 Incorrect = 0 
 List2 = []
 GuessList = []
 NewGame = input("Would you like to play Hangman again? [Y]es, [N]o: \n")
 if NewGame == "Y":
 break
 else:
 sys.exit()
 if Incorrect == 7: #Determines if the player has lost the game
 print("Game over.")
 print("The word was: ", WordChoice + ".")
 Incorrect = 0 
 List2 = []
 GuessList = []
 NewGame = input("Would you like to play Hangman again? [Y]es, [N]o: \n")
 if NewGame == "Y": 
 break
 else:
 sys.exit()
asked Jul 26, 2017 at 8:15
\$\endgroup\$
1
  • 9
    \$\begingroup\$ @t3chb0t its not that hard to understand, its hangman... Not only did he actually tell you "What it is supposed to do" he also commented extensively and pretty plainly showed you "how it works". \$\endgroup\$ Commented Jul 26, 2017 at 16:22

4 Answers 4

24
\$\begingroup\$

Welcome to Python, and welcome to Code Review! Here are some basic tips to help you along.

0.5. EDIT: I think you also have an unused import. import string is not needed.

  1. Consider using a style guideline like PEP8. This is more of a general suggestion and will make your future code much more readable and maintainable.

  2. Consider defining all your constants at the top of the file. This makes them easier to find. In other languages, you cannot use a variable before you define it, so this is a good habit to get used to as well.

  3. Python is a self-documenting language. Generally, in Python and other languages, comments should not be used to state the obvious. Use comments to explain algorithms or non-trivial aspects of the code.

    #Custom Functions
    def Lives(Incorrect): #This function tells the player how many lives they have left when called
    

    This is not a very useful comment.

  4. Consider refactoring some commonly used functions:

    def PicNo(Incorrect): #This function prints the hangman picture to the corresponding incorrect guesses
     if Incorrect == 1: 
     print(Pic1)
     if Incorrect == 2:
     print(Pic2)
     if Incorrect == 3:
     print(Pic3)
     if Incorrect == 4:
     print(Pic4)
     if Incorrect == 5:
     print(Pic5)
     if Incorrect == 6:
     print(Pic6)
     if Incorrect == 7:
     print(Pic7)
    

    Generally, this is a bad idea and goes against the principle of DRY. An alternative is using a Python dictionary/list to store the hangman states. For example:

    PICS = ['''
     +---+
     | |
     |
     |
     |
     |
    =========''', '''
     +---+
     | |
     O |
     |
     |
     |
    =========''', ... # et cetera
    # Accessing it
    print(PICS[0])
    def PicNo(Incorrect):
     print(PICS[Incorrect])
    # This function is a bit of a redundancy and you shouldn't need it.
    
  5. Wording?

    def Hint(Incorrect, WordChoice): #This function prints a hint when the player gets down to their last two guesses
     if Incorrect == 6:
    

    Do you mean:

    if Incorrect >= 6:
    
  6. Consider selecting random words from a text file instead.

    List1 = ["fable", ....]
    

    Try to pick a more description variable name. Also, you shouldn't store large constants like this in your program. What you can do is store them in a text file and read them in from the program.

    words.txt:
    fable
    surf
    english
    paris
    ...
    Code:
    with open("words.txt") as f:
     List1 = f.read().strip().split('\n')
    

    Look up file manipulation in Python.

  7. ???

    Infinity = 9999999999999999999999999999999999
    

    LOL. Technically not infinity, your program would theoretically end if I played until the heat death of the universe. It seems like you're using it for a infinite loop. Why don't you use a while loop instead? An infinite while loop looks like this:

    while True:
     # code in here will loop infinitely
     break # This statement exits the loop
    
  8. Descriptive variable names

    List2 = []
    

    Again, pick a more useful variable name. You want to be able to come back to this in 5 years and still understand what is going on.

  9. Don't repeat yourself.

    if LetterCount == 1: #Prints the 'mystery' words length with underscores and spaces
     L = ("_")
     print(L.replace("", " ")[1: -1], "\n")
    if LetterCount == 2:
     L = ("__")
     print(L.replace("", " ")[1: -1], "\n")
    ...
    

    You don't need parentheses when declaring a string.

    L = "_"
    

    Furthermore, you can achieve this with the following code:

    L = "_" * LetterCount
    

    This shortens your code to:

    if LetterCount >= 1 and LetterCount <= 10:
     L = "_" * LetterCount
     print(L.replace("", " ")[1: -1], "\n")
    

    You should feel suspicious any time you're repeating the same code over and over. Consider refactoring into another function whenever that happens.

  10. Avoid using sys.exit() to exit your programs. It's like killing your program with a chainsaw. Use a return or break to end the code flow. It's good practice to wrap your main code in a main() function or if __name__ == '__main__': guard.

Python is a great language and you're off to a good start. Keep at it and happy coding.

answered Jul 26, 2017 at 9:27
\$\endgroup\$
5
  • 1
    \$\begingroup\$ About #7: In Python 2, it would take until the heat death of the universe before you can start playing. (Assuming you have several Yottabytes of swap.) // Python 2's range() returns a list, while Python 3's range() and Python 2's xrange are implemented as generators. \$\endgroup\$ Commented Jul 26, 2017 at 15:53
  • \$\begingroup\$ Ah yes that's right. I assumed Python 3 because OP used Python 3 style print statements. \$\endgroup\$ Commented Jul 26, 2017 at 18:26
  • \$\begingroup\$ I know, I just wanted to point out. Writing Python code that works with both Python 2 and 3 is relatively easy, I usually do this myself. If you pay just a little attention to various small details, your code will work both on modern systems where 3 is the default version and on legacy systems where Python 3 is unavailable. // PS. Python 3 does not have a print statement, it's a function. And that syntax works in Python 2 too. \$\endgroup\$ Commented Jul 26, 2017 at 19:19
  • 1
    \$\begingroup\$ Most people using Python 2 without the need for forwards compatibility would not use parentheses simply because it's easier to type. I know for quick one-off scripts, I'll prefer writing it that way. \$\endgroup\$ Commented Jul 26, 2017 at 20:40
  • \$\begingroup\$ I know. Just wanted to point out about range. :-) \$\endgroup\$ Commented Jul 26, 2017 at 22:13
6
\$\begingroup\$

Temporary review, I'll try to improve it.

Style

Python has a style guide called PEP 8. It is definitly worth reading and following (except if you have good reasons not to).

You'll find various tools to check your code compliancy to PEP 8.

Among the major "problems" in your code, variable should be lower_case_with_underscores.

To infinity and beyond

for i in range(Infinity): could and should be written while True:.

If you actually need an infinite counter, you can use itertools.count

Regarding "Prints the 'mystery' words length with underscores and spaces

You are using multiple multually exclusive conditions, you could use elif.

Also, you are using useless parentheses, you could write L = "____".

Instead of writing the different strings with n underscores, you could write : L = "_" * LetterCount.

You could use join to add spaces between the underscores instead of using replace and slice selection.

Thus, the whole code becomes:

print(" ".join('_' * LetterCount), "\n")
answered Jul 26, 2017 at 8:44
\$\endgroup\$
0
5
\$\begingroup\$

Both answer are nice and cover everything, just one thing for your def PicNo. Most of the time, if i have more than 3 if, i'll just go for a switch with a dictionary :

def PicNo(Incorrect):
 switcher = {
 0: '''
 +---+
 | |
 |
 |
 |
 |
========='''
 1: "2nd pic",
 2: "3rd pic",
 }
 return switcher.get(Incorrect, "Default pic")
200_success
146k22 gold badges190 silver badges479 bronze badges
answered Jul 26, 2017 at 12:08
\$\endgroup\$
2
  • 2
    \$\begingroup\$ In the future you should pay more attention to the code in the code block. (I've edited for you this time.) // I've heard that the easiest way to insert code is to paste it, highlight it and then press Ctrl+K. \$\endgroup\$ Commented Jul 26, 2017 at 15:55
  • \$\begingroup\$ ooooooh I wasn't aware of that. Thanks! I was always using the arrows then "space space space space" like a monkey \$\endgroup\$ Commented Jul 27, 2017 at 11:27
3
\$\begingroup\$
  • All your variables and functions' names do not respect the naming conventions as described here.
  • Your comments are too long, so it is better to write them just before the corresponding line of code and span them on multiple short lines if necessary.
  • Those multiple if statements can be refactored using a dictionary (as described here, for example)
answered Jul 26, 2017 at 13:23
\$\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.