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.
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.
_ _ _ _ _ _
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.
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.
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.
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.
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.
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.
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:
- If the input is empty, print "please type a letter" and ask again.
- If the input is more than one character, print "type one letter at a time" and ask again.
- 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.
Enter a letter: please type a letter Enter a letter: py type one letter at a time Enter a letter: 1 that'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.
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.
Enter a letter: a nope. lives: 5 _ _ _ _ _ Enter a letter: n correct! _ _ n _ _
Add ASCII hangman art and clean exit
Two polish moves:
- At the start of each game, print a welcome message.
- 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.
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.