Students combine the parser, the bag and the map into a text adventure in three milestones (take and drop, a locked shed, a win plus a change of their own), each starting from a working game.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict, Run and Investigate 15 min · Milestone 1 15 min · Milestone 2 10 min · Milestone 3 20 min
Read the unit primers first. The game keeps three dictionaries: rooms (descriptions), exits (each room's dictionary of directions) and things (each room's list of things). here is the current room and bag is a list. Each command is one elif branch inside while True. Milestone 1 moves a thing between things[here] and bag; Milestone 2 adds one check ("key" not in bag; not in is the opposite of in, said once in the text); Milestone 3 is goals only. Each milestone starts from a working version, so a student stuck on one can still do the next.
Holding several parts in mind: the loop, the parser, the rooms and the bag. Point them back to the milestone list and have them test one command at a time.
| What you will see | A question to ask | The fix |
|---|---|---|
| Taking something says it is not here, though look shows it. | Is the word being checked exactly as stored (small letters)? | The command is lowered; store things in small letters too. |
| The shed opens without the key. | Does the check happen before here = ... changes? | Check where the way leads first, and only move if it is allowed. |
| The win message never appears. | Is the win check inside the loop, after the commands? | Put if "crown" in bag: at the end of the loop body, with break. |
One possible solution for each task. Other correct programs are fine.
rooms = {
"hall": "A long hall with a creaky floor.",
"kitchen": "A kitchen that smells of toast.",
"garden": "A garden full of tall grass.",
}
exits = {
"hall": {"north": "kitchen", "east": "garden"},
"kitchen": {"south": "hall"},
"garden": {"west": "hall"},
}
things = {
"hall": ["lamp"],
"kitchen": ["key"],
"garden": [],
}
bag = []
here = "hall"
print(rooms[here])
while True:
command = input("> ").strip().lower()
words = command.split()
if command == "quit":
break
elif command == "look":
print(rooms[here])
print("Exits: " + ", ".join(exits[here]))
if len(things[here]) > 0:
print("You see: " + ", ".join(things[here]))
elif command == "bag":
print("You carry: " + ", ".join(bag))
elif len(words) == 2 and words[0] == "go":
if words[1] in exits[here]:
here = exits[here][words[1]]
print(rooms[here])
else:
print("You can't go that way.")
elif len(words) == 2 and words[0] == "take":
if words[1] in things[here]:
things[here].remove(words[1])
bag.append(words[1])
print("You take the " + words[1] + ".")
else:
print("There is no " + words[1] + " here.")
elif len(words) == 2 and words[0] == "drop":
if words[1] in bag:
bag.remove(words[1])
things[here].append(words[1])
print("You drop the " + words[1] + ".")
else:
print("You don't have a " + words[1] + ".")
else:
print("Try: look, go north, take lamp, drop lamp, bag or quit")
rooms = {
"hall": "A long hall with a creaky floor.",
"kitchen": "A kitchen that smells of toast.",
"garden": "A garden full of tall grass. A locked shed stands to the east.",
"shed": "A dusty shed. Something glints in the corner.",
}
exits = {
"hall": {"north": "kitchen", "east": "garden"},
"kitchen": {"south": "hall"},
"garden": {"west": "hall", "east": "shed"},
"shed": {"west": "garden"},
}
things = {
"hall": ["lamp"],
"kitchen": ["key"],
"garden": [],
"shed": ["crown"],
}
bag = []
here = "hall"
print(rooms[here])
while True:
command = input("> ").strip().lower()
words = command.split()
if command == "quit":
break
elif command == "look":
print(rooms[here])
print("Exits: " + ", ".join(exits[here]))
if len(things[here]) > 0:
print("You see: " + ", ".join(things[here]))
elif command == "bag":
print("You carry: " + ", ".join(bag))
elif len(words) == 2 and words[0] == "go":
if words[1] in exits[here]:
if exits[here][words[1]] == "shed" and "key" not in bag:
print("The shed is locked.")
else:
here = exits[here][words[1]]
print(rooms[here])
else:
print("You can't go that way.")
elif len(words) == 2 and words[0] == "take":
if words[1] in things[here]:
things[here].remove(words[1])
bag.append(words[1])
print("You take the " + words[1] + ".")
else:
print("There is no " + words[1] + " here.")
elif len(words) == 2 and words[0] == "drop":
if words[1] in bag:
bag.remove(words[1])
things[here].append(words[1])
print("You drop the " + words[1] + ".")
else:
print("You don't have a " + words[1] + ".")
else:
print("Try: look, go north, take lamp, drop lamp, bag or quit")
rooms = {
"hall": "A long hall with a creaky floor.",
"kitchen": "A kitchen that smells of toast.",
"garden": "A garden full of tall grass. A locked shed stands to the east.",
"shed": "A dusty shed. Something glints in the corner.",
}
exits = {
"hall": {"north": "kitchen", "east": "garden"},
"kitchen": {"south": "hall"},
"garden": {"west": "hall", "east": "shed"},
"shed": {"west": "garden"},
}
things = {
"hall": ["lamp"],
"kitchen": ["key"],
"garden": [],
"shed": ["crown"],
}
bag = []
here = "hall"
moves = 0
print(rooms[here])
while True:
command = input("> ").strip().lower()
words = command.split()
if command == "quit":
break
elif command == "look":
print(rooms[here])
print("Exits: " + ", ".join(exits[here]))
if len(things[here]) > 0:
print("You see: " + ", ".join(things[here]))
elif command == "bag":
print("You carry: " + ", ".join(bag))
elif len(words) == 2 and words[0] == "go":
if words[1] in exits[here]:
if exits[here][words[1]] == "shed" and "key" not in bag:
print("The shed is locked.")
else:
here = exits[here][words[1]]
moves += 1
print(rooms[here])
else:
print("You can't go that way.")
elif len(words) == 2 and words[0] == "take":
if words[1] in things[here]:
things[here].remove(words[1])
bag.append(words[1])
print("You take the " + words[1] + ".")
else:
print("There is no " + words[1] + " here.")
elif len(words) == 2 and words[0] == "drop":
if words[1] in bag:
bag.remove(words[1])
things[here].append(words[1])
print("You drop the " + words[1] + ".")
else:
print("You don't have a " + words[1] + ".")
else:
print("Try: look, go north, take lamp, drop lamp, bag or quit")
if "crown" in bag:
print("You found the crown in " + str(moves) + " moves. You win!")
break
Open task: any program that does what the step asks.
Stretch: Add a second item that must be used somewhere (light the lamp in a dark cellar), or a timer of moves that ends the game.
Support: Give students the take branch for Milestone 1 and ask them to write drop by mirroring it.
Which data structure would you use for the things in each room, and why?
A dictionary from room name to a list: look up the room by name, and the list grows and shrinks as things are taken and dropped.
Saving and loading the game is the next part of this course (files, then try for a missing file). Game engines use the same shape: a loop, input, rules and the world as data.