Lab 13: Interactive Fiction
Objectives
So this is the last lab. It's not graded and there's no due date. If you're reading this, you're likely finished with everything else and are either bored or just looking for something to do while waiting to get graded.
The goal, then, is to have a bit of fun, and hopefully learn something about using files and YAML.
Let's get to it!
Interactive Fiction
Before the advent of blazing fast, 256MB, 1.21 jigawatt video cards, adventure games didn't have fancy graphics and pre-rendered cut scenes. Us old farts would sit down in front of monochromatic monitors and play so-called "text adventure" games, where movement and actions were carried out via text commands, and lush textual descriptions were provided for the benefit of active imaginations.
Turns out some folks still find text adventures interesting, though they tend to be referred to as "interactive fiction" now. Wikipedia (who else?) has a good article on them.
The goal of this lab is to implement a very basic interface to an interactive fiction (IF) game. The game will support navigation between any number of "rooms", with the objective being to find the "exit" (though you can easily change this).
Instead of writing a program that implements a "hardcoded" game, however, you're going to write a program that loads the description for a set of rooms from a file (formatted in YAML), and therefore allows different games to be played depending on what files are loaded.
Our file format
Here are the contents of "hauntedhouse.yaml" -- a file describing a fairly small IF "map":
start: name: the start room description: an elegant chamber with a huge crystal chandelier exits: south: [zombie room, a greenish hue] east: [room of mice, a grayish writhing mass] zombie room: name: a room of zombies description: a group of freaky looking zombies heading your way. exits: north: [start, a bright passageway] room of mice: name: a room of mice description: at least a dozen huge, hairy, black rats! exits: west: [start, a bright passageway] east: [exit, a blinding light] exit: name: the exit!
The idea is that each first-level entry in the file (identified by keys in a hash named, in this example, "start", "zombie room", "room of mice", "exit") corresponds to a room, and each room itself consists of a hash of items that comprise the room's name, description, and exits. The exits are also represented as a hash of direction names (east, north, west, south) to arrays; the first element of the array being the key of the room in that direction, and the second element a description to be shown to the player.
Note that YAML allows keys, values, and array elements to be written without quotes, though after loading they can be accessed as strings.
Gameplay
The challenge is to go from the file format described above to a functioning game --- a session with our (fairly spartan) game is shown below:
$ ruby if.rb
What game file to load?
hauntedhouse.yaml
You are now in the start room.
Looking around, you see an elegant chamber with a huge crystal chandelier
There are 2 exits:
- To the south there lies a greenish hue
- To the east there lies a grayish writhing mass
Where would you like to head?
south
You are now in a room of zombies.
Looking around, you see a group of freaky looking zombies heading your way.
There are 1 exits:
- To the north there lies a bright passageway
Where would you like to head?
north
You are now in the start room.
Looking around, you see an elegant chamber with a huge crystal chandelier
There are 2 exits:
- To the south there lies a greenish hue
- To the east there lies a grayish writhing mass
Where would you like to head?
east
You are now in a room of mice.
Looking around, you see at least a dozen huge, hairy, black rats!
There are 2 exits:
- To the west there lies a bright passageway
- To the east there lies a blinding light
Where would you like to head?
east
You've reached the exit... congratulations!
Pretty nifty, huh?
Step 1: Load the file
Clearly, the first thing that needs to be done is to load the contents of the file into a form that is easily used within a Ruby program. Because we're using YAML as a file format, this is remarkably easy to do! The following bit of code we discussed in lecture loads the hash shown above into the rooms
variable:
rooms = {} File.open("hauntedhouse.yaml") do |f| rooms = YAML::load(f) end
Note that at this point,
rooms['start']['name']
⇒"the start room"
rooms['zombie room']['exits']['north'][0]
⇒"start"
rooms['zombie room']['exits']['north'][1]
⇒"a bright passageway"
You can also iterate over items -- e.g., you can get at all the exits from the "room of mice" by doing:
rooms['room of mice']['exits'].each do |dir, name_desc| # dir => "west", "east" # name_desc[0] => "start", "exit" # name_desc[1] => "a bright passageway", "a blinding light" end
After you do a git pull
in your repository, you'll find a data file ("hauntedhouse.yaml", described above) and some sample code in "if.rb".
Step 2: Take it away!
You've got your data loaded -- it's up to you now to implement a working game interface! Feel free to jazz it up a bit; our example above is a little boring. You can use random strings, for instance, as "lead-ins" to the various descriptions that get printed out.
Much more interesting than that would be to expand on the contents of the IF data file itself (and use that content in your program). Here are some ideas:
- Make the map much larger -- it's really not that challenging right now.
- Add different types of exits; you could, for instance, go "up" and "down" from a certain room to take you to different parts of a map.
- Add an additional hash to each room called "actions", which indicates actions that a player can execute in a given room (maybe there's a door to open, or something to break?).
- Add an additional hash to each room called "items", which consists of items that can be picked up by the player -- this would require the game to keep track of items (and remove them from rooms) as they are picked up, of course.
There are a lot of possibilities, really. If you come up with a particularly interesting map or game engine, we'd love for you to send it in for us to play through!
Enjoy.