Starterpython~60 min

🪢 Hangman

Build the classic terminal Hangman: pick a secret word, reveal letters as the player guesses, lose lives on misses, win when the word's complete. You'll touch lists, sets, conditional flow, and the game-loop shape.

You're going to build the classic word-guessing game, Hangman. Pick a secret word, reveal letters as the player guesses, track their lives (starting at 6), and end the game when they win (word complete) or lose (lives reach 0). By the end you'll have a working game you can play again and again — and you'll have used lists, sets, game state, and the loop patterns that power every interactive game.

We're not racing. Each step is one idea. If a hint helps, take it — there's no penalty.

Before you start

Modern macOS ships Python 3 — try python3 --version. If it's older than 3.10, install via Homebrew: brew install python@3.12.

The walkthrough

Make the project file

In your terminal, inside the hangman folder, create an empty file called hangman.py. Open it in your editor.

You can do this any way you like — touch hangman.py, code hangman.py, "File → New" in your editor, whatever's natural for you.

After this step your file should look like… (hangman.py)

Pick a secret word

In hangman.py, hardcode a secret word as a variable. Print how many letters it has (as blanks). For example, if the word is "python", print _ _ _ _ _ _.

Run your program to confirm it works.

After this step you should see…
_ _ _ _ _ _

Show blanks that update when letters match

Store the current game state — which letters have been guessed. Start with all blanks. When you reveal a letter (we'll code the guess logic next), update the display so the correct position shows the letter, not the blank.

For now, hardcode a test: reveal the letter "p" in the word "python" and print the result.

After this step you should see…
p _ _ _ _ _

Ask the player for a letter

Add code to prompt the player for a guess. Read one character from input(). Convert it to lowercase so the game is case-insensitive (the player can type P or p).

For now, don't process the guess yet — just print what they typed.

After this step you should see…
Enter a letter: P
you guessed: p

Reveal the guessed letter if it's in the word

After the player guesses, check whether the letter is in the word. If it is, print something like "correct!". If it's not, print "nope" or similar. Then display the blanks (with any newly-revealed letters shown).

For now, still just one guess — no loop yet.

After this step you should see…
Enter a letter: p
correct!
p _ _ _ _ _

Remember all guessed letters and prevent duplicates

Create a set to track guesses the player has already made. Each turn, before processing the guess, check if they've already guessed that letter. If so, print "you already guessed that" and skip to the next turn (don't re-check or reveal anything).

If it's a new guess, add it to the set, then check if it's in the word.

After this step you should see…
Enter a letter: p
correct!
p _ _ _ _ _
Enter a letter: y
correct!
p y _ _ _ _
Enter a letter: p
you already guessed that
p y _ _ _ _

What does `guessed.add('p')` do if 'p' is already in the set?

Detect when the player has won

After each guess, check if the player has revealed all the letters. The win condition is: every letter in the word has been guessed.

When that happens, print a congratulations message and stop the game.

After this step you should see…
Enter a letter: p
correct!
p _ _ _ _ _
Enter a letter: y
correct!
p y _ _ _ _
Enter a letter: t
correct!
p y t _ _ _
Enter a letter: h
correct!
p y t h _ _
Enter a letter: o
correct!
p y t h o _
Enter a letter: n
correct!
p y t h o n
you won!

Track lives and lose when they run out

Add a lives counter starting at 6. When the player guesses a letter that's not in the word, subtract one life. When lives reach 0, the game ends — print "you lost!" and reveal the word.

After this step you should see…
Enter a letter: a
nope. lives: 5
_ _ _ _ _ _
Enter a letter: e
nope. lives: 4
_ _ _ _ _ _
Enter a letter: p
correct!
p _ _ _ _ _
Enter a letter: z
nope. lives: 3
p _ _ _ _ _

Handle empty and non-letter input

Right now, if the player types nothing (just presses Enter) or types a number or symbol, the code might crash or behave strangely. Add checks:

  1. If the input is empty, print "please type a letter" and ask again.
  2. If the input is more than one character, print "type one letter at a time" and ask again.
  3. If it's not a letter (contains numbers or symbols), print "that's not a letter" and ask again.

Use an <Glossary term="exception">exception</Glossary> handler to safely check if the input is alphabetic.

After this step you should see…
Enter a letter: 
please type a letter
Enter a letter: py
type one letter at a time
Enter a letter: 1
that&apos;s not a letter
Enter a letter: p
correct!
p _ _ _ _ _

Wrap it in a loop so the player can play again

Wrap the whole "ask + validate + process + check win/lose" sequence in a while True: loop. When the game ends (win or lose), ask the player "play again?" and loop back to the top, or break to exit.

After this step you should see…
Enter a letter: p
correct!
p _ _ _ _ _
Enter a letter: y
correct!
p y _ _ _ _
Enter a letter: t
correct!
p y t _ _ _
Enter a letter: h
correct!
p y t h _ _
Enter a letter: o
correct!
p y t h o _
Enter a letter: n
correct!
p y t h o n
you won!
play again? (y/n): y
Enter a letter: a
nope. lives: 5
_ _ _ _ _ _

Pick from a list of words randomly

Instead of hardcoding "python", create a small list of words. Import Python's random module and use random.choice(words) to pick a new word each game.

After this step you should see…
Enter a letter: a
nope. lives: 5
_ _ _ _ _
Enter a letter: n
correct!
_ _ n _ _

Add ASCII hangman art and clean exit

Two polish moves:

  1. At the start of each game, print a welcome message.
  2. Every time lives change, print a simple ASCII hangman figure at that lives level (you can use text art like O, |, /, \\ stacked at different heights, or just descriptive text like "head", "body", etc.).

For example:

lives: 6    (empty)
lives: 5    (head)
    O
lives: 4    (body)
    O
    |
lives: 3    (left arm)
   /|
    O
... and so on.

Add a goodbye message when the player exits.

After this step you should see…
Welcome to Hangman!
_ _ _ _ _ _
Enter a letter: a
nope.
  O
 
lives: 5
_ _ _ _ _ _
Enter a letter: p
correct!
p _ _ _ _ _

You did it

Run python3 hangman.py and play a few rounds. Try invalid input (empty, symbols, multiple letters). Win, lose, play again. Take a screenshot — that thing didn't exist a few hours ago.

You wrote:

  • a Python file that picks random words
  • input validation and type-safe parsing
  • tracking game state (guessed letters, lives) across multiple turns
  • a set for fast membership checks
  • win/lose detection logic
  • an ASCII hangman figure that updates visually
  • a nested loop structure (outer game loop, inner guess loop)
  • error handling for edge cases
  • a "play again" prompt with clean exit

Every one of those is a thing you'll use again — in the next project, in your job, in everything.

Stretch goals