Build a Hangman Game in Python

Published on: July 10, 2026
Reading time: 5 minutes
Jogo da forca para iniciantes desenvolvido com Python

Hangman is a classic terminal project for practicing strings, sets, loops, conditions, random selection, input validation, and functions. The computer chooses a secret word, the player guesses one letter at a time, correct letters are revealed, and incorrect guesses reduce the remaining lives.

This tutorial builds a complete Hangman game in Python. The final program prevents repeated guesses, validates letters, supports whole-word guesses, displays simple ASCII stages, gives hints, separates game logic into testable functions, and lets the player start another round.

The secret word is selected with the Python random module. Lists and sets hold words and guesses; review the Python lists guide when necessary.

How Hangman Works

  1. Choose a secret word.
  2. Display an underscore for every hidden letter.
  3. Read one letter or a complete-word guess.
  4. Reveal every matching letter.
  5. Reduce lives after a wrong new guess.
  6. Continue until the word is complete or lives reach zero.

The official random.choice() documentation defines the selection function. The Python string methods documentation covers methods such as lower(), strip(), and isalpha().

Choose a Secret Word

import random

WORDS = ["python", "variable", "function", "iterator", "package"]
secret_word = random.choice(WORDS)

The standard random module is appropriate here because the game does not protect a secret with security consequences.

Represent Guessed Letters with a Set

A set stores each letter once and makes membership checks clear:

guessed_letters = set()

guessed_letters.add("p")
print("p" in guessed_letters)  # True

Using a set prevents duplicate letters from appearing in the history and lets the program detect repeated input without scanning a list manually.

Build the Masked Word

def masked_word(secret_word, guessed_letters):
    return " ".join(
        letter if letter in guessed_letters else "_"
        for letter in secret_word
    )


print(masked_word("python", {"p", "o"}))
# p _ _ _ o _

The function returns display text and does not print it directly. This makes it reusable and easy to test.

Check Whether the Word Is Complete

def word_is_complete(secret_word, guessed_letters):
    return all(letter in guessed_letters for letter in secret_word)

all() returns true only when every letter satisfies the condition. Repeated letters do not need special handling because checking membership reveals every occurrence.

Validate the Player’s Input

Accept a single alphabetic letter or a full alphabetic word:

def read_guess():
    while True:
        guess = input("Guess a letter or the whole word: ").strip().lower()

        if not guess:
            print("Enter a letter or word.")
            continue

        if not guess.isalpha():
            print("Use letters only.")
            continue

        return guess

isalpha() accepts letters beyond plain English ASCII. If a word list uses accents, normalize words and guesses consistently.

Handle Repeated Guesses

Do not remove a life for a letter the player already tried:

if guess in guessed_letters:
    print("You already tried that letter.")
    continue


guessed_letters.add(guess)

A whole-word guess can be tracked in a separate set when repeated word attempts should also be ignored.

Create Simple Hangman Stages

Store one drawing for each number of wrong guesses. The first stage is empty and the last is complete.

HANGMAN_STAGES = [
    """
     +---+
     |   |
         |
         |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
         |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
     |   |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|   |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
    /    |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
    / \  |
         |
    =========
    """,
]

With seven stages, the player can make six incorrect guesses. The current drawing is HANGMAN_STAGES[wrong_guesses].

Add Words and Hints

A list of dictionaries keeps each word beside a hint:

WORD_BANK = [
    {"word": "python", "hint": "A popular programming language"},
    {"word": "iterator", "hint": "Produces values one at a time"},
    {"word": "function", "hint": "Reusable block of behavior"},
    {"word": "variable", "hint": "A name that refers to a value"},
    {"word": "package", "hint": "Distributable collection of modules"},
]

Hints make uncommon words fairer and let the project teach vocabulary at the same time.

Complete Hangman Game

import random

HANGMAN_STAGES = [
    """
     +---+
     |   |
         |
         |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
         |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
     |   |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|   |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
         |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
    /    |
         |
    =========
    """,
    """
     +---+
     |   |
     O   |
    /|\  |
    / \  |
         |
    =========
    """,
]

WORD_BANK = [
    {"word": "python", "hint": "A popular programming language"},
    {"word": "iterator", "hint": "Produces values one at a time"},
    {"word": "function", "hint": "Reusable block of behavior"},
    {"word": "variable", "hint": "A name that refers to a value"},
    {"word": "package", "hint": "Distributable collection of modules"},
]


def masked_word(secret_word, guessed_letters):
    return " ".join(
        letter if letter in guessed_letters else "_"
        for letter in secret_word
    )


def word_is_complete(secret_word, guessed_letters):
    return all(letter in guessed_letters for letter in secret_word)


def read_guess():
    while True:
        guess = input("Guess a letter or the whole word: ").strip().lower()

        if not guess:
            print("Enter a letter or word.")
            continue

        if not guess.isalpha():
            print("Use letters only.")
            continue

        return guess


def play_round(generator=None):
    generator = generator or random.Random()
    entry = generator.choice(WORD_BANK)
    secret_word = entry["word"].lower()
    hint = entry["hint"]
    guessed_letters = set()
    guessed_words = set()
    wrong_guesses = 0
    maximum_wrong = len(HANGMAN_STAGES) - 1

    print(f"Hint: {hint}")

    while wrong_guesses < maximum_wrong:
        print(HANGMAN_STAGES[wrong_guesses])
        print(masked_word(secret_word, guessed_letters))
        print(f"Lives: {maximum_wrong - wrong_guesses}")

        if guessed_letters:
            print("Letters:", " ".join(sorted(guessed_letters)))

        guess = read_guess()

        if len(guess) == 1:
            if guess in guessed_letters:
                print("You already tried that letter.")
                continue

            guessed_letters.add(guess)

            if guess in secret_word:
                print("Correct letter!")
            else:
                wrong_guesses += 1
                print("That letter is not in the word.")
        else:
            if guess in guessed_words:
                print("You already tried that word.")
                continue

            guessed_words.add(guess)

            if guess == secret_word:
                guessed_letters.update(secret_word)
            else:
                wrong_guesses += 1
                print("That is not the secret word.")

        if word_is_complete(secret_word, guessed_letters):
            print(masked_word(secret_word, guessed_letters))
            print("You won!")
            return True

    print(HANGMAN_STAGES[wrong_guesses])
    print(f"You lost. The word was: {secret_word}")
    return False


def wants_to_play_again():
    while True:
        answer = input("Play again? [y/n]: ").strip().lower()

        if answer in {"y", "yes"}:
            return True

        if answer in {"n", "no"}:
            return False

        print("Enter y or n.")


def main():
    print("Python Hangman")

    while True:
        play_round()

        if not wants_to_play_again():
            print("Thanks for playing!")
            break


if __name__ == "__main__":
    main()

Save the program as hangman.py and run:

python hangman.py

Test the Core Functions

from hangman import masked_word, word_is_complete


def test_masked_word():
    result = masked_word("letter", {"l", "e", "r"})
    assert result == "l e _ _ e r"


def test_word_is_complete():
    assert word_is_complete("cat", {"c", "a", "t"}) is True
    assert word_is_complete("cat", {"c", "a"}) is False

The Python unit testing guide explains assertions and mocks. A seeded random.Random instance can make word selection predictable during a larger test.

Debug the Game

Set breakpoints where guesses are added and where wrong_guesses changes. Inspect secret_word, guessed_letters, and guess. The VS Code debugging guide covers conditional breakpoints and variable inspection.

Load Words from a Text File

from pathlib import Path


def load_words(path):
    lines = Path(path).read_text(encoding="utf-8").splitlines()
    words = [line.strip().lower() for line in lines]
    return [word for word in words if word.isalpha()]

Validate that the returned list is not empty before calling choice(). The Python pathlib guide explains file paths and text methods.

Common Mistakes

  • Reducing a life for a repeated letter.
  • Revealing only one occurrence when a letter appears several times.
  • Mixing uppercase words with lowercase guesses without normalization.
  • Accepting digits or punctuation as guesses.
  • Calling random.choice() on an empty word list.
  • Putting all logic inside one long interactive loop.
  • Using broad exception handling to hide unrelated programming errors.
  • Testing only through manual gameplay instead of testing pure functions.

Ideas to Extend the Game

  • Add categories and difficulty levels.
  • Allow a limited number of hints.
  • Save wins and losses to JSON.
  • Use words loaded from separate category files.
  • Add colors to terminal output.
  • Create a graphical version with Turtle or Pygame.
  • Add command-line options for lives, category, and seed.
  • Record rounds with the Python logging module.
  • Reuse menu and validation ideas from the terminal quiz project.

Frequently Asked Questions

Why use a set for guessed letters?

A set stores unique values and provides direct membership tests.

How are repeated letters revealed?

The masked-word function checks every character against the same set, so every matching position becomes visible.

Can the player guess the complete word?

Yes. The final program treats guesses longer than one letter as complete-word attempts.

How do I use accented words?

Store and compare text consistently. More advanced programs can normalize Unicode and decide whether accented and unaccented letters should be equivalent.

Do I need an external package?

No. This terminal version uses only the standard library.

Conclusion

A Hangman game in Python practices several fundamentals in a single project: random choice, string iteration, sets, input validation, loops, functions, and testing. Separating the mask, win condition, input, and round logic keeps the program understandable.

Once the basic game is reliable, add one improvement at a time. External word files, categories, scores, command-line options, and a graphical interface all fit naturally on top of the same core rules.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Quiz interativo no terminal desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Terminal Quiz Game in Python

    Build a terminal quiz game in Python with questions, input validation, scoring, shuffled answers, replay support, JSON loading, and tests.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    Jogo de adivinhação de números desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Number Guessing Game in Python

    Build a number guessing game in Python with random numbers, input validation, hints, limited attempts, replay support, and clean functions.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    Desenhos para iniciantes usando Turtle em Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Python Turtle Drawing: Complete Beginner Guide

    Learn Python Turtle drawing from scratch: move the turtle, draw shapes, use colors, handle keys, and create a complete geometric

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    Criação de jogos para iniciantes usando Pygame em Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Pygame for Beginners: Build Your First Game

    Learn Pygame from scratch: install it, create a window, handle events, move a player, detect collisions, add scoring, and build

    Ler mais

    Tempo de leitura: 6 minutos
    10/07/2026
    Ilustração de uma cobra com o logo do Python centralizado
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Snake Game in Python with Turtle

    Build a complete Snake game in Python with Turtle. Add movement, food, collisions, body growth, scoring, and keyboard controls.

    Ler mais

    Tempo de leitura: 6 minutos
    10/07/2026
    Projeto clássico do jogo Pong desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build Your First Pong Game with Python

    Build your first Pong game with Python and the Turtle module: window setup, paddles, ball physics, collision detection, scoreboard, and

    Ler mais

    Tempo de leitura: 7 minutos
    03/06/2026