Put the parser, the bag and the map together into a text adventure, in three milestones, then make it your own.
Text adventures were among the first computer games, and the same pieces (a parser, an inventory, a map) still sit under every game.
You have built every piece: a parser that tidies and splits commands, a bag that grows and shrinks, and a map of rooms in dictionaries. Now put them together into a text adventure, in three milestones. Each milestone starts from a working game; the last one is yours.
Make your prediction first. Help opens once you've locked it in.
exits = {
"hall": {"north": "kitchen", "east": "garden"},
"kitchen": {"south": "hall"},
"garden": {"west": "hall", "east": "shed"},
}
here = "hall"
for move in ["north", "south", "west", "east", "east"]:
if move in exits[here]:
here = exits[here][move]
print(here)
Follow the moves through the map, one at a time. A move that is not an exit from the room you are in does nothing.
Play it: look, go north, look, bag. You can see things but not take them yet. Each command is one branch of the if / elif chain inside the loop.
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.")
# Milestone 1: take and drop go here.
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.",
}
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.")
# Milestone 1: take and drop go here.
else:
print("Try: look, go north, take lamp, drop lamp, bag or quit")
The third dictionary.
Where it would go.
Where the comment says Milestone 1, add two branches:
take lamp: if the thing is in things[here], remove it from there and append it to bag. If not, say it is not here.drop lamp: if it is in bag, remove it from the bag and append it to things[here]. If not, say you do not have it.Test: take the lamp, carry it to the kitchen, drop it, look.
take moves a thing from the room into the bag, and drop puts it back.
Run your program. This ticks when your code does all of the above.
This version adds a shed east of the garden, and take and drop work. Where the comment says Milestone 2, make the shed locked: if the way leads to "shed" and "key" not in bag (not in is the opposite of in), print The shed is locked. and stay where you are.
The shed only opens when the key is in the bag.
Run your program. This ticks when your code does all of the above.
The game ends with a win message when the crown is in the bag.
After the if / elif chain, still inside the loop: if "crown" in bag:, print a win message and break.
Add something of your own: a room, a thing to find, a help command, a move counter, a second locked door.
Win when the crown is in the bag.
Run your program. This ticks when your code does all of the above.
Every game, from text adventures to open worlds, is this shape: a loop that reads input, rules that change the world, and the world stored as data. Next in this course: saving and loading the game with a file.
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. About 60 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
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.
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.
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.