Session 13 of the Python Fundamentals series, and the first part of the capstone. You plan and start a multi-room text adventure using every Phase 1 skill: sketch the map of rooms and choices, then model each room as a function that prints the scene, reads a cleaned choice, and returns the name of the next room. A while-loop state machine drives the whole thing, and you connect rooms, loop back from dead ends, and handle invalid input by re-prompting. The traps are a room with no handler, forgetting to return the next room, and a loop that never ends. Every snippet was verified under CPython 3.12, with interactive input shown as the sequence the player types.
Subject: Python Fundamentals · 95 slides · code lesson
Open the interactive version of this deck · Homework for this lesson
Title
Python Fundamentals - Session 13
Part 1 - plan the map and build the engine
Objectives
Input, conditionals, loops, lists, dicts, functions, strings, errors - the game uses all of it. This session plans and starts it. By the end you can:
Warm-up
Discussion prompt
Before we open Session 13 - Capstone: Adventure Game (Part 1): without looking back, what was the main idea of Session 12 - Errors & Debugging, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
That session covers reading tracebacks, the common error types, using try and except on specific errors, validation loops, and debugging with print.
Section
Part 1
Concept
A text game is a set of rooms (scenes). In each, the player reads a description and makes a choice that moves them to another room.
That is the whole model: rooms connected by choices, until an ending.
Counterexample
Discussion prompt
A text game is a set of rooms (scenes). In each, the player reads a description and makes a choice that moves them to another room.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Concept
Before any code, draw the map on paper: each room is a box, each choice is an arrow to another box.
Planning the shape first means the code just fills in a structure you already understand.
Analogy
Discussion prompt
Explain Sketch the map first by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Before any code, draw the map on paper: each room is a box, each choice is an arrow to another box.
Intuition
Your boxes become functions; your arrows become the values those functions return. The paper map and the code are the same thing in two forms.
If the map makes sense on paper, the code will follow almost mechanically.
Explain it
Discussion prompt
Explain The map is the program to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Your boxes become functions; your arrows become the values those functions return. The paper map and the code are the same thing in two forms.
Concept
Every room does three things: describe the scene, ask for a choice, and decide which room comes next.
Keep that shape identical across all rooms and the game stays easy to extend.
Section
Part 2
Concept
Give each room its own function: room_start(), room_cave(), room_forest(). One job each - exactly the design from the functions sessions.
Concept
The function prints the scene, reads the choice, and returns a string naming the next room - like "cave" or "forest".
That returned string is the arrow on your map.
Pattern
Predict first
The table runs: left | forest · right | cave
In The starting room, given the rows so far: what is the next one — the row where choice is (other)?
Correct: (other) | start
| choice | returns |
|---|---|
| left | forest |
| right | cave |
| (other) | start |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. strip().lower() forgives spaces and capitals, as in the strings session.
Worked example
The player types right:
def room_start():
print("You stand at a fork. Go (left) or (right)?")
choice = input("> ").strip().lower()
if choice == "left":
return "forest"
elif choice == "right":
return "cave"
print("You hesitate.")
return "start"Describe, then read a cleaned choice
Why: strip().lower() forgives spaces and capitals, as in the strings session.
Return the next room based on the choice
Why: Verified by execution: typing right returns "cave". Left returns "forest"; anything else re-shows start.
| choice | returns |
|---|---|
| left | forest |
| right | cave |
| (other) | start |
Comparison
Comparison matrix
From The starting room: refill the returns column from what you know. The rest of the table is as it appeared.
| choice | returns |
|---|---|
| left | forest |
| right | cave |
| (other) | start |
Concept
The main program will read that returned string and jump to the matching room. The room functions never call each other directly.
This keeps rooms independent - each just says where to go next, and the engine handles the jump.
Section
Part 3
Concept
Keep a variable room holding the current room's name. A while loop calls the matching function and updates room with what it returns.
Fill the middle
Fill in the blanks
From The engine, one room so far — one line has had its right-hand side removed. Put it back.
room = "start"
while room != "done":
if room == "start":
room = room_start()
else:
room = "done"
Why: room is what everything below it consumes, so the wrong expression here fails later and somewhere else. It starts at "start"; each pass replaces it with the next room.
Worked example
The player types right:
room = "start"
while room != "done":
if room == "start":
room = room_start()
else:
room = "done"room holds where the player is now
Why: It starts at "start"; each pass replaces it with the next room.
The loop calls the room and updates room
Why: Verified by execution: room_start() returns "cave", so room becomes "cave"; the else then ends it (until we add that room).
| pass | room before | room after |
|---|---|---|
| 1 | start | cave |
| 2 | cave | done (no handler yet) |
Trade off
Comparison matrix
From The engine, one room so far: every row here is a choice with a cost. Fill the room before column, then say which row you would actually pick and what you give up for it.
| pass | room before | room after |
|---|---|---|
| 1 | start | cave |
| 2 | cave | done (no handler yet) |
Intuition
The current room is the game's state. Each choice moves it to a new state. The loop just keeps stepping from state to state.
state machine — A program that is always in one of several named states and moves between them based on input. Here, each room is a state.
Sorting
Sort into buckets
These are the pieces of Session 13 - Capstone: Adventure Game (Part 1), out of order. Put each one back under the part of the lesson it belongs to.
Concept
Choose special room names for endings - "win", "lose" - and make the loop stop when room becomes one of them.
That is the exit condition, exactly like a sentinel value in the loops session.
Section
Part 4
Concept
For each new room, write its function and add an elif room == "name": that calls it. The engine grows one branch at a time.
Worked example
def room_forest():
print("The forest is a dead end.")
return "start"A dead end simply returns to start
Why: The player is sent back to the fork to try the other path.
Read the flow
Why: Verified by execution: entering forest prints the message and returns "start", so the engine loops back.
| room | returns |
|---|---|
| forest | start |
Error analysis
Annotate
Walk the callouts on A dead-end forest. Each one is a place this is easy to get subtly wrong.
Faded example
Fill in the blanks
Wiring forest into the engine, with the scaffolding fading: two lines are gone now — fill both.
room = "start"
while room not in ("win", "lose"):
if room == "start":
room = room_start()
elif room == "forest":
room = room_forest()
elif room == "cave":
room = "lose"
Why: Reproducing these unaided, rather than reading them, is what tells you the method has transferred. The loop dispatches to the right function based on room.
Worked example
room = "start"
while room not in ("win", "lose"):
if room == "start":
room = room_start()
elif room == "forest":
room = room_forest()
elif room == "cave":
room = "lose"Each room name maps to a branch
Why: The loop dispatches to the right function based on room.
Trace a left-then-loop path
Why: Verified by execution: typing left goes to forest, which returns to start - the player is back at the fork.
| room | action |
|---|---|
| start | room_start() -> forest |
| forest | room_forest() -> start |
| start | back at the fork |
Blank canvas
Draw it
Draw what Wiring forest into the engine just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A room returns "cave", but the loop has no branch for it.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: No branch matches "cave", so room stays "cave" forever - an infinite loop that prints nothing.
Add a branch for every room a function can return.
Why: No branch matches "cave", so room stays "cave" forever - an infinite loop that prints nothing.
Trap
A room returns "cave", but the loop has no branch for it.
while room not in ("win", "lose"):
if room == "start":
room = room_start()
# no elif for "cave"!room becomes "cave" and never changes again
Why: No branch matches "cave", so room stays "cave" forever - an infinite loop that prints nothing.
| room | matched? | next |
|---|---|---|
| cave | no branch | stays cave (stuck) |
Add a branch for every room a function can return.
while room not in ("win", "lose"):
if room == "start":
room = room_start()
elif room == "cave":
room = room_cave()Every returned name has a handler
Why: Now "cave" is handled, so the game advances. Rule: every arrow on your map needs a branch in the loop.
| room | matched? | next |
|---|---|---|
| cave | room_cave() | advances |
Break the constraint
Discussion prompt
The rule this trap just fixed:
Add a branch for every room a function can return.
Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?
Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.
Answer:
No branch matches "cave", so room stays "cave" forever - an infinite loop that prints nothing.
Section
Part 5
Concept
Players type Left, right , RIGHT. Normalize with .strip().lower() before comparing, so all of these work.
Worked example
The player types LEFT :
choice = " LEFT ".strip().lower()
print(choice == "left")Trim and lowercase before comparing
Why: " LEFT " cleans to "left", which matches.
Read the output
Why: Verified by execution: True. Messy input still routes correctly.
| raw | cleaned | == "left" |
|---|---|---|
| LEFT | left | True |
Concept
If the choice matches nothing, return the same room name. The engine will simply run that room again, re-asking the question.
Estimation
Predict first
The player types jump (invalid), then left:
Commit before you compute: what does Staying put on bad input come out to? A rough magnitude and the right form is enough — the point is to have something concrete to be wrong about.
Correct: The engine re-runs start
Why: A prediction you can defend turns the computation into a check rather than a leap of faith — and an answer that contradicts it is caught on the spot. Verified by execution: jump keeps the player at the fork; the next input left then moves to forest.
Worked example
The player types jump (invalid), then left:
def room_start():
print("Go (left) or (right)?")
choice = input("> ").strip().lower()
if choice == "left":
return "forest"
elif choice == "right":
return "cave"
print("You hesitate.")
return "start"Unknown choices fall through to return "start"
Why: jump matches neither branch, so it prints You hesitate and returns start.
The engine re-runs start
Why: Verified by execution: jump keeps the player at the fork; the next input left then moves to forest.
| choice | returns |
|---|---|
| jump | start (re-ask) |
| left | forest |
Anomaly
Predict first
A student writes this, and it looks reasonable:
A branch that prints but does not return.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: With no return, room becomes None, which matches no branch - the engine gets stuck or errors comparing None.
Always return a room name from every path.
Why: With no return, room becomes None, which matches no branch - the engine gets stuck or errors comparing None.
Trap
A branch that prints but does not return.
def room_cave():
print("A cave. (go) deeper?")
choice = input("> ").strip().lower()
if choice == "go":
print("You go deeper.")
# no return!The function returns None
Why: With no return, room becomes None, which matches no branch - the engine gets stuck or errors comparing None.
| room after room_cave() | problem |
|---|---|
| None | matches no branch |
Always return a room name from every path.
def room_cave():
print("A cave. (go) deeper?")
choice = input("> ").strip().lower()
if choice == "go":
return "deep"
return "cave"Every path returns a next room
Why: go leads deeper; anything else re-asks the cave. No path leaves the function without a return.
| choice | returns |
|---|---|
| go | deep |
| (other) | cave |
Section
Part 6
Concept
A minimal playable skeleton: a start room, two rooms it leads to, and the engine loop. Endings come in Part 2.
Get this running first, then flesh out rooms one at a time.
Fill the middle
Fill in the blanks
From The full skeleton — one line has had its right-hand side removed. Put it back.
def room_start():
print("A fork. (left) or (right)?")
c = input("> ").strip().lower()
if c == "left":
return "forest"
if c == "right":
return "cave"
return "start"
def room_forest():
print("Dead end.")
return "start"
def room_cave():
print("You found the exit!")
return "win"
room = "start"
while room != "win":
if room == "start":
room = room_start()
elif room == "forest":
room = room_forest()
elif room == "cave":
room = room_cave()
print("You escaped!")
Why: room is what everything below it consumes, so the wrong expression here fails later and somewhere else. Each room returns a name; the loop dispatches until room is "win".
Worked example
def room_start():
print("A fork. (left) or (right)?")
c = input("> ").strip().lower()
if c == "left":
return "forest"
if c == "right":
return "cave"
return "start"
def room_forest():
print("Dead end.")
return "start"
def room_cave():
print("You found the exit!")
return "win"
room = "start"
while room != "win":
if room == "start":
room = room_start()
elif room == "forest":
room = room_forest()
elif room == "cave":
room = room_cave()
print("You escaped!")Three rooms, one loop
Why: Each room returns a name; the loop dispatches until room is "win".
Trace a winning path (right)
Why: Verified by execution: right -> cave -> win, then prints You escaped!
| room | returns |
|---|---|
| start | cave (typed right) |
| cave | win |
| (loop ends) | You escaped! |
Comparison
Comparison matrix
From The full skeleton: refill the returns column from what you know. The rest of the table is as it appeared.
| room | returns |
|---|---|
| start | cave (typed right) |
| cave | win |
| (loop ends) | You escaped! |
Worked example
Following left, then right:
# left -> forest -> start -> right -> cave -> winDead ends loop back, real paths progress
Why: left goes to the forest dead end and back to start; right then reaches the cave and wins.
Read the room path
Why: Verified by execution against the skeleton: this is a valid play-through.
| step | room |
|---|---|
| 1 | start |
| 2 | forest |
| 3 | start |
| 4 | cave |
| 5 | win |
Pattern
Step through it
Step through Trace the transitions one row at a time. What is driving the change, and what would the row after the last one be?
Section
Part 7
Anomaly
Predict first
A student writes this, and it looks reasonable:
No room ever returns an ending name.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: If no room returns "win", room != "win" is always true and the game loops forever.
Make sure at least one room can return the ending.
Why: If no room returns "win", room != "win" is always true and the game loops forever.
Trap
No room ever returns an ending name.
while room != "win":
if room == "start":
room = room_start()
elif room == "forest":
room = room_forest()
# but nothing ever returns "win"The exit condition can never be met
Why: If no room returns "win", room != "win" is always true and the game loops forever.
| condition | ever false? |
|---|---|
| room != "win" | no -> infinite |
Make sure at least one room can return the ending.
def room_cave():
print("You found the exit!")
return "win"A reachable room returns the ending
Why: Now room can become "win", so the loop can end. Every game needs a reachable ending, like a loop needs a way to stop.
| room | returns |
|---|---|
| cave | win -> loop ends |
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
Concept
All the room functions must be defined above the engine loop that calls them - Python reads top to bottom.
Concept
If a room grows complicated, split its work into helper functions. A room function should mostly be: print, read, decide, return.
Section
Part 8
Concept
A room can print several lines to set the mood before asking for a choice. More description makes the game feel real.
Worked example
def room_cave():
print("Cold air drifts from a dark cave.")
print("A faint glow flickers deeper in.")
c = input("(enter) or (leave)? ").strip().lower()
if c == "enter":
return "deep"
return "start"Several prints, then one choice
Why: The description is just extra print lines; the choice logic is unchanged.
Read the flow
Why: Verified by execution: enter -> deep; anything else -> start.
| choice | returns |
|---|---|
| enter | deep |
| (other) | start |
Blank canvas
Draw it
Draw what A described room just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Concept
Store a room's exits in a list and loop over them to print a numbered menu - the lists and loops sessions, put to work.
Faded example
Fill in the blanks
A numbered-door room, with the scaffolding fading: two lines are gone now — fill both.
def room_hall():
print("A hall with three doors:")
exits = ["kitchen", "study", "cellar"]
for i in range(len(exits)):
print(i + 1, exits[i])
c = input("> ").strip()
if c in ("1", "2", "3"):
return exits[int(c) - 1]
return "hall"
Why: Reproducing these unaided, rather than reading them, is what tells you the method has transferred. range(len(exits)) gives 0, 1, 2; i + 1 shows human numbers 1, 2, 3.
Worked example
The player types 2:
def room_hall():
print("A hall with three doors:")
exits = ["kitchen", "study", "cellar"]
for i in range(len(exits)):
print(i + 1, exits[i])
c = input("> ").strip()
if c in ("1", "2", "3"):
return exits[int(c) - 1]
return "hall"Loop prints numbered options
Why: range(len(exits)) gives 0, 1, 2; i + 1 shows human numbers 1, 2, 3.
Map the number back to a room
Why: Verified by execution: typing 2 returns exits[1] = "study". Convert the choice to an index with int(c) - 1.
| typed | index | returns |
|---|---|---|
| 1 | 0 | kitchen |
| 2 | 1 | study |
| 3 | 2 | cellar |
Pattern
Step through it
Step through A numbered-door room one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Every room reads a cleaned choice. Wrap that in a helper: def ask(prompt): return input(prompt).strip().lower().
Now each room calls ask(...) instead of repeating the strip/lower - the DRY idea from the functions session.
Worked example
The player types RIGHT :
def ask(prompt):
return input(prompt).strip().lower()
def room_start():
if ask("(left) or (right)? ") == "right":
return "cave"
return "forest"ask cleans the input in one place
Why: room_start no longer repeats strip().lower(); ask does it.
Read the flow
Why: Verified by execution: " RIGHT " cleans to "right", so it returns "cave".
| raw | ask cleans to | returns |
|---|---|---|
| RIGHT | right | cave |
Error analysis
Annotate
Walk the callouts on Rooms share the helper. Each one is a place this is easy to get subtly wrong.
Intuition
One ask helper serves every room. Fix input handling once - say, also stripping punctuation - and every room improves at once.
This is why the earlier design work pays off: the game is just small, familiar pieces wired together.
Section
Part 9
Concept
You can win with just two rooms and an ending. Build the tiniest complete game first, then grow it.
Fill the middle
Fill in the blanks
From Two rooms and a win — one line has had its right-hand side removed. Put it back.
def entrance():
print("A door stands before you. (open) it?")
if input("> ").strip().lower() == "open":
return "treasure"
return "entrance"
def treasure():
print("Gold everywhere!")
return "win"
room = "entrance"
while room != "win":
if room == "entrance":
room = entrance()
elif room == "treasure":
room = treasure()
print("YOU WIN")
Why: room is what everything below it consumes, so the wrong expression here fails later and somewhere else. open moves to treasure; treasure returns win, ending the loop.
Worked example
The player types open:
def entrance():
print("A door stands before you. (open) it?")
if input("> ").strip().lower() == "open":
return "treasure"
return "entrance"
def treasure():
print("Gold everywhere!")
return "win"
room = "entrance"
while room != "win":
if room == "entrance":
room = entrance()
elif room == "treasure":
room = treasure()
print("YOU WIN")entrance leads to treasure, which wins
Why: open moves to treasure; treasure returns win, ending the loop.
Read the play-through
Why: Verified by execution: prints the scenes, then YOU WIN.
| room | returns |
|---|---|
| entrance | treasure |
| treasure | win |
Trade off
Comparison matrix
From Two rooms and a win: every row here is a choice with a cost. Fill the returns column, then say which row you would actually pick and what you give up for it.
| room | returns |
|---|---|
| entrance | treasure |
| treasure | win |
Pattern
Predict first
The table runs: 1 | entrance · 2 | treasure
In Trace the mini-game, given the rows so far: what is the next one — the row where pass is 3?
Correct: 3 | win (loop ends)
| pass | room |
|---|---|
| 1 | entrance |
| 2 | treasure |
| 3 | win (loop ends) |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. The state moves entrance -> treasure -> win, then the loop stops.
Worked example
Following the open path:
# entrance --open--> treasure --> winTwo hops to victory
Why: The state moves entrance -> treasure -> win, then the loop stops.
Read the states
Why: Verified by execution against the mini-game.
| pass | room |
|---|---|
| 1 | entrance |
| 2 | treasure |
| 3 | win (loop ends) |
Comparison
Comparison matrix
From Trace the mini-game: refill the room column from what you know. The rest of the table is as it appeared.
| pass | room |
|---|---|
| 1 | entrance |
| 2 | treasure |
| 3 | win (loop ends) |
Concept
Add rooms one at a time, testing after each. A working two-room game plus one new room is easier to debug than ten rooms written at once.
This is your homework path: sketch a 4-room map, then build it room by room on top of this skeleton.
Explain it
Discussion prompt
Explain Grow from the mini-game to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Add rooms one at a time, testing after each. A working two-room game plus one new room is easier to debug than ten rooms written at once.
Concept
"win" and "lose" are room names too - but instead of having a function, they are the values that stop the loop.
After the loop, an if room == "win": decides which closing message to print. That final check is your ending screen.
Analogy
Discussion prompt
Explain Endings are just special rooms by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
"win" and "lose" are room names too - but instead of having a function, they are the values that stop the loop.
Concept
After writing a room, play through it immediately. Catch a missing return or a wrong room name while the change is small and fresh.
Slow and steady beats writing the whole game and facing ten bugs at once - the debugging lesson applied to a real project.
Counterexample
Discussion prompt
After writing a room, play through it immediately. Catch a missing return or a wrong room name while the change is small and fresh.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
Slow and steady beats writing the whole game and facing ten bugs at once - the debugging lesson applied to a real project.
Section
Part 10
Pattern
1. List the rooms as boxes
Why: start, forest, cave, ... plus ending rooms like win/lose.
2. Draw the choices as arrows
Why: Each arrow is a choice that leads from one room to another.
3. Every arrow becomes a return; every box a function
Why: The map converts directly into code.
4. Make sure an ending is reachable
Why: There must be a path to win (and usually one to lose).
Pattern
Print the scene
Why: Describe where the player is and the choices available.
Read a cleaned choice
Why: input().strip().lower() so messy input still works.
Return the next room from every path
Why: Match choices to room names; on invalid input, return the same room to re-ask.
Real world
Discussion prompt
Outside this lesson: where does Session 13 - Capstone: Adventure Game (Part 1) actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of Writing a room function is doing the work in it.
Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.
Answer:
Session 13 of the Python Fundamentals series - the capstone, part 1. Plan and start a multi-room text adventure using every Phase 1 skill: sketch the map (rooms and choices), model each room as a function that prints the scene, reads a cleaned choice, and returns the next room's name; drive it all with a while-loop state machine; connect rooms, loop back from dead ends, and handle invalid input by re-prompting.
Check
The player types right.
def room_start():
c = input("> ").strip().lower()
if c == "left":
return "forest"
elif c == "right":
return "cave"
return "start"| choice | returns |
|---|---|
| right | ? |
Check your understanding
What does room_start() return?
Answer: A
Why: right matches the second branch, so the function returns "cave", telling the engine to go to the cave room next. Verified by execution.
Check
What role does room play?
room = "start"
while room != "win":
if room == "start":
room = room_start()| room | means |
|---|---|
| current value | ? |
Check your understanding
What does the variable room represent?
Answer: A
Why: room holds the name of the current room - the game's state. Each pass replaces it with the next room the player moves to. Verified by the loop's logic.
Check
room becomes "cave", but there is no elif for it.
while room != "win":
if room == "start":
room = room_start() # returns "cave"| room | handled? |
|---|---|
| cave | ? |
Check your understanding
What happens after room becomes "cave"?
Answer: A
Why: With no branch matching "cave", room never changes and "cave" is never "win", so the while loop runs forever doing nothing. Add an elif for cave to fix it. Verified by reasoning about the loop.
Check
The player types jump at the fork.
def room_start():
c = input("> ").strip().lower()
if c == "left":
return "forest"
elif c == "right":
return "cave"
return "start"| choice | returns |
|---|---|
| jump | ? |
Check your understanding
What does room_start() return for jump?
Answer: A
Why: jump matches neither branch, so control falls through to return "start", and the engine re-runs the start room - re-asking the question. Verified by execution.
Elimination
Eliminate the wrong options
When does the loop stop and print You escaped!?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: The loop runs while room != "win". As soon as a room function returns "win", room becomes "win", the condition is false, and the loop ends - then You escaped! prints. Verified by the loop logic.
Check
The loop condition.
while room != "win":
...
print("You escaped!")| room | loop |
|---|---|
| win | ? |
Check your understanding
When does the loop stop and print You escaped!?
Answer: A
Why: The loop runs while room != "win". As soon as a room function returns "win", room becomes "win", the condition is false, and the loop ends - then You escaped! prints. Verified by the loop logic.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — Plan Before You Build · A Room Is a Function · The Game Loop · Connecting Rooms · Handling the Choice · Build: the Skeleton. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
Plan the map (rooms + choices), write one function per room that returns the next room's name, and drive it with a while-loop state machine.
| Map piece | Code piece |
|---|---|
| a room (box) | a function room_x() |
| a choice (arrow) | a return "next_room" |
| current location | the room variable |
| the engine | while + if/elif dispatch |
| an ending | return "win" / "lose" |
Every returned room needs a branch, every path needs a return, and an ending must be reachable. Next session we add state - a score and an inventory - and real win/lose endings.
Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.