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.

Features of the Hangman Game in Python:
- Randomized Word Choice: The game selects a random fruit name from a predefined list as the secret word.
- Interactive Gameplay: Players enter letter guesses and receive instant feedback on their accuracy.
- Guess Management: The game keeps track of both correct and incorrect guesses, preventing duplicate attempts.
- Limited Tries: Players must guess the word within a fixed number of attempts before the game ends.
- 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