LEARN PYTHON | Project: A Number Guessing Game

Lesson objective

Build and test a number guessing game with a stable secret, comparisons, repeated attempts, input handling, range checks and clear win, loss and quit outcomes.

Learn

02.6 | PROJECT: A NUMBER GUESSING GAME

01 | DEFINE THE GAME BEFORE CODING

The player must guess an INTEGER secret from one to twenty. After an accepted wrong guess, the game says Too low or Too high. An exact match wins.

The finished game allows five accepted in-range guesses. Non-numeric or out-of-range responses do not use an attempt. A response of quit exits voluntarily. If five accepted guesses are wrong, the game ends with a loss and reveals the secret.

These are deliberate design decisions. Stating them first prevents inconsistent counting or messages when you add features. There is one secret per game, not a new target after each guess.

02 | START WITH ONE FIXED GUESS

Use secret = 12 while developing. A fixed target makes outcomes reproducible. Read one suitable integer guess and choose Too low, Too high or Correct using an if/elif/else chain.

This first version assumes valid integer input and has one guess only. It is a small component to verify before adding repetition. Test 7, 16 and 12 in separate runs.

secret = 12
guess = int(input("Guess from 1 to 20: "))
if guess < secret:
    print("Too low")
elif guess > secret:
    print("Too high")
else:
    print("Correct")

03 | GIVE THE GAME A STATE

The game needs attempts, max_attempts and won. attempts counts accepted guesses. max_attempts is the allowed limit. won is a Boolean flag that begins False and becomes True when the guess matches.

The condition attempts < max_attempts and not won means continue only while guesses remain and success has not occurred. Initialise these values before the loop, so they are not reset on every iteration.

The secret is also set before the loop. Choosing it inside the body would move the target and make feedback unreliable.

04 | ADD REPEATED ACCEPTED GUESSES

The loop below introduces repetition while still assuming valid in-range integer input. Each input becomes an accepted guess, so attempts increases once before feedback. A correct first guess is attempt one, not zero.

Setting won to True prevents another iteration. Once the limit is reached, the condition becomes false. The result after the loop must distinguish those two outcomes.

secret = 12
max_attempts = 5
attempts = 0
won = False
while attempts < max_attempts and not won:
    guess = int(input("Guess from 1 to 20: "))
    attempts += 1
    if guess < secret:
        print("Too low")
    elif guess > secret:
        print("Too high")
    else:
        won = True
        print(f"Correct in {attempts} accepted guesses!")
if not won:
    print(f"No guesses left. The secret was {secret}.")

05 | HANDLE TEXT BEFORE COMPARING NUMBERS

Collect the raw response as text first. strip removes surrounding whitespace. Check quit before conversion, because quit is a command rather than integer text.

Use try/except ValueError around int(text). If conversion fails, print a helpful message and continue. The continue skips the accepted-guess counter and feedback for that iteration.

Then check the permitted range. A whole number such as 25 converts successfully but is still out of range. These two checks establish different properties.

text = input("Guess from 1 to 20, or quit: ").strip()
# This fragment is used inside the full game loop below.
try:
    guess = int(text)
except ValueError:
    print("That response is not a whole number")

06 | COUNT ONLY WHAT THE RULE ACCEPTS

The attempt update belongs after successful conversion and range validation. Otherwise a typo or invalid range value could use a guess despite the stated rule.

Use a separate quit_game flag to record voluntary exit. break leaves the loop, but does not itself explain why it ended. The final selection can then distinguish quit, win and exhausted attempts.

Check the final allowed guess carefully. If attempt five is correct, won becomes True and the win message appears rather than an incorrect loss.

07 | THE COMPLETE TESTABLE CORE GAME

This version uses a fixed secret so every test is repeatable. The named limits appear in prompts and range checks. Read the validation routes before running: invalid input continues without increasing attempts.

# Number guessing game: fixed secret for reproducible testing
MIN_NUMBER = 1
MAX_NUMBER = 20
MAX_ATTEMPTS = 5
secret = 12
attempts = 0
won = False
quit_game = False

print("Guess the secret number")
print(f"Range: {MIN_NUMBER} to {MAX_NUMBER}; accepted guesses: {MAX_ATTEMPTS}")

while attempts < MAX_ATTEMPTS and not won:
    text = input(f"Guess {MIN_NUMBER} to {MAX_NUMBER}, or quit: ").strip()
    if text == "quit":
        quit_game = True
        break

    try:
        guess = int(text)
    except ValueError:
        print("Enter a whole number or the command quit")
        continue

    if guess < MIN_NUMBER or guess > MAX_NUMBER:
        print("That number is outside the allowed range")
        continue

    attempts += 1
    if guess < secret:
        print("Too low")
    elif guess > secret:
        print("Too high")
    else:
        won = True

if quit_game:
    print(f"Game ended after {attempts} accepted guesses.")
elif won:
    print(f"Correct! You used {attempts} accepted guesses.")
else:
    print(f"No guesses left. The secret was {secret}.")

08 | SWITCH TO A RANDOM SECRET AFTER TESTING

Python’s standard-library random module provides pseudo-random values for games and simulations. import random makes its features available through the module name.

random.randint(MIN_NUMBER, MAX_NUMBER) returns an INTEGER including both endpoints. This differs from range(), whose stop is excluded. Replace the fixed-secret assignment with that call, keeping it before the loop.

This is suitable for a casual learning game, not for secrets such as passwords or security tokens. Keep a fixed-secret development version for regression tests, so random outcomes do not hide a broken branch.

import random

MIN_NUMBER = 1
MAX_NUMBER = 20
secret = random.randint(MIN_NUMBER, MAX_NUMBER)

09 | PLAY A BROWSER MODEL OF THE RULES

The activity models the game rules with a new browser-generated secret from one to twenty. It does not execute the Python source. Invalid responses do not use attempts; enter quit to end a round.

    10 | TEST EVERY ROUTE WITH SECRET TWELVE

    First guess 12 should win with one accepted guess. Sequence 7, 16, 12 should give low, high, then win in three. Sequence 1, 2, 3, 4, 12 should win on the last allowed guess.

    Five wrong in-range guesses should lose and reveal twelve. Input hello, 25, then 12 should show two validation messages but win with one accepted guess. Immediate quit should exit after zero accepted guesses.

    Include endpoints one and twenty, blank text, a decimal such as 12.5, and whitespace around 12. Explain which inputs convert, which meet the range and which count as guesses.

    11 | DEBUG WITHOUT MOVING THE TARGET

    If feedback contradicts an earlier clue, check whether secret was reassigned inside the loop. If invalid input reduces remaining guesses, inspect the attempt update’s location. If quitting prints a loss, inspect the final outcome selection.

    A temporary diagnostic print of the fixed secret and attempts can help during development, but remove it for actual play. Revealing the secret defeats the normal game even if it helps testing.

    Use the known tests after every change. A replay extension should initialise a new round’s state rather than carry the previous round’s count or won flag into it.

    12 | MAKE IT YOUR OWN WITHOUT LOSING CLARITY

    Personalise the title and messages. Add the number of remaining accepted guesses after a wrong response. Then change the limits through the named constants and update the tests.

    Extension: make quit case-insensitive by using text.lower() for the command comparison. lower is a string method that returns a lowercase version; it does not change the original text automatically.

    Write a short guide describing range, attempt counting, invalid input and exit commands. Give the game to a partner, then record one improvement based on their experience.

    Official random module reference

    PUT YOUR SKILLS TO WORK

    Use the Section 2 challenges to practise these ideas independently. Work in your Python editor, predict results and keep a short test record.

    Section 2 challenges Python course navigation

    MATCH THE PYTHON TERM TO ITS MEANING

    Terminology

    Terminology

    Secret

    The stable target number for one game.

    Attempt

    An accepted in-range guess under this game’s rule.

    Win flag

    A Boolean recording a successful guess.

    Quit flag

    A Boolean recording voluntary exit.

    State

    The current values governing the game.

    Input validation

    Checking numeric content and permitted range.

    Conversion failure

    A ValueError from unsuitable integer text.

    Range rejection

    A converted number lies outside the game bounds.

    Feedback

    A message explaining low, high or success.

    Attempt limit

    The maximum accepted guesses.

    continue

    Skips invalid input’s remaining iteration work.

    break

    Leaves the loop for a quit command.

    Outcome selection

    Distinguishing quit, win and loss after the loop.

    Module

    A source of reusable Python features.

    import

    Makes a module available to the program.

    random.randint()

    Chooses a pseudo-random integer including both endpoints.

    Fixed-secret test

    A reproducible game run with a known target.

    Regression check

    Rerunning known routes after a modification.

    Questions

    Questions

    CHECK YOUR UNDERSTANDING

    Select all correct choices. Each exact set earns one point.

    1. Which game choices are correct?
    2. Which count as attempts in this design?
    3. Which checks belong before the counter update?
    4. Which describe continue for bad input?
    5. Which outcomes must be distinguished?
    6. Which describe randint(1, 20)?
    7. Which tests are useful?
    8. Which extensions keep the rules clear?

    EXPLAIN AND COMPARE

    Write your answers before revealing each sample.

    1. Explain why secret belongs before the loop.

    2. Explain attempts update placement.

    3. Trace guesses 7, 16, 12 for secret 12.

    4. Trace hello, 25, 12 for secret 12.

    5. Compare quit and exhausted attempts.

    6. Describe a last-attempt win test.

    7. Explain randint endpoints versus range.

    8. Suggest a clear next improvement.

    CODE IT | YOUR INDEPENDENT CHALLENGE

    Build the full guessing game in your editor. Test fixed-secret win, final-attempt win, loss, invalid-input and quit routes before adding randomness.

    Work in your Python editor. Keep a working version, explain one design choice and record at least two tests. Use the Learn tab for worked examples before comparing your result.

    Flashcards

    Flashcards

    Click to flip. Select the ideas you need to revisit.

    0 cards selected for revision.

      Selections are kept while this page is open.

      Workbook

      Workbook

      COMING SOON

      The workbook for Project: A Number Guessing Game is coming soon. Complete the matching task and written questions in your exercise book.