Skip to content

Hangman Game

Hangman is the perfect “second game” project. It is more complex than Rock-Paper-Scissors but still fits in one file. You learn file I/O (loading a word list), random selection, sets (tracking guessed letters), string assembly (showing the partially-revealed word), and game-state management (win, lose, keep going). In this tutorial you will build the classic version with a word list, then layer in ASCII-art gallows, input validation, category selection, score tracking, hints, and a replay loop.

You will learn:

  • Why set is the right structure for “letters already guessed”.
  • How to reveal a word letter-by-letter from a hidden secret.
  • How to draw step-by-step ASCII art from a list of stages.
  • How to organize game state into clean functions.
  • How to extend a beginner game with categories, hints, and persistence.
  1. The computer picks a secret word.
  2. The player sees blanks: _ _ _ _ _ _ _.
  3. Player guesses one letter at a time.
  4. Correct letters fill in their positions.
  5. Wrong letters cost one “limb” of the hanged figure.
  6. Player wins by completing the word; loses if the figure is fully drawn first.
  • Python 3.6 or above.
  • A code editor or IDE.
  • A text file of words (we will make one).
  • Comfort with while loops, if/else, and basic file reading.
  1. Create a folder named hangman-game.
  2. Inside it, create hangman.py.
  3. Create words.txt next to it. Suggested starter contents:
    words.txt
    python
    programming
    computer
    science
    technology
    development
    software
    coding
    algorithm
    function
    variable
    recursion
    compiler
    interpreter
Hangman pch.viewSource
Hangman
# Hangman game
# -----------------------------------

# Importing the random module
import random
import time

# Inputting the name of the user
name = input("What is your name? ")
print("Good Luck ! ", name)

time.sleep(1)

print("The game is about to start !")
print("Let's play Hangman")

time.sleep(1)

open_file = open("words.txt", "r")
words = open_file.readlines()

# Function will choose one random
# word from this list of words
word = random.choice(words)
word = word.lower().strip().replace("\n", "").replace("\r", "").replace(" ", "").replace("-", "")
print("Guess the characters")

guesses = ''
turns = len(word) * 2 

# Checks if the turns are more than zero
while turns > 0:
    failed = 0

    # for every character in secret_word
    for char in word:

        # see if the character is in the players guess
        if char in guesses:
            print(char, end="")

        else:
            print("_", end="")

            # and increase the failed counter with one
            failed += 1

    if failed == 0:
        print("\nYou Win")

        # this print the correct word
        print("The word is: ", word)
        break

    # if failed equals to zero
    # then you will get this message
    if turns == 1:
        print("\nYou have", turns, 'more guess')
    else:
        print("\nYou have", turns, 'more guesses')

    guess = input("guess a character: ")

    # every input character will be stored in guesses
    guesses += guess

    # check input with the character in word
    if guess not in word:

        turns -= 1

        # if the character doesn’t match the word
        # then “Wrong” will be given as output
        print("Wrong")

        # this will print the number of
        # turns left for the user
        if turns == 1:
            print("\nYou have", turns, 'more guess')
        else:
            print("\nYou have", turns, 'more guesses')

        if turns == 0:
            print("\nYou Loose")
            print("\nThe word is: ", word)
            break
command
C:\Users\Your Name\hangman-game> python hangman.py
What is your name? John
Good luck, John! Let's play Hangman.
Word: _ _ _ _ _ _ _
Guesses left: 6
Guess a letter: p
Word: p _ _ _ _ _ _
Guess a letter: ...
hangman.py
import random
import time

random.choice picks the word. time.sleep adds drama.

hangman.py
with open("words.txt", encoding="utf-8") as f:
    words = [line.strip().lower() for line in f if line.strip()]
word = random.choice(words)

Reading inside a with block ensures the file is closed automatically. The list comprehension strips trailing newlines and skips empty lines.

hangman.py
guessed_letters = set()
wrong = 0
max_wrong = 6

Why a set for guessed_letters?

  • letter in guessed_letters is O(1).
  • Adding a duplicate is harmless.
  • It mirrors the natural language of the rules — “have I guessed this letter already?”
hangman.py
def display(word: str, guessed: set[str]) -> str:
    return " ".join(c if c in guessed else "_" for c in word)

A list/generator comprehension over the secret word: keep characters the player has guessed, otherwise show _. " ".join(...) spaces them out for readability.

hangman.py
while wrong < max_wrong:
    print(f"\n{display(word, guessed_letters)}")
    print(f"Guesses left: {max_wrong - wrong}")
    guess = input("Guess a letter: ").lower().strip()
 
    if len(guess) != 1 or not guess.isalpha():
        print("Enter a single letter.")
        continue
    if guess in guessed_letters:
        print("Already guessed.")
        continue
 
    guessed_letters.add(guess)
    if guess in word:
        if all(c in guessed_letters for c in word):
            print(f"\n🎉 You win! The word was '{word}'.")
            break
    else:
        wrong += 1
        print("Wrong!")
else:
    print(f"\nYou lost. The word was '{word}'.")

Several patterns in play:

  • Input validation rejects multi-char or non-alphabetic input.
  • Duplicate detection uses the set.
  • Win check asks “are every letter of the word now in guessed?”all(...) is the right tool.
  • else clause on a while runs only if the loop ended normally (the player ran out of guesses). It is a lesser-known but elegant feature of Python.

A 7-frame gallows that draws progressively as the player loses:

gallows.py
STAGES = [
    r"""
       -----
       |   |
           |
           |
           |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
           |
           |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
       |   |
           |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
      /|   |
           |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
      /|\  |
           |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
      /|\  |
      /    |
           |
    =========""",
    r"""
       -----
       |   |
       O   |
      /|\  |
      / \  |
           |
    =========""",
]
 
print(STAGES[wrong])     # in the main loop

Six wrong guesses → seven stages (0 wrong = empty gallows, 6 wrong = full hangman). The r"""...""" is a raw triple-quoted string — backslashes inside stay literal.

ProblemCauseFix
Word contains a newline characterForgot .strip() after readlines()Use the list-comp above
Capital letters never matchMixed casesLowercase both the word and the guess
Pressing Enter empty crashes the gameNo length checkValidate len(guess) == 1
Counting wrong letters when a duplicate is pressedNo duplicate checkSkip already-guessed letters
Win never triggersUsed == instead of all(... in ...)Use all(c in guessed_letters for c in word)

Store one word list per category:

text
fruits.txt
animals.txt
programming.txt

Ask the user to pick a category. Each .txt becomes a Path:

categories.py
from pathlib import Path
cats = {p.stem: p for p in Path("words").glob("*.txt")}
choice = input(f"Pick: {', '.join(cats)}\n> ")
words = cats[choice].read_text().splitlines()
  • Easy: 4–6 letter words, 8 guesses.
  • Medium: 7–9 letter words, 6 guesses.
  • Hard: 10+ letter words, 5 guesses, only common letters give hints.

Give a hint after N wrong guesses — reveal one letter automatically:

hint.py
if wrong == 4:
    for c in word:
        if c not in guessed_letters:
            print(f"Hint: contains '{c}'")
            guessed_letters.add(c)
            break

A win earns (letters - wrong) * 10 points. Persist between sessions in a JSON file. See Personal Diary for the same persistence pattern.

replay.py
while True:
    play_round()
    if input("Play again? (y/n): ").lower() != "y":
        break

Player 1 enters the word secretly (getpass.getpass hides it from the terminal); Player 2 guesses.

Tkinter with a letter-grid of buttons and an image-based gallows. See Basic Music Player for the GUI pattern.

Flask plus a single HTML page. The state lives in the user’s session. See Basic Web Server.

Pull a random English word from a dictionary API instead of words.txt:

api_word.py
import requests
word = requests.get("https://random-word-api.herokuapp.com/word").json()[0]

After the round, look up the word’s definition using pip install nltk + the WordNet corpus, and show it to teach vocabulary.

For a serious version, wrap state in a class:

hangman_class.py
class Hangman:
    def __init__(self, word: str, max_wrong: int = 6):
        self.word = word.lower()
        self.guessed: set[str] = set()
        self.wrong = 0
        self.max_wrong = max_wrong
 
    def guess(self, letter: str) -> str:
        letter = letter.lower()
        if letter in self.guessed:
            return "duplicate"
        self.guessed.add(letter)
        if letter not in self.word:
            self.wrong += 1
            return "miss"
        return "hit"
 
    @property
    def display(self) -> str:
        return " ".join(c if c in self.guessed else "_" for c in self.word)
 
    @property
    def is_won(self) -> bool:
        return all(c in self.guessed for c in self.word)
 
    @property
    def is_lost(self) -> bool:
        return self.wrong >= self.max_wrong

Now the game logic is testable without input() — perfect for unit tests.

  • Vocabulary teaching — a hangman with curated word lists works in language learning apps.
  • CAPTCHA-style verification in a friendly form.
  • Conference / classroom icebreaker — group hangman on a projector.
  • Onboarding gamification — turn product terminology into a guessing game.

This project teaches:

  • File I/O — reading lists from text files.
  • Sets — O(1) membership tests and natural-language semantics.
  • String manipulation — partial reveal, comparison, validation.
  • Game-state management — wrong count, guessed letters, win/lose conditions.
  • Refactoring — moving from a script to a class for testability.
  • Build the ASCII-art version with the STAGES list above.
  • Add categories and difficulty levels.
  • Wrap state in a Hangman class and add unit tests with pytest.
  • Build a GUI or web version.
  • Use a real word API so the dictionary never runs out.

You built a complete Hangman game from a 50-line script: file loading, secret picking, partial reveal, input validation, win/lose conditions, and ASCII-art gallows. The same patterns power dozens of guessing games and quiz apps. Full source on GitHub. Explore more games on Python Central Hub.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading