Skip to content

codehelping.com

  • Home
  • Projects
  • Blog
  • Contact Us
  • About Us

Master the Hangman Game in Python: 2025 CodeHelping

Posted on February 12, 2025April 6, 2025 By Omkar Pathak No Comments on Master the Hangman Game in Python: 2025 CodeHelping
Project, Python Project

What is Hangman Game in Python?

Let’s create a simple Hangman game in Python code. Players guess letters to uncover a hidden word. With each incorrect guess, a part of the hangman is drawn. The game ends when the word is guessed correctly, or the hangman is fully drawn.

Hangman Game in Python

Features of the Hangman Game in Python:

  1. Randomized Word Choice: The game selects a random fruit name from a predefined list as the secret word.
  2. Interactive Gameplay: Players enter letter guesses and receive instant feedback on their accuracy.
  3. Guess Management: The game keeps track of both correct and incorrect guesses, preventing duplicate attempts.
  4. Limited Tries: Players must guess the word within a fixed number of attempts before the game ends.
  5. Dynamic Visuals: A progressively drawn hangman figure provides visual feedback for incorrect guesses

Instructions for the Hangman Game in Python

  • Enter your name when prompted.
  • You’ll be given a limited number of attempts to guess the secret word.
  • Enter a single letter as your guess for each round.
  • Letters may be capital letters or small letters; it makes no difference.
  • If your guess is correct, the letter will be revealed in the word.
  • If your guess is incorrect, a part of the hangman will be drawn.
  • You win if you guess all letters before the hangman is fully drawn.

The Complete Source Code: Hangman Game in Python

Note: Directly copy paste the code in compiler

import os
import sys
from collections import namedtuple
from dataclasses import dataclass, field
from random import randint
from time import sleep

PuzzleLetter = namedtuple('PuzzleLetter', ['character', 'guessed'])
"""Type definition for a namedtuple('character', 'guessed').
character: str
    One of the characters from the mystery word.
guessed: bool
    True if the letter has been guessed, else False.
"""

Puzzle = list[PuzzleLetter]
"""Type definition for a list of PuzzleLetter's."""


def images() -> tuple[str, ...]:
    """Return a tuple of hangman (ascii) drawings."""
    return (
        r"""
=====""",

        r"""
    +
    |
    |
    |
    |
    |
=====""",

        r"""
 +--+
    |
    |
    |
    |
    |
=====""",

        r"""
 +--+
 |  |
    |
    |
    |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
    |
    |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
 |  |
    |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
/|  |
    |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
/|\ |
    |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
/|\ |
/   |
    |
=====""",

        r"""
 +--+
 |  |
 O  |
/|\ |
/ \ |
    |
====="""
    )


def get_word_list(category: str = 'animals') -> list[str]:
    """Return a list of quiz words.
    Define your list of words here.
    Words must be separated by white-space only.
    Each word list must have a unique name, and have an
    entry in the word_list_dict.
    Parameters
    ----------
    category: str
        Types of words, default: "animals"
    Returns
    -------
    list[str]
        List of words of selected category
    Raises
    ------
    ValueError
        If 'category' invalid.
    """

    category = category.lower()

    animal_words = """
    Dog Cat Elephant Lion Tiger Giraffe Zebra Bear Koala
    Panda Kangaroo Penguin Dolphin Eagle Owl Fox Wolf Cheetah
    Leopard Jaguar Horse Cow Pig Sheep Goat Chicken Duck Goose
    Swan Octopus Shark Whale Platypus Chimpanzee Gorilla Orangutan
    Baboon Raccoon Squirrel Bat Hedgehog Armadillo Sloth Porcupine
    Anteater Camel Dingo Kangaroo Rat Lemur Meerkat Ocelot Parrot
    Quokka Vulture Wombat Yak Iguana jaguar Kakapo Lemming
    Manatee Nutria Ostrich Pangolin Quail Rhinoceros Serval
    Wallaby Coypu Tapir Pheasant
    """

    word_list_dict = {'animals': animal_words}

    try:
        words: str = word_list_dict[category]
        return [word.upper() for word in words.split()]
    except KeyError as exc:
        raise ValueError("Invalid category.") from exc


def get_secret_word() -> str:
    """Return a random word from multiple options."""
    try:
        words: list[str] = get_word_list()
    except ValueError as exc:
        raise RuntimeError("Unable to retrieve word list.") from exc
    secret_word = words[randint(0, len(words) - 1)]
    if isinstance(secret_word, str) and len(secret_word) > 0:
        return secret_word
    raise RuntimeError("Unable to return secret word.")


@dataclass
class GameState:
    """Manage state for the game.
    Attributes
    ----------
    player_name : str
        The player's name.
    word : str
        The mystery word.
    current_guess : str
        The current guess.
    guesses : set
        The set of all guesses tried in this game.
    remaining_letters : set
        The set of letters still required.
    puzzle : list
        Puzzle list.
    image_idx : int
        Index of the image to display.
    """
    player_name: str = ''
    word: str = ''
    current_guess: str = ''
    guesses: set[str] = field(default_factory=set)
    remaining_letters: set[str] = field(default_factory=set)
    puzzle: Puzzle = field(default_factory=list)
    image_idx: int = 0

    def initialise_game_state(self, ) -> None:
        """Post-instantiation initialisation.
        Complete the initialisation of GameState after
        puzzle_word has been set.
        """
        self.remaining_letters = set(self.word)
        self.puzzle = [PuzzleLetter(char, False) for char in self.word]

    def update_state_on_guess(self) -> None:
        """Update the game state based on the current guess.
        Tries to remove the guessed letter from the remaining_letters set.
        If the letter is not in the word, increment the image index.
        """
        try:
            self.remaining_letters.remove(self.current_guess)
            self.update_puzzle()
        except KeyError:
            self.image_idx += 1  # Not in word

    def update_puzzle(self) -> None:
        """Return updated puzzle.
        Called by update_game_state to handle updating the puzzle data.
        Add 'True' to each matching tuple and return result.
        """
        self.puzzle = [
            PuzzleLetter(char, val or (char == self.current_guess))
            for char, val in self.puzzle]

    def reset_current_game(self) -> None:
        """Reset current game settings.
        Does not reset entire session as some game settings,
        such as _player_name, need to persist across multiple games.
        """
        self.word = ''
        self.current_guess = ''
        self.guesses = set()
        self.remaining_letters = set()
        self.puzzle = []
        self.image_idx = 0


class UI:
    """User interface class."""

    def __init__(self, game_state: GameState) -> None:
        """Initialise UI.
        Parameters
        ----------
        game_state: GameState
            Game state
        """
        self.game_state = game_state
        self._indent = ' ' * 4

    def indent_text(self, text: str):
        """Indent each printed line."""
        indented = '\n'.join(
            [self._indent + line for line in str(text).split('\n')])
        return indented

    def display_message(self, message: str, end: str = '\n') -> None:
        """Display arbitrary text message to player.
        In the CLI interface, text is indented for an improved
        aesthetic appearance.
        """
        message = self.indent_text(message)
        print(message, end=end)

    def do_welcome(self) -> str:
        """Welcome new player.
        Get player's name, print welcome message and return player's name.
        Returns
        -------
        str
            The player's name.
        """
        UI.clear_terminal()
        self.print_slowly("Hi there. What's your name?", end=' ')
        player_name = input().title()
        self.print_slowly(f"Hello {player_name}.", end='\n')
        self.print_slowly(
            "You can quit at any time by pressing 'Ctrl + C'.", 8)
        return player_name

    def print_intro(self) -> None:
        """Print introduction to game.
        """
        self.print_slowly(f"OK {self.game_state.player_name}, let's play.")
        self.print_slowly("I'll think of a word""", end='')
        self.print_slowly(' .' * randint(3, 8), speed=5, indent=False)
        UI.clear_terminal()

    def get_guess(self) -> str:
        """Return a new guess.
        Returns
        -------
        str
            The guess - a single character string.
        """
        while True:
            print("Guess a letter: ", end='')
            new_guess = input().strip().upper()

            if len(new_guess) != 1:
                print("Guesses must be one letter only.")
                continue
            if new_guess in self.game_state.guesses:
                print(f"You've already guessed '{new_guess}'")
                continue
            return new_guess

    def display_game_start_screen(self) -> None:
        """Inform user of word length."""
        self.print_slowly(
            "I've thought of a word.\n"
            f"The word has {len(self.game_state.word)} letters.")
        sleep(1)
        UI.clear_terminal()

    def display_game_result(self,
                            is_winner: bool,
                            correct_answer: str) -> None:
        """Congratulate or console player."""
        if is_winner:
            self.print_slowly(f"Well done {self.game_state.player_name}. "
                              f"YOU WIN!", 20)
        else:
            self.print_slowly(
                f"Too bad {self.game_state.player_name}, you loose. "
                f"The word was {correct_answer}.")
            self.print_slowly("Better luck next time.", 6)

    def get_image(self) -> str:
        """Return hangman ascii drawing."""
        return images()[self.game_state.image_idx]

    def prompt_confirm(self, prompt: str) -> bool:
        """Prompt for yes/no answer.
        Parameters
        ----------
        prompt: str
            The message prompt.
        Returns
        -------
        bool
            True if yes, else False.
        """
        yes = ('y', 'yes')
        no = ('n', 'no')
        while True:
            self.display_message(prompt, end='')
            val = input()
            if val in yes:
                return True
            if val in no:
                return False
            print("Enter 'Y' or 'N'.")

    def update_screen(self, clear: bool = True) -> None:
        """Refresh screen with current game state."""
        if clear:
            UI.clear_terminal()
        # Print hangman image.
        self.display_message(self.get_image())
        # Print underscores and guessed letters.
        output = [f'{char} ' if val else '_ ' for
                  char, val in self.game_state.puzzle]
        self.display_message(f'{"".join(output)}\n\n')

    @staticmethod
    def clear_terminal() -> None:
        """Clear the terminal."""
        os.system('cls' if os.name == 'nt' else 'clear')

    def print_slowly(self,
                     message: str,
                     speed: float = 10.0,
                     end: str = '\n',
                     indent: bool = True) -> None:
        """Print message one character at a time.
        Pauses for 1/speed seconds between characters
        Parameters
        ----------
        message: str
            The message to print
        end: str
            Line termination
        speed: int
            How fast to print. Higher = faster
        indent: bool
            Whether to indent the line, default: True
        """
        try:
            delay = abs(1 / speed)
        except ZeroDivisionError:
            self.display_message("Invalid speed. Defaulting to speed = 4")
            delay = 0.25
        for line in message.split('\n'):
            if indent:
                print(self._indent, end='')
            for char in line:
                sleep(delay)
                print(char, flush=True, end='')
            print(end=end)

    def display_exit_dialog(self) -> None:
        """Dialog before quitting."""
        self.display_message(f"\nBye {self.game_state.player_name}.")


class Hangman:
    """Game logic class.
    Attributes
    ----------
    self.state: GameState
        Game state manager.
    self.ui: UI
        User interface.
    """
    def __init__(self) -> None:
        """Constructor of game logic class."""
        self.state = GameState()
        self.ui = UI(self.state)

    def initialise_game(self, puzzle_word: str) -> None:
        """Post-instantiation initialisation.
        Complete the initialisation from puzzle_word.
        """
        self.state.word = puzzle_word
        self.state.initialise_game_state()

    def update_game_state(self, new_guess: str) -> None:
        """Update game attributes according to current guess.
        If current_guess is in word, update game state.
        - update GameState::current_guess
        - update GameState::guesses
        Then tell GameState() instance to manage its own update,
        """
        self.state.current_guess = new_guess
        self.state.guesses.add(new_guess)
        self.state.update_state_on_guess()

    def is_good_guess(self) -> bool:
        """Return True if current guess in puzzle word."""
        return self.state.current_guess in self.state.word

    def player_loses(self) -> bool:
        """Return True if player has lost.
        Game is lost when final hangman image is displayed.
        """
        return self.state.image_idx == len(images()) - 1

    def do_quit(self) -> None:
        """Exit the program."""
        self.ui.display_exit_dialog()
        sys.exit()


def play_game(game: Hangman) -> bool:
    """Play game.
    Main game loop.
    Parameters
    ----------
    game: Hangman
        Instance of the game logic class.
    Returns
    -------
    bool:
        True if player wins, else False.
    """
    game.ui.update_screen(clear=False)

    while game.state.remaining_letters:
        # Update the game state from player guess.
        game.update_game_state(game.ui.get_guess())
        # Display the result.
        game.ui.update_screen()
        if game.is_good_guess():
            game.ui.display_message(f"{game.state.current_guess} is correct.")
        else:
            game.ui.display_message(f"{game.state.current_guess} is wrong.")

        # Return False if hangman complete.
        if game.player_loses():
            return False
    return True


def new_game(game: Hangman) -> None:
    """A single complete game.
    Displays a welcome message to the player, generates a secret word, and
    initiates a game. Prints a win or loose message when game completes.
    Parameters
    ----------
    game: Hangman
        Instance of the game logic class.
    """
    state = game.state
    ui = game.ui

    # player_name initialised only in first game.
    if state.player_name == '':
        state.player_name = ui.do_welcome()

    ui.print_intro()

    try:
        secret_word = get_secret_word()
    except RuntimeError as exc:
        print(f"Sorry, there has been an error: {exc}")
        sys.exit()
    # Now that we have player_name and secret_word
    # we can complete initialisation of GameState.
    game.initialise_game(secret_word)

    ui.display_game_start_screen()

    # Play game and get result
    player_wins = play_game(game)
    ui.display_game_result(player_wins, state.word)

    # Reset for next game.
    state.reset_current_game()


def main():
    """Main loop.
    Instantiate an instance of Hangman game, which will
    persist for the life of program.
    Play game repeatedly until player quits.
    """
    new_game_session = Hangman()
    while True:
        try:
            new_game(new_game_session)
        except KeyboardInterrupt:
            new_game_session.do_quit()
        if new_game_session.ui.prompt_confirm("Play again? [y/n] "):
            continue
        new_game_session.do_quit()


if __name__ == '__main__':
    # Check Python version
    if sys.version_info < (3, 9):
        print("Hangman requires Python 3.9 or later.")
        print("Please update your Python version.")
        sys.exit(1)
    main()

Credit: Hangman ASCII artwork borrowed from:
https://inventwithpython.com/bigbookpython/project34.html


Conclusion: Hangman Game in Python 2025

The Hangman game in Python Project has features like random word selection, interactive input, and ASCII art, you’ll gain experience in essential concepts like loops, conditionals, and string manipulation

If you found this hangman game in python helpful, don’t forget to check out more programming guides and resources on CodeHelping. Keep coding, keep learning, and happy programming!

For coding projects of JavaScript, C++, and Python along with their source code visit Link

Post navigation

❮ Previous Post: Create a Fun Rock Paper Scissors Game in Python with Tkinter | 2025 Tutorial
Next Post: Let’s Build a Random Password Generator in Python using Tkinter- 2025 ❯

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • Home
  • Projects
  • Blog
  • Contact Us
  • About Us

Copyright © 2025 codehelping.com.

Theme: Oceanly by ScriptsTown

Social Chat is free, download and try it now here!