Session 13 - Capstone: Adventure Game (Part 1)

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

What this lesson covers

The lesson, slide by slide

1. Capstone: Adventure Game

Title

Python Fundamentals - Session 13

Part 1 - plan the map and build the engine

2. What you will be able to do

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:

  1. Sketch a game map as rooms and choices.
  2. Write one function per room that returns the next room's name.
  3. Drive the rooms with a while-loop state machine.
  1. Connect rooms, loop back from dead ends, and re-prompt on bad input.
  2. Avoid the no-handler, no-return, and no-ending traps.

3. What survived from Session 12 - Errors & Debugging?

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.

4. Plan Before You Build

Section

Part 1

5. A text adventure is rooms and choices

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.

6. Break it if you can: A text adventure is rooms and choices

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.

7. Sketch the map first

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.

8. By analogy: Sketch the map first

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.

9. The map is the program

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.

10. Teach it back: The map is the program

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.

11. A room: scene, choice, next

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.

12. A Room Is a Function

Section

Part 2

13. One function per room

Concept

Give each room its own function: room_start(), room_cave(), room_forest(). One job each - exactly the design from the functions sessions.

14. A room returns the next room's name

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.

15. Predict the next row: The starting room

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

choicereturns
leftforest
rightcave
(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.

16. The starting room

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.

choicereturns
leftforest
rightcave
(other)start

17. Fill in: returns for The starting room

Comparison

Comparison matrix

From The starting room: refill the returns column from what you know. The rest of the table is as it appeared.

choicereturns
leftforest
rightcave
(other)start

18. The return value drives the game

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.

19. The Game Loop

Section

Part 3

20. A while loop drives the rooms

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.

21. Restore the missing line: The engine, one room so far

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.

22. The engine, one room so far

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).

passroom beforeroom after
1startcave
2cavedone (no handler yet)

23. What each one costs: The engine, one room so far

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.

passroom beforeroom after
1startcave
2cavedone (no handler yet)

24. This is a state machine

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.

25. Where does each piece belong: Session 13 - Capstone: Adventure Game (Part…

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.

Plan Before You Build
A text adventure is rooms and choices; Sketch the map first; The map is the program
A Room Is a Function
One function per room; A room returns the next room's name; The starting room
The Game Loop
A while loop drives the rooms; The engine, one room so far; This is a state machine
s1
Plan Before You Build is where Session 13 - Capstone: Adventure Game (Part 1) puts A text adventure is rooms and choices, Sketch the map first, The map is the program. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s2
A Room Is a Function is where Session 13 - Capstone: Adventure Game (Part 1) puts One function per room, A room returns the next room's name, The starting room. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.
s3
The Game Loop is where Session 13 - Capstone: Adventure Game (Part 1) puts A while loop drives the rooms, The engine, one room so far, This is a state machine. Knowing which part of the lesson a problem belongs to is most of knowing which method to reach for.

26. The loop ends at an ending room

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.

27. Connecting Rooms

Section

Part 4

28. Add a room, add an elif

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.

29. A dead-end forest

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.

roomreturns
foreststart

30. Inspect it line by line: A dead-end forest

Error analysis

Annotate

Walk the callouts on A dead-end forest. Each one is a place this is easy to get subtly wrong.

  • The player is sent back to the fork to try the other path.
  • Verified by execution: entering forest prints the message and returns "start", so the engine loops back.

31. Finish it with less help: Wiring forest into the engine

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.

32. Wiring forest into the engine

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.

roomaction
startroom_start() -> forest
forestroom_forest() -> start
startback at the fork

33. Draw the shape of it: Wiring forest into the engine

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.

34. Something is wrong here: a room with no handler

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.

35. Trap: a room with no handler

Trap

The 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.

roommatched?next
caveno branchstays cave (stuck)

The fix

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.

roommatched?next
caveroom_cave()advances

36. Break it on purpose: a room with no handler

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.

37. Handling the Choice

Section

Part 5

38. Clean the player's input

Concept

Players type Left, right , RIGHT. Normalize with .strip().lower() before comparing, so all of these work.

39. Forgiving choices

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.

rawcleaned== "left"
LEFT leftTrue

40. Invalid choice: re-prompt

Concept

If the choice matches nothing, return the same room name. The engine will simply run that room again, re-asking the question.

41. Guess the shape of the answer: Staying put on bad input

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.

42. Staying put on bad input

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.

choicereturns
jumpstart (re-ask)
leftforest

43. Something is wrong here: forgetting to return

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.

44. Trap: forgetting to return

Trap

The 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
Nonematches no branch

The fix

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.

choicereturns
godeep
(other)cave

45. Build: the Skeleton

Section

Part 6

46. Start + two branches + loop

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.

47. Restore the missing line: The full skeleton

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".

48. The full skeleton

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!

roomreturns
startcave (typed right)
cavewin
(loop ends)You escaped!

49. Fill in: returns for The full skeleton

Comparison

Comparison matrix

From The full skeleton: refill the returns column from what you know. The rest of the table is as it appeared.

roomreturns
startcave (typed right)
cavewin
(loop ends)You escaped!

50. Trace the transitions

Worked example

Following left, then right:

# left -> forest -> start -> right -> cave -> win

Dead 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.

steproom
1start
2forest
3start
4cave
5win

51. Watch it run: Trace the transitions

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?

  1. Step 1: step is 1
  2. Step 2: step is 2
  3. Step 3: step is 3
  4. Step 4: step is 4
  5. Step 5: step is 5

52. Pitfalls

Section

Part 7

53. Something is wrong here: a loop with no ending

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.

54. Trap: a loop with no ending

Trap

The 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.

conditionever false?
room != "win"no -> infinite

The fix

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.

roomreturns
cavewin -> loop ends

55. Which of these survive contact with Session 13 - Capstone: Adventure Game (Part…?

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.

Holds up
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.; Before any code, draw the map on paper: each room is a box, each choice is an arrow to another box.; 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.
Breaks
A room returns "cave", but the loop has no branch for it.; A branch that prints but does not return.
sound
These are stated as this lesson states them — each one survives the edge cases Session 13 - Capstone: Adventure Game (Part 1) puts it through.
flawed
Each of these is lifted from a trap in this deck: reasonable-sounding, and wrong in a way that only shows up once you rely on it.

56. Define rooms before the loop

Concept

All the room functions must be defined above the engine loop that calls them - Python reads top to bottom.

57. Keep each room small

Concept

If a room grows complicated, split its work into helper functions. A room function should mostly be: print, read, decide, return.

58. Richer Rooms

Section

Part 8

59. Describe the scene vividly

Concept

A room can print several lines to set the mood before asking for a choice. More description makes the game feel real.

60. A described room

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.

choicereturns
enterdeep
(other)start

61. Draw the shape of it: A described room

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.

62. List the exits from a list

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.

63. Finish it with less help: A numbered-door room

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.

64. A numbered-door room

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.

typedindexreturns
10kitchen
21study
32cellar

65. Watch it run: A numbered-door room

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?

  1. Step 1: typed is 1
  2. Step 2: typed is 2
  3. Step 3: typed is 3

66. A reusable ask helper

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.

67. Rooms share the helper

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".

rawask cleans toreturns
RIGHT rightcave

68. Inspect it line by line: Rooms share the helper

Error analysis

Annotate

Walk the callouts on Rooms share the helper. Each one is a place this is easy to get subtly wrong.

  • room_start no longer repeats strip().lower(); ask does it.
  • Verified by execution: " RIGHT " cleans to "right", so it returns "cave".

69. Small helpers, many rooms

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.

70. A Two-Room Mini-Game

Section

Part 9

71. The smallest complete game

Concept

You can win with just two rooms and an ending. Build the tiniest complete game first, then grow it.

72. Restore the missing line: Two rooms and a win

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.

73. Two rooms and a win

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.

roomreturns
entrancetreasure
treasurewin

74. What each one costs: Two rooms and a 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.

roomreturns
entrancetreasure
treasurewin

75. Predict the next row: Trace the mini-game

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)

passroom
1entrance
2treasure
3win (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.

76. Trace the mini-game

Worked example

Following the open path:

# entrance --open--> treasure --> win

Two 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.

passroom
1entrance
2treasure
3win (loop ends)

77. Fill in: room for Trace the mini-game

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.

passroom
1entrance
2treasure
3win (loop ends)

78. Grow from the mini-game

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.

79. Teach it back: Grow from the mini-game

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.

80. Endings are just special rooms

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.

81. By analogy: Endings are just special rooms

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.

82. Test each room as you add it

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.

83. Break it if you can: Test each room as you add it

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.

84. Patterns & Checks

Section

Part 10

85. Designing the map

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).

86. Writing a room function

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.

87. Where this shows up: Session 13 - Capstone: Adventure Game (Part 1)

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.

88. Check: what does a room return?

Check

The player types right.

def room_start():
    c = input("> ").strip().lower()
    if c == "left":
        return "forest"
    elif c == "right":
        return "cave"
    return "start"
choicereturns
right?

Check your understanding

What does room_start() return?

  • A. "cave" (correct)
  • B. "forest"
  • C. "start"
  • D. None

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.

Why B tempts people
"forest" is returned for left, not right.
Why C tempts people
"start" is the fallback for an unrecognized choice; right is recognized.
Why D tempts people
Every path returns a room name, so it is not None.

89. Check: the state variable

Check

What role does room play?

room = "start"
while room != "win":
    if room == "start":
        room = room_start()
roommeans
current value?

Check your understanding

What does the variable room represent?

  • A. The room the player is currently in (correct)
  • B. The number of rooms
  • C. The player's score
  • D. A list of all rooms

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.

Why B tempts people
room is a single name string, not a count of rooms.
Why C tempts people
Score is separate state, added in Part 2; room is the location.
Why D tempts people
room is one name at a time, not a list of every room.

90. Check: no handler

Check

room becomes "cave", but there is no elif for it.

while room != "win":
    if room == "start":
        room = room_start()  # returns "cave"
roomhandled?
cave?

Check your understanding

What happens after room becomes "cave"?

  • A. The loop spins forever with room stuck on "cave" (correct)
  • B. It prints the cave room
  • C. It ends the game
  • D. It raises a KeyError

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.

Why B tempts people
There is no code to run the cave room, so nothing about the cave prints.
Why C tempts people
The loop only ends when room == "win"; it never reaches that.
Why D tempts people
There is no dictionary lookup here, so no KeyError - just an infinite loop.

91. Check: invalid input

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"
choicereturns
jump?

Check your understanding

What does room_start() return for jump?

  • A. "start" - so the room is asked again (correct)
  • B. "forest"
  • C. None
  • D. It raises an error

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.

Why B tempts people
"forest" is only for left; jump is unrecognized.
Why C tempts people
There is a fallback return "start", so it is not None.
Why D tempts people
An unrecognized choice is handled gracefully, not with an error.

92. Rule out three: Check: the ending

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.

  • A. When a room returns "win"
  • B. After exactly 10 passes
  • C. When the player types win
  • D. Never

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.

93. Check: the ending

Check

The loop condition.

while room != "win":
    ...
print("You escaped!")
roomloop
win?

Check your understanding

When does the loop stop and print You escaped!?

  • A. When a room returns "win" (correct)
  • B. After exactly 10 passes
  • C. When the player types win
  • D. Never

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.

Why B tempts people
There is no pass counter; the loop ends based on the room value, not a fixed count.
Why C tempts people
The player types choices like left/right; "win" is produced by a room's return, not typed.
Why D tempts people
It does end - as long as some reachable room returns "win".

94. Connect it up: Session 13 - Capstone: Adventure Game (Part 1)

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.

95. What you can do now

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 pieceCode piece
a room (box)a function room_x()
a choice (arrow)a return "next_room"
current locationthe room variable
the enginewhile + if/elif dispatch
an endingreturn "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.

Sources

  1. Python 3 Tutorial - Control Flow (while, functions)
  2. All snippets executed under CPython 3.12; interactive input shown as typed values. — Author verification run, 2026-07-15 (Python Fundamentals series, Session 13).

Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108