Number Guessing Game
Build a complete, replayable guessing game and learn the “keep asking until the input is valid” pattern that powers every interactive program.
About this project
The computer picks a secret number; you guess, and it tells you to go higher or lower until you crack it. Simple to describe — but building it well brings together loops, conditionals, input, error handling, and functions into one working whole.
Why it’s worth building: the heart of this game is a loop that keeps asking until it gets a valid answer. That exact pattern shows up everywhere real software lives — login prompts, menus, “are you sure?” confirmations, retrying a flaky download. Get it right here and you’ll reuse it for the rest of your Python life.
Build it step by step
We’ll grow the game one idea at a time. Each step adds a single concept and leaves you with something that runs, so you’re never staring at a wall of code wondering where to start.
Step 1 — Pick a secret number
The random module ships with Python. randint(1, 100) returns a whole number from 1 to 100, including both ends. We print it for now just so we can see it while testing — we’ll remove that line later.
import random
secret = random.randint(1, 100) # 1 to 100, both ends included
print("(testing) the secret is:", secret)
Step 2 — Read a guess you can trust
input() always hands back a string, even when the user types digits, so we convert with int(). But people fat-finger things — they’ll type fifty or hit enter by accident. Wrapping the conversion in try/except lets us catch that and ask again instead of crashing. Putting it in a function means we can reuse this “pester until valid” logic anywhere.
def read_guess(low, high):
"""Ask until the player types a whole number within range."""
while True:
raw = input(f"Guess ({low}-{high}): ")
try:
guess = int(raw)
except ValueError:
print("Please type a whole number.")
continue
if guess < low or guess > high:
print(f"Stay between {low} and {high}.")
continue
return guess
Step 3 — Compare and give a hint
With a trustworthy guess in hand, one if/elif/else covers every case: too low, too high, or spot on. Returning a flag from this round lets the caller know whether to keep going.
secret = 42
guess = 30
if guess < secret:
print("Higher!")
elif guess > secret:
print("Lower!")
else:
print("You got it!")
Higher!
Step 4 — Loop until they win, counting tries
Now we stitch it together: keep reading guesses until one matches, and tick up a counter each time so we can report how many attempts it took. A while True loop with a return inside is the cleanest way to say “go until you win.”
def play_round(low=1, high=100):
secret = random.randint(low, high)
attempts = 0
while True:
guess = read_guess(low, high)
attempts += 1
if guess < secret:
print("Higher!")
elif guess > secret:
print("Lower!")
else:
print(f"You got it in {attempts} tries!")
return attempts
The finished game
Here’s everything assembled, plus a replay loop and a “best score” tracker so it feels like a real game. Notice how each function does one job — that separation is what keeps a growing program understandable.
import random
def read_guess(low, high):
"""Ask until the player types a whole number within range."""
while True:
raw = input(f"Guess ({low}-{high}): ")
try:
guess = int(raw)
except ValueError:
print("Please type a whole number.")
continue
if guess < low or guess > high:
print(f"Stay between {low} and {high}.")
continue
return guess
def play_round(low=1, high=100):
secret = random.randint(low, high)
attempts = 0
while True:
guess = read_guess(low, high)
attempts += 1
if guess < secret:
print("Higher!")
elif guess > secret:
print("Lower!")
else:
print(f"You got it in {attempts} tries!")
return attempts
def main():
print("I'm thinking of a number between 1 and 100.")
best = None
while True:
attempts = play_round()
if best is None or attempts < best:
best = attempts
print(f"Best so far: {best} tries.")
again = input("Play again? (y/n): ").strip().lower()
if again != "y":
print("Thanks for playing!")
break
if __name__ == "__main__":
main()
I'm thinking of a number between 1 and 100. Guess (1-100): 50 Higher! Guess (1-100): 75 Lower! Guess (1-100): sixty Please type a whole number. Guess (1-100): 62 You got it in 3 tries! Best so far: 3 tries. Play again? (y/n): n Thanks for playing!
Keep going — make it your own
You’ve got a real game. Now make it yours — each idea below adds one concept and a reason to use it. Start with whichever sounds most fun.
Give the player a limited number of tries. Swap the endless while for a counted for loop over range(1, MAX_TRIES + 1). If it runs out before they win, reveal the answer — instant tension.
MAX_TRIES = 7
def play_round(low=1, high=100):
secret = random.randint(low, high)
for attempts in range(1, MAX_TRIES + 1):
guess = read_guess(low, high)
if guess == secret:
print(f"You got it in {attempts} tries!")
return attempts
print("Higher!" if guess < secret else "Lower!")
print(f"Out of tries! The number was {secret}.")
return MAX_TRIES
Add difficulty levels. Let the player pick a range (1–10, 1–100, 1–1000). Because play_round already takes low and high, this is mostly a menu in front of what you’ve built — a great example of why parameters beat hard-coded numbers.
ranges = {"easy": (1, 10), "normal": (1, 100), "hard": (1, 1000)}
choice = input("easy / normal / hard? ").strip().lower()
low, high = ranges.get(choice, (1, 100)) # default to normal
play_round(low, high)
Choose the difficulty from the command line. Reading sys.argv lets you run python guessing_game.py 1000 and jump straight in — your first taste of a script that takes arguments like a real tool.
import sys
# python guessing_game.py 1000 -> guess between 1 and 1000
high = int(sys.argv[1]) if len(sys.argv) > 1 else 100
play_round(1, high)
Remember the all-time best score between runs. Save it to a small file so it survives closing the program — your first bit of persistence. Read it on startup, write it whenever it’s beaten.
from pathlib import Path
scores = Path("best_score.txt")
record = int(scores.read_text()) if scores.exists() else None
# after a round, if you beat the record:
if record is None or attempts < record:
scores.write_text(str(attempts))
print("New all-time best!")
Mini exercise (easy)
Write the game’s core feedback: a function hint(guess, secret) that returns 'Higher!' when the guess is too low, 'Lower!' when it’s too high, and 'You got it!' when they match.
Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.
def hint(guess, secret):
# return "Higher!", "Lower!", or "You got it!"
return "?"
print(hint(30, 42))
print(hint(50, 42))
print(hint(42, 42))
Three branches: if guess < secret → 'Higher!', elif guess > secret → 'Lower!', else 'You got it!'.
def hint(guess, secret):
if guess < secret:
return "Higher!"
elif guess > secret:
return "Lower!"
else:
return "You got it!"
print(hint(30, 42))
print(hint(50, 42))
print(hint(42, 42))
Higher!
Lower!
You got it!
✓ The hint logic works!
assert hint(30, 42) == "Higher!", "a guess below the secret should say Higher!"
assert hint(50, 42) == "Lower!", "a guess above the secret should say Lower!"
assert hint(42, 42) == "You got it!", "a matching guess should say You got it!"
print("✓ The hint logic works!")