Defining the Data for our Game World |
In order to learn some more about forms, let's create a some forms that create the data for our game world. First of all, our game is going to have some objects in it that the player can pick up and use- Let's define those objects: |
(setf *objects* '(whiskey-bottle bucket frog chain))
Ok, now let's dissect this line an see what it means: Since a Lisp compiler always starts reading things in Code Mode and expects a form, the first symbol, setf, must be a command. In this case, the command sets a variable to a value: The variable is *objects* (Lispers like to put stars around the names for global variables as a convention) and the value we are setting it to is a list of the four objects. Now, since the list is data (i.e. we don't want the compiler to try and call a function called whiskey-bottle) we need to "flip" the compiler into Data Mode when reading the list. The single quote in front of the list is the command that tells the compiler to flip: |
You may be wondering why the command is called setf... I'm not sure why, actually, but you'll find that a lot of the commands in Lisp have quirky names, since Lisp is such an ancient language. This is actually somewhat useful, since the Lisp versions of common commands have all kind of elegant powers unique to Lisp and therefore the wacky names prevent confusing vocabulary when comparing command in Lisp to commands in other languages. The setf command, for instance, has all kinds of clever abilities that we won't even have a chance to touch on in this tutorial. Now that we've defined some objects in our world, let's ramp it up a step and define a map of the actual world itself. Here is a picture of what our world looks like: |
In this simple game, there will only be three different locations: A house with a living room and an attic, along with a garden. Let's define a new variable, called *map* that describes this mini world: |
(setf *map* '((living-room (you are in the living-room of a wizards house. there is a wizard snoring loudly on the couch.) (west door garden) (upstairs stairway attic)) (garden (you are in a beautiful garden. there is a well in front of you.) (east door living-room)) (attic (you are in the attic of the wizards house. there is a giant welding torch in the corner.) (downstairs stairway living-room))))
This map contains everything important that we'd like to know about our three locations: a unique name for the location (i.e. house, garden, and attic) a short description of what we can see from there (stored in its own list within the bigger list) , plus the where and how of each path into/out of that place. Notice how information-rich this one variable is and how it describes all we need to know but not a thing more- Lispers love to create small, concise pieces of code that leave out any fat and are easy to understand just by looking at them. Now that we have a map and a bunch of objects, it makes sense to create another variable that says where each of these object is on the map: |
(setf *object-locations* '((whiskey-bottle living-room) (bucket living-room) (chain garden) (frog garden))) |
Here we have associated each object with a location. Lists such as this are, not surprisingly, called "association lists" in Lisp. An association list is simply a list of lists where the first item in each inside list is a "key" symbol that is associated with a bunch of other data. Our *map* variable was also an association list- The three keys in that case were living-room, garden, and attic. Now that we have defined our world and the objects in the world, the only thing left to do is describe the location of the player of the game: (setf *location* 'living-room) |