Python Arena
Project · After module 23: Reading files

A text adventure

In this project you build a text adventure: a game that tells you where you are, reads what you want to do (go north, take key), and answers in text. The world isn't written into the program. It comes from a file, world.txt, so the same program can play any world that the file describes.

When it's finished, this file is a whole world: the house of an old clockmaker, with five rooms, three things to find, a locked door and a goal.

room;Workshop;Half-built clocks tick on every shelf.
room;Hallway;A long hallway. The grandfather clock here has stopped.
room;Kitchen;A kettle sits on a cold stove.
room;Attic;Dusty boxes stand under a round window.
room;Clock Tower;Huge wheels fill the tower. One gear is missing.
exit;Workshop;north;Hallway
exit;Hallway;south;Workshop
exit;Hallway;east;Kitchen
exit;Hallway;up;Attic
exit;Kitchen;west;Hallway
exit;Attic;down;Hallway
exit;Attic;up;Clock Tower
exit;Clock Tower;down;Attic
item;Workshop;key
item;Kitchen;gear
item;Attic;oil
lock;Attic;up;key
goal;Clock Tower;gear;You fit the gear into place, and the great clock starts ticking again.

A player who types these commands, one per line:

take key
go north
go east
take gear
go west
go up
go up

sees this, with the game's prompt > in front of each command:

== Workshop ==
Half-built clocks tick on every shelf.
Exits: north
You see: key
> take key
You take the key.
> go north
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east, up
> go east
== Kitchen ==
A kettle sits on a cold stove.
Exits: west
You see: gear
> take gear
You take the gear.
> go west
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east, up
> go up
== Attic ==
Dusty boxes stand under a round window.
Exits: down, up
You see: oil
> go up
You unlock the way up with the key.
== Clock Tower ==
Huge wheels fill the tower. One gear is missing.
Exits: down
You fit the gear into place, and the great clock starts ticking again.
You won in 5 moves.

What you need

Everything up to module 23: functions that return values (modules 13 and 14), lists (module 15), the string methods split, join and strip (module 18), dictionaries, also dictionaries inside a dictionary (module 21), a function that returns two values as a tuple (module 22), and reading a file line by line with with open(...) (module 23).

How you build it

Every line of world.txt starts with its kind (room, exit, item, lock or goal), then the name of the room it's about, and then the rest, all separated by ;. The room lines come first in the file. Each milestone teaches the program one more kind of line, with the commands that go with it:

  1. Rooms: the rooms from the file, and a loop that reads commands.
  2. Exits: go north takes you to the next room.
  3. Things to carry: take, drop and inventory.
  4. A locked door: an exit that opens only for a player who carries the right thing.
  5. The goal: the game ends when you reach it, and counts your moves.

The program skips the lines of a kind it doesn't know yet, so a world file written for a later milestone still works with an earlier program.

Milestones

  1. Rooms
  2. Exits
  3. Things to carry
  4. A locked door
  5. The goal

Milestone 1: Rooms

The starting code opens world.txt and splits each of its lines at ;. A line such as room;Workshop;Half-built clocks tick on every shelf. is a room: the word room, the room's name and its description.

  1. In read_world, add each room to the dictionary rooms. The key is the room's name, and the value is a dictionary of its own, for everything the game knows about that room. For now that's only the description: {"description": "Half-built clocks tick on every shelf."}. The game starts in the first room of the file, so start is the name of that room. A line of another kind (the next milestones read those) is simply skipped.

  2. Write show_room(rooms, name), which prints the room's name between == signs, and its description under it:

    == Workshop ==
    Half-built clocks tick on every shelf.
  3. In main, show the room where the game starts. Then read commands with the prompt > , one at a time, until the player types quit:

    • look shows the room again.
    • quit prints Goodbye! and ends the game.
    • Anything else prints I don't understand that.

With this world.txt

room;Workshop;Half-built clocks tick on every shelf.
room;Hallway;A long hallway. The grandfather clock here has stopped.

and the commands look, dance and quit, the program prints:

== Workshop ==
Half-built clocks tick on every shelf.
> look
== Workshop ==
Half-built clocks tick on every shelf.
> dance
I don't understand that.
> quit
Goodbye!

Milestone 2: Exits

Now the rooms get exits. A line such as exit;Workshop;north;Hallway means: from the Workshop, the way north leads to the Hallway. The room lines come first in the file, so every room that an exit line names already exists when the line is read.

  1. Give each room's dictionary the key "exits", with an empty dictionary as its value when the room is created. For each exit line, read_world adds the direction as a key to that dictionary, with the name of the room it leads to as the value.
  2. When a room has exits, show_room prints one more line after the description, with their directions in the order of the file, separated by a comma and a space: Exits: south, east. A room without exits prints no such line.
  3. A new command: go and a direction, such as go north, takes the player through that exit and shows the new room. When the room has no exit that way, it prints You can't go west from here. (with the direction the player typed). Only a command of exactly these two words is a move; go on its own is still a command the game doesn't understand.

With this world.txt

room;Workshop;Half-built clocks tick on every shelf.
room;Hallway;A long hallway. The grandfather clock here has stopped.
room;Kitchen;A kettle sits on a cold stove.
exit;Workshop;north;Hallway
exit;Hallway;south;Workshop
exit;Hallway;east;Kitchen
exit;Kitchen;west;Hallway

and the commands go north, go up, go east and quit, the program prints:

== Workshop ==
Half-built clocks tick on every shelf.
Exits: north
> go north
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east
> go up
You can't go up from here.
> go east
== Kitchen ==
A kettle sits on a cold stove.
Exits: west
> quit
Goodbye!

Milestone 3: Things to carry

An adventure needs things to find. A line such as item;Kitchen;gear means that a gear lies in the Kitchen. Item names are single words.

  1. Give each room's dictionary the key "items", with an empty list when the room is created. For each item line, read_world appends the item to that room's list.
  2. When a room has items, show_room prints one more line after the exits: You see: gear, spoon, in the order of the list.
  3. The player carries an inventory, a list that starts empty, and three new commands use it:
    • take gear: when the gear is in the room, it moves from the room's list to the end of the inventory, and the game prints You take the gear. Otherwise it prints There is no gear here.
    • drop gear: when the player carries the gear, it moves from the inventory to the end of the room's list, with You drop the gear. Otherwise You don't have the gear.
    • inventory prints You carry: key, gear, in the order of the list, or You carry nothing.

With the world of the last milestone and three item lines at the end of it

item;Workshop;key
item;Kitchen;gear
item;Kitchen;spoon

and the commands take key, take gear, go north, go east, take gear, drop key, inventory, look and quit, the program prints:

== Workshop ==
Half-built clocks tick on every shelf.
Exits: north
You see: key
> take key
You take the key.
> take gear
There is no gear here.
> go north
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east
> go east
== Kitchen ==
A kettle sits on a cold stove.
Exits: west
You see: gear, spoon
> take gear
You take the gear.
> drop key
You drop the key.
> inventory
You carry: gear
> look
== Kitchen ==
A kettle sits on a cold stove.
Exits: west
You see: spoon, key
> quit
Goodbye!

Milestone 4: A locked door

Some ways are locked. A line such as lock;Attic;up;key means that the exit up from the Attic is locked, and that the key opens it. The exit itself has its own exit line, as before.

  1. Give each room's dictionary the key "locks", with an empty dictionary when the room is created. For each lock line, read_world adds the direction as a key, with the item that opens it as the value.
  2. When the player tries to go through a locked exit:
    • If they carry the item that opens it, the game prints You unlock the way up with the key., the lock is gone for good, and the player goes through as usual.
    • Otherwise the game prints The way up is locked. and the player stays where they are.

A locked exit is listed among the exits as usual: the player only finds out it's locked when they try it.

With this world.txt

room;Hallway;A long hallway. The grandfather clock here has stopped.
room;Attic;Dusty boxes stand under a round window.
room;Clock Tower;Huge wheels fill the tower. One gear is missing.
room;Workshop;Half-built clocks tick on every shelf.
exit;Hallway;up;Attic
exit;Hallway;south;Workshop
exit;Attic;down;Hallway
exit;Attic;up;Clock Tower
exit;Clock Tower;down;Attic
exit;Workshop;north;Hallway
item;Workshop;key
lock;Attic;up;key

and the commands go up, go up, go down, go south, take key, go north, go up, go up, go down, go up and quit, the program prints:

== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: up, south
> go up
== Attic ==
Dusty boxes stand under a round window.
Exits: down, up
> go up
The way up is locked.
> go down
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: up, south
> go south
== Workshop ==
Half-built clocks tick on every shelf.
Exits: north
You see: key
> take key
You take the key.
> go north
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: up, south
> go up
== Attic ==
Dusty boxes stand under a round window.
Exits: down, up
> go up
You unlock the way up with the key.
== Clock Tower ==
Huge wheels fill the tower. One gear is missing.
Exits: down
> go down
== Attic ==
Dusty boxes stand under a round window.
Exits: down, up
> go up
== Clock Tower ==
Huge wheels fill the tower. One gear is missing.
Exits: down
> quit
Goodbye!

The last go up passes without a word: the lock was opened before.

Milestone 5: The goal

Last, the game gets a goal. A line such as goal;Clock Tower;gear;You fit the gear into place, and the great clock starts ticking again. means: the player wins by being in the Clock Tower with the gear in their inventory, and then the game prints that message.

  1. For a goal line, read_world gives that room's dictionary the key "goal", with a tuple of the item and the message as its value: ("gear", "You fit the gear ..."). Rooms without a goal don't get the key at all.
  2. The game counts the player's moves: each go that takes the player to another room is one move. A way that is closed, or locked, is no move.
  3. After every command, the game checks whether the player has won. If so, it prints the goal's message and then You won in 5 moves. (with the number of moves; for exactly one move, You won in 1 move.), and the game ends. It doesn't matter how the player got there: walking in with the item, or picking it up in that room.

A world without a goal line is played as before, until quit.

With the world and the commands at the top of this page, the program prints:

== Workshop ==
Half-built clocks tick on every shelf.
Exits: north
You see: key
> take key
You take the key.
> go north
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east, up
> go east
== Kitchen ==
A kettle sits on a cold stove.
Exits: west
You see: gear
> take gear
You take the gear.
> go west
== Hallway ==
A long hallway. The grandfather clock here has stopped.
Exits: south, east, up
> go up
== Attic ==
Dusty boxes stand under a round window.
Exits: down, up
You see: oil
> go up
You unlock the way up with the key.
== Clock Tower ==
Huge wheels fill the tower. One gear is missing.
Exits: down
You fit the gear into place, and the great clock starts ticking again.
You won in 5 moves.