Today's Plan
3 minBy the end of this lesson you will have:
- One polished file
guesser_deluxe.py— the Level 1 game you'll show off to family. - A working mental map of every headline Level 1 idea, lesson by lesson.
- A concrete next step: what to look forward to in Level 2.
The hour is split roughly: 20 min building Deluxe, 25 min walking the recap, 10 min reflecting and asking questions, 5 min on the path to Level 2.
Warm-Up · The Brief
5 minNumber Guessing Game Deluxe is the version you'd ship if this were a real product. Below is the feature list — read it carefully before you start coding. Most of it's lifted from Parts 1-3 with a few small additions.
- Welcome screen with a small ASCII banner and a name prompt.
- Difficulty menu — Easy / Medium / Hard / Impossible — each with its own range and try-cap.
- Validated input throughout — no crashes on bad text or out-of-range numbers.
- Higher / Lower feedback after each valid guess; "repeat guess" and "you're close" (within 5) bonus messages.
- A win-or-lose ending per round, with the secret revealed on loss.
- Top-5 leaderboard with name and tries, printed before each round and at goodbye.
- Cumulative Wins / Losses counter in the leaderboard header.
- Replay loop with a friendly farewell.
Start from your guesser.py homework. Add one feature at a time. Don't try to write the whole 150 lines in one go — make a feature work, run the game, then add the next. That habit has served you since Lesson 1.
Level 1 Recap · Eight Big Ideas
25 minEvery Level 1 lesson, organised by theme. Use this as a personal scorecard — for each idea, ask "could I explain this to a classmate?". Anywhere you hesitate, that's where to revisit.
1 · The first conversation (PY-L1-01..07)
- Variables & types — names that hold values; integers, floats, strings, booleans.
x = 5,name = "Aisyah". - I/O —
print()for output,input()for input.int()andfloat()for conversion. Comments with#. - Math —
+ - * /, the half-siblings//,%,**. Operator precedence.
2 · Making choices (PY-L1-08..11)
- Conditionals —
if,elif,else, indentation = block. - Booleans & comparisons —
==,!=,<,<=, etc. - Combining —
and,or,not. - First mini-game: Rock-Paper-Scissors (PY-L1-11) — your first time gluing input + random + branching.
3 · Repeating (PY-L1-12..14)
whileloops — repeat until a condition becomes false.breakto exit,continueto skip to the top.forloops &range()— iterate a fixed number of times.- ASCII art patterns (PY-L1-14) — your first taste of nested loops.
4 · Lists (PY-L1-15..22)
- Creation, indexing, slicing —
nums = [3, 1, 4],nums[0],nums[-1],nums[1:3]. - Methods —
.append(),.pop(),.remove(),.sort(). Theinoperator for membership. - Looping —
for item in list:walks every value cleanly. randommodule —random.choice(list),random.shuffle(list),random.randint(a, b).- Games: Magic 8-Ball (PY-L1-20), Lucky Draw Picker (PY-L1-21). Challenge: List Lab (PY-L1-22).
5 · Strings (PY-L1-23..25)
- Methods —
.upper(),.lower(),.replace(),.count(),.strip(),.isdigit(). - Indexing & slicing — strings behave like immutable lists of characters.
word[0],word[-1],word[::-1]. - Game: Anagram Detective (PY-L1-25) — sort the letters, compare the lists.
6 · Functions (PY-L1-26..34)
- Define & call —
def name():writes the recipe,name()cooks it. - Parameters — slots in the def. Arguments — values at the call. Positional, keyword, defaults.
return— sends a value back so the caller can use it. Different fromprint.- Composition — pass one function's return into another. The big unlock.
- Functions + lists — pass a list in, return one value (total, biggest, count). The shape of every real Python helper.
- Games: Quiz Engine v1 + v2 (PY-L1-32..33). Decathlon challenge (PY-L1-34) — 10 tiny functions against a stopwatch.
7 · Putting it together — bigger games (PY-L1-35..41)
- Hangman — string immutability, mask building char by char, lives counter, ASCII gallows from a list (Parts 1-3).
- ASCII Banner — letter shapes stored as data, row-major printing, dictionary lookup preview.
- Text Adventure — scene functions return next-location strings, a dispatcher loop calls the right one, list-based inventory, dragon fight with HP and randint damage (Parts 1-3).
8 · Sharpening the eye (PY-L1-42..44)
- Bug Hunt — eight bug families to spot fast.
- Predict the Output — trace code on paper, gap-test your mental Python.
- Speed Round — 10 micro-problems against the clock.
9 · The build-up to today (PY-L1-45..48)
- Number Guesser Parts 1-3 — core loop, difficulty levels, hi-score table.
- Today — Deluxe.
Go through it slowly. For every line, give yourself a 0-2: 0 = haven't internalised, 1 = can do with the lesson open, 2 = solid. Anything that's a 0, revisit the lesson tonight. Anything that's a 1, write a fresh 5-line example of your own. Anything that's a 2, congratulations — those are now permanent.
Build · Number Guessing Game Deluxe
20 minThe full file
Save as guesser_deluxe.py. Read it once top-to-bottom, then start building from your existing guesser.py. The file is bigger than usual — it's a complete game.
Code
# guesser_deluxe.py — Level 1 Capstone import random # ---- Constants & data ---- TOP_N = 5 DIFFICULTIES = { "easy": [1, 50, 10], "medium": [1, 100, 7], "hard": [1, 200, 8], "impossible": [1, 500, 9], } BANNER = """ +============================================+ | | | N U M B E R G U E S S E R | | | | D E L U X E | | | +============================================+ """ ENCOURAGEMENT = [ "You've got this.", "Halve the range each guess!", "Trust your hunches.", "So close — keep going.", ] # ---- Helpers ---- def pick_difficulty(): print() print("Difficulty:") for name, settings in DIFFICULTIES.items(): low, high, cap = settings[0], settings[1], settings[2] print(" ", name, "— ", low, "to", high, "with", cap, "tries") while True: choice = input("Pick: ").strip().lower() if choice in DIFFICULTIES: s = DIFFICULTIES[choice] return s[0], s[1], s[2] print("Type one of: easy, medium, hard, impossible.") def read_guess(low, high, history): while True: raw = input("Guess: ").strip() if raw.lower() == "quit": return None if not raw.isdigit(): print(" whole numbers only.") continue n = int(raw) if n < low or n > high: print(" out of range (", low, "-", high, ").") continue if n in history: print(" already guessed — no penalty.") continue return n def play_round(low, high, cap): secret = random.randint(low, high) tries = 0 history = [] print() print("I'm thinking of a number between", low, "and", high, ". You have", cap, "tries.") while tries < cap: guess = read_guess(low, high, history) if guess is None: print("You walked away from the table.") return False, tries history.append(guess) tries = tries + 1 remaining = cap - tries if guess == secret: print("🎉 Correct! Got it in", tries, "tries.") return True, tries diff = abs(guess - secret) if guess < secret: print("⬆️ Higher.", end=" ") else: print("⬇️ Lower.", end=" ") if diff <= 5: print("(very close)") else: print("(", remaining, "tries left)") if tries == 2 and not (secret - 5 <= guess <= secret + 5): print(" 💬 ", random.choice(ENCOURAGEMENT)) print("💀 Out of tries. The number was", secret, ".") return False, tries def add_score(scores, used, name): scores.append([used, name]) scores.sort() del scores[TOP_N:] def print_scoreboard(scores, wins, losses): print() print("=" * 46) print(" HI-SCORE (W:", wins, " L:", losses, ") — best", TOP_N) print("=" * 46) if not scores: print(" (no scores yet — be the first!)") else: for i, entry in enumerate(scores, start=1): used, name = entry[0], entry[1] print(" ", i, ". ", used, "tries —", name) print("=" * 46) # ---- Main ---- print(BANNER) player = input("Your name: ").strip() or "Anonymous" print("Welcome,", player + "!") hi_scores = [] wins = 0 losses = 0 while True: print_scoreboard(hi_scores, wins, losses) low, high, cap = pick_difficulty() won, used = play_round(low, high, cap) if won: wins = wins + 1 add_score(hi_scores, used, player) else: losses = losses + 1 if input("Play again? (y/n) ").strip().lower() != "y": print() print("Final board:") print_scoreboard(hi_scores, wins, losses) print() print("Thanks for playing,", player + "!") break
The Level 1 ideas in this file, by appearance
- Constants & data (top of file): a dictionary preview, a multi-line ASCII string, a list of encouragement strings.
- Functions with parameters & multiple returns:
pick_difficulty(),play_round(low, high, cap)→True/False, tries. - Validation gate (
read_guess):isdigit, range check, repeat check — all withcontinue. A polite, robust input reader. - Two-exit loop: win (return inside loop) vs run out (loop ends, fall through).
- Boolean math:
abs(guess - secret) <= 5for the "very close" bonus. - List as scoreboard: append + sort + del to keep top-N.
enumeratefor friendly numbering. - Outer replay loop:
while Truewith a friendly farewell.
Per-difficulty separate boards. A "reverse mode" where the computer guesses your number using binary search (Level 3 algorithm). A score that combines difficulty multiplier × tries efficiency. Coloured terminal output. All of those are now within your reach — you have all the Python you need.
Play, Reflect, Compare
10 minOnce Deluxe runs, play through it three times: one Easy, one Medium, one Hard. Then do this short reflection on paper:
- Which feature surprised you with how easy it was to add? Which one was harder than you expected?
- If you only had time for one polish task, what would you do next — and why?
- Compare today's Deluxe to your first program from Lesson 1 (
print("hello world")). How would you explain the gap to a friend who's never coded?
Keep those answers somewhere — they'll be useful at the start of Level 2 when we set new goals.
Stretch · Three Optional Upgrades
8 minFor students who finish the Deluxe build early, three stretch ideas of increasing difficulty.
Stretch 1 · Score formula
Replace the "tries" on the leaderboard with a score: harder difficulty multiplies the points. E.g. score = (cap - tries + 1) * multiplier, where multiplier is 1 / 2 / 4 / 8 for easy/medium/hard/impossible. Sort descending now (high score = best).
Stretch 2 · Time the round
Add import time. Record start = time.time() before the loop and elapsed = time.time() - start after. Add the elapsed seconds to the score formula or print it as a stat — "solved in 23.4 seconds".
Stretch 3 · The computer plays
Reverse mode — you pick a number 1-100, the computer guesses. Use binary search: keep a lo and hi range, computer guesses the midpoint, you tell it "higher", "lower", or "correct". It should always win in 7 tries or fewer. This is your first algorithm — proper full deep-dive in Level 3.
Show the binary-search guesser
def computer_guesses(): print("Pick a number 1-100. I'll guess; tell me 'higher', 'lower', or 'right'.") lo, hi = 1, 100 tries = 0 while lo <= hi: guess = (lo + hi) // 2 # midpoint, integer tries = tries + 1 ans = input("Is it " + str(guess) + "? ").strip().lower() if ans == "right": print("Got it in", tries, "guesses!") return if ans == "higher": lo = guess + 1 elif ans == "lower": hi = guess - 1 else: print("Say 'higher', 'lower', or 'right' please.") tries = tries - 1 print("You changed your number 😏")
Binary search is the "halve the range each time" idea you've been using all along, formalised. (lo + hi) // 2 is integer midpoint. The narrowing happens in lo = guess + 1 and hi = guess - 1. This algorithm guarantees ≤ log₂(100) ≈ 7 guesses — the same number you've probably been hitting by intuition.
What's Next · Level 2 Preview
5 minLevel 2 builds on every bone you have and adds the things that turn scripts into software:
- Tuples & dictionaries — proper deep-dive on the lookup structures we've been previewing in the dispatcher and ASCII banner lessons.
- Files — read from disk, write to disk. Your hi-scores will survive between runs.
- f-strings — cleaner string formatting (no more
+juggling). - Errors & try/except — proper crash handling, so
int(input())on bad input no longer kills the program (we've been working around this all term). - Turtle graphics — your first visual Python. Mandalas, mazes, races.
- Regex & JSON — text patterns and data formats real programs use every day.
- Bigger games — Wordle-Lite, Tic-Tac-Toe, Turtle Race.
- Capstone — Personal Notes & Tasks Manager, a CLI app you'd actually use.
Level 1 was the foundation. Level 2 is where Python starts feeling like a real tool you can build with. Welcome to the second half of the journey.
Level 1 Glossary · The Quick List
Variable · type · int · float · string · bool · cast · input · print · comment · operator · expression · if / elif / else · indentation · comparison · and/or/not · while · for · range · break · continue · list · index · slice · append · pop · remove · sort · in · random.choice · random.randint · function · def · parameter · argument · keyword arg · default · return · None · scope · str.upper / lower / strip / replace / count / isdigit / split / join · enumerate · str(n) · ord · dict (preview) · triple-quoted string · constants · two-exit loop · validation gate · accumulator · helper function · composition · dispatcher · state machine · top-N scoreboard.
Homework · The Brag File
4 minThree tiny "you finished Level 1" tasks.
- Polish your
guesser_deluxe.pyuntil you're proud to show it. Add one of the three stretch upgrades from this lesson, or invent your own. - Open a new file
BRAG.md(or paper notebook). List five programs you wrote this term. For each, write one sentence on what it does and one sentence on what you learnt building it. - Record a 60-second screen capture (or phone video) playing through your Deluxe game. Send it to someone in your life who'll be proud. (Optional, but very recommended — the moment people see what you can do, they start asking you to build things for them.)
And then — well done. You finished Level 1. Bring guesser_deluxe.py and BRAG.md to the Level 1 Assessment.
Sample · guesser_deluxe.py with score formula
# guesser_deluxe.py — Level 1 Capstone (with score formula) import random TOP_N = 5 DIFFICULTIES = { "easy": [1, 50, 10, 1], "medium": [1, 100, 7, 2], "hard": [1, 200, 8, 4], "impossible": [1, 500, 9, 8], } def pick_difficulty(): print("\nDifficulty:") for name, s in DIFFICULTIES.items(): print(" ", name, "—", s[0], "to", s[1], "with", s[2], "tries (x", s[3], ")") while True: c = input("Pick: ").strip().lower() if c in DIFFICULTIES: s = DIFFICULTIES[c] return s[0], s[1], s[2], s[3], c def read_guess(low, high, history): while True: raw = input("Guess: ").strip() if raw.lower() == "quit": return None if not raw.isdigit(): print(" numbers only."); continue n = int(raw) if n < low or n > high: print(" out of range."); continue if n in history: print(" already guessed."); continue return n def play_round(low, high, cap): secret = random.randint(low, high) tries = 0 history = [] print("Secret is between", low, "and", high, ". You have", cap, "tries.") while tries < cap: g = read_guess(low, high, history) if g is None: return False, tries history.append(g) tries = tries + 1 if g == secret: print("🎉 Correct in", tries, "tries!") return True, tries elif g < secret: print("⬆️ Higher.") else: print("⬇️ Lower.") print("💀 Out of tries. Secret was", secret) return False, tries def add_score(scores, points, name): scores.append([points, name]) scores.sort(reverse=True) # higher points = better del scores[TOP_N:] def print_board(scores): print("\n========== HI-SCORE ==========") if not scores: print(" (empty)") else: for i, e in enumerate(scores, start=1): print(" ", i, ". ", e[0], "pts —", e[1]) print("==============================") # main player = input("Your name: ").strip() or "Anonymous" scores = [] while True: print_board(scores) low, high, cap, mult, level = pick_difficulty() won, used = play_round(low, high, cap) if won: points = (cap - used + 1) * mult print("Score this round:", points, "pts (", level, ")") add_score(scores, points, player) if input("Again? (y/n) ").strip().lower() != "y": print_board(scores) print("Bye,", player + "!") break
The score formula (cap - used + 1) * multiplier is a single line that elegantly rewards both efficiency and difficulty. A 1-try win on impossible scores 9 × 8 = 72 pts; a 10-try win on easy scores 1 × 1 = 1 pt. Tunable too — bump the multipliers if hard feels under-rewarded. And the leaderboard now sorts descending because higher is better — one keyword (reverse=True) flips the whole game's competition.