How to Build a Simple Hangman Game in Python, Beginner's Tutorial
There's a lot of different ways to build a Hangman game in Python. but I think I've found a way that makes it a little simpler than the methods of looping through a string. I want to spend a bit of time going over the core concept before we really get into the code. You can follow along in an editor, but feel free to skip ahead.
I'm going to show two ways of completing this game. First, we're going to let Python handle the work with the .find() method, then do the work manually by looping through the string while checking.
This tutorial isn't going to touch on anything like functions or classes, and it may get a little unpythonic because I want to keep things as simple as possible for now.
This tutorial is assuming that you're already familiar with concepts like:
- variables,
- lists,
- indexing,
- loops,
- if statements,
- and basic math operators
===================================================
Option 1: using the .find() string method
1: Let's start with the .find() method. The .find() string method searches the string on the left for the string on the right, and returns the index location of where it first finds it.
print("CAT".find("A"))
This will print out 1, because "A" is at index location 1 ( The three letters of "CAT" are at 0, 1, and 2).
2: Next, we can take that index location and plug it into another string to locate something.
print("abc"["CAT".find("A")])
This will print out b, because the brackets point to an index location in "abc", and the contents of the bracket are equal to 1. It's the same as if we entered print("abc"[1])
3: Now let's look at list mutability. We can use an index number to locate and then change a list item, by assigning it with =.
list1 = ["_", "_", "_"]
list1[1] = "A"
print(list1)
Now this will print out ["_", "A", "_"]. We have changed the list, and replaced the second item (index 1) with string "A".
4: We can clean up a list a little bit with the .join() method, which will change it into a string. The left side of .join() is for separators, the right side is the list that's going to be joined
list1 = ["_", "A", "_"]
print(" ".join(list1))
This will print out _ A _. No quotes, no brackets, the list is now a string.
5: So, let's combine all of this.
answer = "CAT"
display = ["_", "_", "_"]
letter = "A"
display[answer.find(letter)] = letter
print(" ".join(display))
This will again print out _ A _. So this one line here, display[answer.find(letter) = letter, handles a good chunk of the workload of our hangman game, because it is searching for the location of the letter in the answer, locating it in the display list, and inserting it.
6: Let's make this a little interactive with an input and a loop now. For the input, we'll use [0] to just grab the first letter, and .upper() to ensure that it matches our case. We'll leave the initial variables outside of the loop, because we only need to set them one time. There's a number of different ways to start a loop, while True: is one of the easiest if you have no conditions.
answer = "CAT"display = ["_", "_", "_"]
while True:
letter = input("Guess a letter: ")[0].upper()
display[answer.find(letter)] = letter
print(" ".join(display))
Congratulations! You've almost got a functional Hangman game already! Although it's not very fun to play right now, and it's very easily broken. There's no way to win or lose, so let's start with that.
7: Let's set up a win and life counter, and then we modify those counters inside the loop. Once again, we'll set these variables outside the loop, they only need to be set once. We'll check right or wrong with some if/else statements.
So we have to ask ourselves, what do we want to happen for each check?
- If the letter is in the answer, we should be one step closer to winning and place the letter in the display.
- Else, we should be one step closer to losing, and we'll tell the player.
answer = "CAT"
display = ["_", "_", "_"]
win = 0
life = 6
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
win += 1
display[answer.find(letter)] = letter
else:
life -= 1
print(f"Nope! {life} tries left")
print(" ".join(display))
Okay, we've got a score and a life now, but way to end the game.
8: Now we'll give ourselves an ending, by checking the win and life counters. If the counters reach a winning or losing state, we'll tell the player and end the loop, ending the script.
So we again have to ask ourselves, what do we want to happen for each check?
- If we guess right enough times we should win, and break the loop.
- If we run out of tries we should lose, and break the loop.
answer = "CAT"
display = ["_", "_", "_"]
win = 0
life = 6
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
win += 1
display[answer.find(letter)] = letter
else:
life -= 1
print(f"Nope! {life} tries left")
if win >= 3:
print("You win!")
break
if life <= 0:
print("The man has been hung.")
break
print(" ".join(display))
print(f"\nThanks for playing!\nThe word was {answer}")
Technically, this is a fully functional game now. You can play, you can win, and you can lose. But it's still not very fun. Let's go ahead and randomize the word.
9: First off, not all words are 3 letters. So we're going to need to change the code a bit to work with different answer lengths, or len(answer). We can use list comprehension to adjust the length of the dashes. Multiplying a list concatenates it, just like with strings. ["W"] * 3 = ["W", "W", "W"] just like "W" * 3 = "WWW"
Finally, we'll have to import the random module.
(Note: one limitation of using a simple .find() method like this is that it only returns the FIRST instance of that letter, so just to keep things simple, only choose words that have no repeating letters for now.)
import random
word_list = ["CAT", "SHAKE", "DOGS", "ROAD", "SMITH",
"RADIO", "MARK", "SPOT", "MATCHES"]
answer = random.choice(word_list)
display = ["_"] * len(answer)
win = 0
life = 6
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
win += 1
display[answer.find(letter)] = letter
else:
life -= 1
print(f"Nope! {life} tries left")
if win >= len(answer):
print("You win!")
break
if life <= 0:
print("The man has been hung.")
break
print(" ".join(display))
print(f"\nThanks for playing!\nThe word was {answer}")
10: One part of the hangman game is to write down the wrong guesses. To do this, we'll create a blank list and append wrong guesses to it, then display it with .join().
import random
word_list = ["CAT", "SHAKE", "DOGS", "ROAD", "SMITH",
"RADIO", "MARK", "SPOT", "MATCHES"]
answer = random.choice(word_list)
display = ["_"] * len(answer)
win = 0
life = 6
wrong = []
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
win += 1
display[answer.find(letter)] = letter
else:
life -= 1
wrong.append(letter)
print(f"Nope! {life} tries left")
if win >= len(answer):
print("You win!")
break
if life <= 0:
print("The man has been hung.")
break
print(" ".join(display))
print("Wrong guesses:", ", ".join(wrong))
print(f"\nThanks for playing!\nThe word was {answer}")
11: Let's draw a man hanging with some simple ASCII art.
print("""
----|---
| 0
| /|\\
| / \\
========""")
Why did I add extra right arms? Because \ is an escape character in strings, used for escapes like \n and \t, and adding one \ by itself will cause an error. If we want to show a \, we need to escape it with \\.
12: Now let's take that drawing and make a list of drawings like it in various stages of completion. The syntax might make it look a little wonky now, but it's still the same
hanglist = ["""----|---|
|
|
========""", """----|---
| 0
|
|
========""", """----|---
| 0
| |
|
========""", """----|---
| 0
| /|
|
========""", """----|---
| 0
| /|\\
|
========""", """----|---
| 0
| /|\\
| /
========""", """----|---
| 0
| /|\\
| / \\
========"""]
There's ways to draw this shorter in a more compact space, but we've got plenty of space to work with.
13: Let's add that list into the game and call upon it to display the man now! We can set it to display based on the index number of lives left, and we can display it every turn. Since the lives are counting down while the list is counting up, we'll subtract. Also we'll display the man one more time after losing.
import randomword_list = ["CAT", "SHAKE", "DOGS", "ROAD", "SMITH",
"RADIO", "MARK", "SPOT", "MATCHES"]
answer = random.choice(word_list)
display = ["_"] * len(answer)
win = 0
life = 6
wrong = []
hang_list = ["""----|---
|
|
|
========""", """----|---
| 0
|
|
========""", """----|---
| 0
| |
|
========""", """----|---
| 0
| /|
|
========""", """----|---
| 0
| /|\\
|
========""", """----|---
| 0
| /|\\
| /
========""", """----|---
| 0
| /|\\
| / \\
========"""]
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
win += 1
display[answer.find(letter)] = letter
else:
life -= 1
wrong.append(letter)
print(f"Nope! {life} tries left")
if win >= len(answer):
print("You win!")
break
if life <= 0:
print(hang_list[6])
print("The man has been hung.")
break
print(" ".join(display))
print(hang_list[6 - life])
print("Wrong guesses:", ", ".join(wrong))
print(f"\nThanks for playing!\nThe word was {answer}")
===================================================
Option 2: Using a loop to search through the string
word_list = ["CAT", "SHAKE", "DOGS", "ROLL", "CHECK",
"RADIO", "TARTAR", "SPOTS", "CATCHES"]
answer = random.choice(word_list)
display = ["_"] * len(answer)
win = 0
life = 6
wrong = []
hang_list = ["""----|---
|
|
|
========""", """----|---
| 0
|
|
========""", """----|---
| 0
| |
|
========""", """----|---
| 0
| /|
|
========""", """----|---
| 0
| /|\\
|
========""", """----|---
| 0
| /|\\
| /
========""", """----|---
| 0
| /|\\
| / \\
========"""]
while True:
letter = input("Guess a letter: ")[0].upper()
if letter in answer:
life -= 1
wrong.append(letter)
print(f"Nope! {life} tries left")
if win >= len(answer):
print("You win!")
break
if life <= 0:
print(hang_list[6])
print("The man has been hung.")
break
print(" ".join(display))
print(hang_list[6 - life])
print("Wrong guesses:", ", ".join(wrong))
print(f"\nThanks for playing!\nThe word was {answer}")
Comments
Post a Comment