Build Bagels: instructions
Follow the steps in order. Your teacher codes each module live. Use the module map and spec to know what to build, and run it after every step.
The game and the big picture
The computer thinks of a secret number with no repeated digits. You guess, and it gives clues.
| Clue | Meaning |
|---|---|
| Fermi | A digit is correct and in the right position. |
| Pico | A digit is in the secret, but in the wrong position. |
| Bagels | No digit is correct. |
Example: secret 248, guess 843 gives Fermi Pico.
How the modules fit together
Colour key: blue = control flow, green = creates data, amber = user input, purple = pure function (no input or print).
Build one small module, test it, then move on. Never write the next module until the last one works.
1Settings
Store the game settings in one place and import the tool we need.
Module spec
| Needs | random (imported at the top) |
|---|---|
| Constant 1 | NUM_DIGITS = 3: length of the secret |
| Constant 2 | MAX_GUESSES = 10: tries allowed |
Module map
NUM_DIGITS = 3Length of the secret. Max 10, because there are only ten distinct digits.
MAX_GUESSES = 10How many tries the player gets.
Change one number and the whole game adapts: no other line needs editing.
Key ideas
- CAPITAL names are constants: set once, never changed while running.
- One edit changes the whole game (e.g. 4 digits).
Run the file. Nothing happens and there is no error.
2Make the secret
Create a secret with no repeated digits.
Module spec
| Name | make_secret |
|---|---|
| Input | n, how many digits (default: NUM_DIGITS) |
| Returns | a string of n different digits, e.g. '248' |
| Tools | list of the ten digits, shuffle, slice, join |
Module map
Because each digit appears once in the shuffled list, repeats are impossible.
Key ideas
- Shuffle all ten digits, then keep the first n: repeats become impossible.
- Result is a string, because we compare it with the typed guess later.
Call it twice and print both. Expect two different 3-digit strings, such as 581 and 027, and never a repeat like 118.
[:3] keep? What if n were 10?3Give clues
Compare a guess with the secret and return the right clue text.
Module spec
| Name | get_clues |
|---|---|
| Inputs | guess and secret (strings of the same length) |
| Returns | You got it!, Bagels, or clues joined by spaces |
| Rules | Same digit, same place: Fermi. In the secret, wrong place: Pico. Nothing: Bagels. Clues sorted alphabetically. |
| Must not | print or ask for input (a pure function) |
Module map
| i | guess[i] | secret[i] | Same spot? | In secret? | Clue |
|---|---|---|---|---|---|
| 0 | 8 | 2 | no | yes | Pico |
| 1 | 4 | 4 | yes | - | Fermi |
| 2 | 3 | 8 | no | no | none |
clues = ['Pico', 'Fermi'] → clues.sort() → ['Fermi', 'Pico'] → "Fermi Pico". Sorting stops the order from revealing which position was right.
Two shortcuts around the loop: guess == secret returns "You got it!" immediately, and an empty clue list returns "Bagels".
Key ideas
- Check the exact win first, then score each position.
- Sort the clues so their order does not leak which place was right.
| guess | secret | Expected result |
|---|---|---|
| 843 | 248 | Fermi Pico |
| 248 | 248 | You got it! |
| 159 | 248 | Bagels |
| 284 | 248 | Fermi Pico Pico |
4Ask for a guess
Keep asking until the player types exactly the right number of digits.
Module spec
| Name | ask_guess |
|---|---|
| Input | num_guesses, used only in the prompt text |
| Returns | a valid guess: exactly NUM_DIGITS digits, trimmed of spaces |
| Rule | Repeat while the length is wrong or it is not all digits |
Module map
.strip() removes stray spaces, and isdecimal() rejects letters like "ab3".
Key ideas
- Start with an empty guess so the loop runs at least once.
- Trim spaces; reject letters and symbols.
Type abc, then 12, then 123. The first two are rejected; 123 is returned.
12a: which half of the test catches it?5Play one game
Connect the three helpers into one complete round.
Module spec
| Name | play_once |
|---|---|
| Input | none |
| Returns | nothing (it prints) |
| Uses | make_secret, ask_guess, get_clues |
| Ends when | the guess is correct, or guesses run out (then reveal the answer) |
Module map
Key ideas
- A counter starts at 1 and grows each guess.
- A correct guess leaves the loop early; running out prints the answer.
Play a full game twice: win once, and lose once. On the losing game the answer must be shown after guess #10.
6Main and play again
Show the rules once, replay on request, and only start when run directly.
Module spec
| Name | main |
|---|---|
| Input | none |
| Does | prints the rules, loops play_once(), asks to play again, says thanks |
| Entry guard | the game starts only when the file is run directly, not when imported |
Module map
The guard means importing this file (for testing) won't start a game.
Key ideas
- An endless loop plus an early exit is the standard replay pattern.
- Accept yes, Yes, y, YES by lowering the case and checking the first letter.
Finish a game, answer yes: a new game starts. Answer no: it says thanks and stops.
Common errors
| Message or symptom | Usual cause |
|---|---|
IndentationError | Lines inside a function or loop need the same indent (4 spaces). |
NameError | A name is misspelled, or something was never imported or defined. |
SyntaxError near a def, if, for or while line | Missing colon at the end of the line. |
IndexError: string index out of range | Guess and secret have different lengths. |
| Game never ends | The counter is never increased. |
| Secret has repeated digits | Shuffle all ten digits and slice, instead of picking random digits one by one. |
Read the last line of the error first, then the line number above it. Add a temporary print to see what a variable really holds.
Challenges
- Easy: set the digits to 4, then 5. Does everything still work?
- Easy: set the guesses to 5 for a hard mode.
- Medium: print how many guesses are left after each wrong guess.
- Medium: keep a score of games won and print it on quit.
- Hard: let the player choose the number of digits at the start.
- Hard: reject guesses with repeated digits (hint: a set removes duplicates).
Check your understanding
- Why does the clue module not print or ask for input?
- What would happen if the clues were not sorted?
- What is the job of the entry guard?