Build a Number Guessing Game in Python

Published on: July 10, 2026
Reading time: 5 minutes
Jogo de adivinhação de números desenvolvido com Python

A number guessing game is a compact project that combines random values, loops, conditions, functions, input validation, and game state. The computer chooses a secret number, and the player receives higher-or-lower hints until the answer is correct or the available attempts run out.

This tutorial builds a complete number guessing game in Python and explains each design decision. The final version supports difficulty levels, repeated guesses, input validation, a limited number of attempts, replay, and a testable hint function.

The project uses the Python random module to choose the secret value. It also applies clean function boundaries similar to those covered in the Python return statement guide.

How the Game Works

  1. The player chooses a difficulty.
  2. The computer generates a secret integer inside a range.
  3. The player enters a guess.
  4. The program validates the input.
  5. The game reports whether the guess is too low, too high, or correct.
  6. The round ends after a correct answer or the final attempt.
  7. The player may start another round.

The official Python random documentation defines randint(), and the input() documentation describes terminal input.

Create the Simplest Version

import random

secret = random.randint(1, 100)
guess = int(input("Guess a number from 1 to 100: "))

if guess == secret:
    print("Correct!")
elif guess < secret:
    print("Too low")
else:
    print("Too high")

This version demonstrates the core comparison, but it accepts only one guess and crashes when the input cannot be converted to an integer.

Repeat with a while Loop

import random

secret = random.randint(1, 100)
guess = None

while guess != secret:
    guess = int(input("Your guess: "))

    if guess < secret:
        print("Too low")
    elif guess > secret:
        print("Too high")

print("You found it!")

A sentinel value of None makes the first loop condition clear. The loop continues until the guess matches the secret.

Validate User Input

Terminal input arrives as text. Converting invalid text with int() raises ValueError. A dedicated function can repeat until it receives an integer within the permitted range.

def read_integer(prompt, minimum, maximum):
    while True:
        raw_value = input(prompt).strip()

        try:
            value = int(raw_value)
        except ValueError:
            print("Enter a whole number.")
            continue

        if not minimum <= value <= maximum:
            print(f"Enter a number from {minimum} to {maximum}.")
            continue

        return value

The Python errors and exceptions tutorial explains why specific exceptions should be handled near the operation that can fail.

Add Limited Attempts

A limited number of attempts gives the game a clear losing condition. A for loop naturally represents a fixed number of turns.

MAX_ATTEMPTS = 7

for attempt in range(1, MAX_ATTEMPTS + 1):
    remaining = MAX_ATTEMPTS - attempt
    guess = read_integer("Your guess: ", 1, 100)

    if guess == secret:
        print(f"Correct in {attempt} attempts!")
        break

    if guess < secret:
        print("Too low")
    else:
        print("Too high")

    print(f"Attempts remaining: {remaining}")
else:
    print(f"The secret number was {secret}.")

The else attached to the loop runs only when the loop finishes without break. This is a useful but sometimes overlooked Python feature.

Prevent Repeated Guesses

A set stores unique guesses and provides fast membership checks.

guessed_numbers = set()

guess = read_integer("Your guess: ", 1, 100)

if guess in guessed_numbers:
    print("You already tried that number.")
else:
    guessed_numbers.add(guess)

Repeated guesses should not consume an attempt. The complete program handles this with a while loop whose attempt counter increases only after a new valid guess.

Create Reusable Hint Logic

Separating comparisons from terminal output makes the core rule easy to test.

def compare_guess(guess, secret):
    if guess < secret:
        return "low"

    if guess > secret:
        return "high"

    return "correct"

This small pure function always returns the same result for the same inputs. It has no terminal interaction and no random behavior.

Add Difficulty Levels

Store each mode in a dictionary:

DIFFICULTIES = {
    "easy": {"maximum": 50, "attempts": 10},
    "normal": {"maximum": 100, "attempts": 7},
    "hard": {"maximum": 500, "attempts": 9},
}

The hard mode uses a wider range and slightly more attempts. Difficulty does not have to mean only fewer turns; it can also change the available interval.

Complete Number Guessing Game

import random

DIFFICULTIES = {
    "easy": {"maximum": 50, "attempts": 10},
    "normal": {"maximum": 100, "attempts": 7},
    "hard": {"maximum": 500, "attempts": 9},
}


def read_integer(prompt, minimum, maximum):
    while True:
        raw_value = input(prompt).strip()

        try:
            value = int(raw_value)
        except ValueError:
            print("Enter a whole number.")
            continue

        if minimum <= value <= maximum:
            return value

        print(f"Enter a number from {minimum} to {maximum}.")


def choose_difficulty():
    while True:
        print("Available levels: easy, normal, hard")
        choice = input("Difficulty: ").strip().lower()

        if choice in DIFFICULTIES:
            return choice

        print("Choose easy, normal, or hard.")


def compare_guess(guess, secret):
    if guess < secret:
        return "low"

    if guess > secret:
        return "high"

    return "correct"


def play_round(generator=None):
    generator = generator or random.Random()
    difficulty = choose_difficulty()
    settings = DIFFICULTIES[difficulty]
    maximum = settings["maximum"]
    max_attempts = settings["attempts"]
    secret = generator.randint(1, maximum)

    guessed_numbers = set()
    attempt = 0

    print(f"I chose a number from 1 to {maximum}.")

    while attempt < max_attempts:
        guess = read_integer("Your guess: ", 1, maximum)

        if guess in guessed_numbers:
            print("You already tried that number.")
            continue

        guessed_numbers.add(guess)
        attempt += 1
        result = compare_guess(guess, secret)

        if result == "correct":
            print(f"Correct! You used {attempt} attempts.")
            return True

        direction = "low" if result == "low" else "high"
        remaining = max_attempts - attempt
        print(f"Too {direction}. Attempts remaining: {remaining}")

    print(f"No attempts left. The number was {secret}.")
    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("Number Guessing Game")

    while True:
        play_round()

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


if __name__ == "__main__":
    main()

The if __name__ == "__main__" guard prevents the interactive game from starting when the file is imported by a test.

Test the Comparison Function

Create test_guessing_game.py:

from guessing_game import compare_guess


def test_compare_guess():
    assert compare_guess(3, 8) == "low"
    assert compare_guess(10, 8) == "high"
    assert compare_guess(8, 8) == "correct"

The unit testing guide covers test structure, mocks, and frameworks. You can also inject random.Random(42) into play_round() when a predictable sequence helps a test.

Debug the Game in VS Code

Set a breakpoint after the secret number is created, start a debug session, and inspect secret, attempt, and guessed_numbers. The VS Code Python debugging guide explains breakpoints and stepping.

Common Mistakes

  • Generating a new secret number inside the guessing loop.
  • Forgetting that input() returns a string.
  • Using a broad except Exception instead of handling ValueError.
  • Counting invalid or repeated input as a real attempt.
  • Creating an endless loop with no correct exit condition.
  • Putting all code at module level, which makes testing difficult.
  • Revealing the secret number in normal output before the round ends.

Ideas to Extend the Project

  • Add a score based on remaining attempts.
  • Save the best score to JSON.
  • Offer warmer and colder hints based on distance.
  • Add a two-player mode.
  • Create a graphical version with Turtle or Pygame.
  • Accept difficulty through command-line arguments.
  • Record completed rounds with the Python logging module.

Frequently Asked Questions

Why use randint()?

It returns an integer and includes both boundaries, which matches a range such as 1 through 100.

Why store guesses in a set?

A set keeps unique values and makes repeated-guess checks clear.

How many attempts should the player receive?

It depends on the range and desired difficulty. Start with values that make the game enjoyable, then adjust after testing.

Can the secret be reproducible?

Yes. Use a dedicated random.Random(seed) instance for demos or automated tests. Do not use predictable seeds for security-sensitive data.

How do I avoid the game starting during tests?

Put the interactive entry point inside main() and call it under the __main__ guard.

Conclusion

A number guessing game in Python is small enough to understand in one sitting but rich enough to teach important structure. Random generation creates the challenge, validation protects the program from bad input, functions separate responsibilities, and tests verify the core rules.

After the basic version works, add one improvement at a time. Difficulty, scoring, saved results, and graphical interfaces all build naturally on the same clean game loop.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Jogo da forca para iniciantes desenvolvido com Python
    Projects
    Foto de perfil de Leandro Hirt da Academify

    Build a Hangman Game in Python

    Build a complete Hangman game in Python with random words, input validation, repeated-letter checks, lives, ASCII art, and replay support.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    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
    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