In a series of posts, I’ll be writing about a gaming system I’ve been using to teach children writing skills but have also found helps testers with analysis and thinking skills. This particular gaming system is called Inform 7 and it’s used to program interactive fiction games, which used to be called “text adventures” back in the day. Inform 7 offers some unique challenges to thinking, writing, and programming such that I’ve found it to be an excellent system to explore with. Given that Inform 7 is used to create games that present puzzles to be solved, it’s been instructive for me to treat Inform 7 itself as a puzzle to be solved.
You can view the Inform 7 web site for more information and you can download the Inform game creation interface for Linux, MacOS, and Windows. I will be writing all of this against the latest Inform 7 version, designated 6L02, which was released in May of 2014.
So what is Inform 7 and why am I writing about it? In line with much of my professional work, Inform 7 provides a Domain-Specific Language (DSL). Such languages are designed to work within a particular domain with a certain amount of conciseness and expressiveness because they focus on the particulars of that domain. The domain of Inform is creating text-based interactive fiction or, as I’ll usually refer to it, textual IF. These are the old school text adventures like Colossal Cave, Zork, Planetfall, and so on. These types of games are distinct from graphical IF adventure games in that the primary medium of input and output is text.
As a note of relevancy as well as being fair, while I say these are “old school” games, there is a vibrant and active community out there. This community continues to create new textual IF games, build new engines to support the creation of these games as well as interpreters to play them. Check out the Interactive Fiction Database for a huge catalog of games. You can also check out one of the most common places for discussing such games, as well as the tools to create them, at the Interactive Fiction Community Forum. There’s also a Text Adventure Documentary that you can check out.
My goal here isn’t really to teach you Inform necessarily. Inform comes with two large manuals (Writing with Inform and The Inform Recipe Book) that will do that. Instead my goal is to teach exploration of a system that I believe helps testers and developers think more deeply about their own projects. That said, even if you are not a tester or developer, I do hope these posts will help people who want to learn Inform 7 just for its own sake. It’s a fun system to play around with and I hope a lot of that comes through.
A Bit About Inform
Inform is unique in a couple of ways. The one that becomes most obvious is that it utilizes natural language programming. (Not just natural language parsing; natural language programming.) Inform is a system where a constrained form of natural English language is the code. Beyond that, Inform is also rule-focused, event-driven, and object-based. But what does all that mean?
What you create in natural language in Inform 7 translates down into classes and objects. Yet how you talk about the interactions of those objects is all in rules. The event-driven part comes in because those objects are declarative. You define what objects are, provide some properties for those objects, and state the relationships of objects to one another. But the objects don’t say how they behave. How objects behave comes into play when certain rules are executed to manipulate those objects based on certain circumstances. Rules are executed when a given action (event) is processed. The interesting part is that you don’t know which events are going to be fired or in what order. After all, that depends on the player who is playing your game.
A Few Technical Details
Inform 7 translates down to Inform 6, the latter of which was the precursor to Inform 7 and is a much more traditional object-based programming language. The Inform 6 code is then in turn converted into a form of “assembly” or “bytecode” that is read by one of two virtual machines: the z-machine or Glulx. This is very similar to how languages like Java, Groovy, Scala, and Clojure operate in the context of a Java Virtual Machine (JVM) or how C# and VB.NET operate in the context of the .NET Common Language Runtime (CLR).
What all this means is that Inform 7 presents some interesting challenges to learning. You have to understand you are using a programming language, but one with a natural language gloss. You are declaring various types of objects but are not declaring the interactions between them. Rather, you are stating rules that will take place in the context of actions that won’t happen until runtime.
Starting an Inform Project
After you have downloaded and installed Inform 7, follow these steps to get a new project going:
- Start the Inform application.
- (Windows) Click the “Start a new project…” button on the introductory screen.
- (Mac) Click the “Project” item under “Create New” on the introductory screen.
- Choose a directory where you want the project to be stored.
- For the name of the project, enter Learning Inform.
- Enter your name as the author. (For Windows; on Mac, your user name will be used).
- Click the “Start” button (for Windows) or the “Create Project” button (For Mac).
The two pane interface will start up. You’ll note that each pane has a set of tabs along the top (if on Windows) or along the side (if on Mac). I recommend checking into the Inform manuals for more details; I’m likely going use a very small subset of all the available features in these posts and I certainly won’t be presenting them systematically. In the left pane, within the Source tab, you’ll end up with source text that looks like this:
"Learning Inform" by Jeff Nyman
That’s just a bit of heading text that Inform uses to indicate exactly what it says: the title and author of the game. In any code examples I present, I’ll generally avoid showing the heading text every time, but don’t take it out since it is required.
Incidentally, I called the above “source text.” What does that actually mean? Well, given that one goal of Inform is to reach writers, you could think of “source text” as the words you would write in a novel or screenplay. From that perspective, you could then think of Inform as the word processor into which you are typing those words. Another goal of Inform is to reach programmers and, from a programming standpoint, the source text is your source code and the Inform interface is your IDE.
A Brief Digression
This emphasis on appealing to writers and programmers with a common format has an interesting parallel in the software development world, with the increasing use of tools like Cucumber, SpecFlow, jBehave, and so on for providing a structured language for discussing application features.
In most cases, that structured language is not just there to allow for expressive collaboration but the tooling around that language allows for specific language phrases to be “matched” and, when said matching occurs, logic is used to delegate down to various other tools, like browser automation libraries. What this does is create a form of executable specification and, in many ways, that is exactly what you produce with Inform 7: an executable specification of your story.
Starting a Game
Designing starts with specifying the world model. That’s a fancy way of saying that you state what locations exist in your world, what things exist in those locations, and how those things are situated relative to each other. Inform requires the source text to contain at least one statement that specifies a starting location for the player. What that means is that you have to create a room. (Everything in Inform is considered a “room”; even outdoor locations. It’s a holdover from the old days.) So add the following statement to the source text:
"Learning Inform" by Jeff Nyman The Learning Lab is a room. "This is the Learning Lab."
Note that the Mac version will likely have a bit of code in place already (probably something like
Example Location is a room.). Simply change “Example Location” to “The Learning Lab” and add the rest as shown above.
To see that this actually does something, click the “Go!” button. You can also press F5 (Windows) or Command+R (Mac). That’s essentially calling the NI compiler, where NI means Natural Inform. This compiles the Inform 7 code into Inform 6 code. A built-in interpreter will then fire up and start the game in the Story panel in the right pane. This is where you can play the game just as one of your players would.
Given that you only have one room and no other objects, there’s really not a whole lot you can do to play the game at the moment. Still: you should be excited by the fact that a purely natural language bit of code actually does generate a working game.
What’s Going On?
If you are one of those that likes to peek behind the curtain and wants to see what happened during the compile process, click on the Results tab and then on the Console button. The output on that screen is essentially the two-phase compiler output. Phase one is Inform 7 translating your source text (from a file called story.ni) into a file called auto.inf. Phase two is the compilation of auto.inf into a file called output.ulx, which is a playable game file.
The .ulx extension indicates that this is a Glulx-style game, meaning it needs to be played on the Glulx virtual machine. If you look in the Settings panel, you’ll see an option for Story File Format, which can be Z-Code or Glulx. Were you to change the format to Z-Code, then the final game file would be called output.z8 and would play on the z-machine interpreter. The good news is that when starting out, none of this has to matter to you at all.
An Inform 7 Game Looks Like…
You get this output on the Story tab when you start the game:
Learning Inform An Interactive Fiction by Jeff Nyman Release 1 / Serial number 140618 / Inform 7 build 6L02 (I6/v6.33 lib 6/12N) SD Learning Lab This is the Learning Lab. >
You get the standard banner that Inform provides for any game. You’ll see the text “Learning Lab”, which is Inform telling the player where they currently are. The bit of text provided in the source text after the statement about the Learning Lab serves as a description of the room so that the player gets some idea of the location. (Clearly you would be a bit more expressive in a real game!) The “>” character is the prompt that textual IF games tend to present, indicating that they are waiting for input from the player.
All of the interaction with a textual IF game takes place in the form of text input to the game and text output from the game. A large part of the authoring process, beyond actually making the mechanics of the game work, is presenting an interesting textual description to the player.
Your Source Text Is Code
So the game apparently works. But why does the game work? What does the sentence in the source text actually do? And, for that matter, how does a natural language statement like that work as code?
The statement tells Inform that a room exists and that room is to be called “Learning Lab”. Since this is the only location mentioned in the source text, Inform treats this as the starting location for the player. From a programmatic standpoint, Inform recognizes a “room” as a kind. That’s essentially a class in object-oriented programming languages. So what I’ve done with the above line is create an instance of a room class that is called “Learning Lab”.
The behind the scenes code is not very helpful to look at, but if you are curious, here is what the natural language statement becomes:
Constant IK1_First = I123_learning_lab; Object I123_learning_lab "" class K1_room with short_name BC_119 with description BC_120 with vector 0 with room_index -1 with list_together 0 has mark_as_room with IK1_Count 0 with IK1_Link nothing with KD_Count 1 with name 'learning' 'lab' 'rooms//p' with plural BC_121 with article BC_122 ;
If you come from a programming background, understand that object names in Inform can have spaces to allow for expressiveness. So “Learning Lab” is allowed in Inform 7 code which the becomes a more traditional object name (“learning_lab”). As far as the above object, you can see that a constant for the first room is set up (IK1_First). That points to an “Object” (I23_learning_lab) and if you look in that object, you’ll see that it is a “class” (K1_room) and it has a property called “mark_as_room”. This object also has a property called “description”, which refers to BC_120. If you really want to dig into the weeds, BC_120 is:
Array BC_120 --> PACKED_TEXT_STORAGE TX_PS_35;
This refers to a constant TX_PS_35 which is:
Constant TX_PS_35 = "This is the Learning Lab.";
All of this is Inform 6 code, by the way. For what are probably obvious reasons, I don’t plan on showing much behind the scenes code like that, particularly since the whole point of the natural language abstraction layer is that you don’t have to worry about the low-level code. But every once in awhile it can be instructive.
Now that we have a starting location, and our first object, let’s add a few more objects to our source text:
The Learning Lab is a room. "This is the Learning Lab." The Office is a room. "This is the Office." It is east of the Learning Lab. A shredder is in the Office.
By the way, I do recommend actually typing this stuff in rather than just copy+pasting. Typing code in builds up the mental memory of how you structure code in any language. Copy+pasting shortcuts that process.
With the new text added, feel free to click “Go” (or F5 on Windows, Command+R on Mac) and try out the game. You’ll now find that you can move from the Learning Lab to the Office. Type the command
east, which you can shorten to
e if you want. You can also interact with the shredder. Try
examine shredder and
take shredder. After doing the latter, you can type
inventory (or shorten that to
inv or even just
i) and you’ll see that you are now the proud carrier of a shredder.
So now I’ve got a statement that says there is a room called Office. I’ve further asserted that this Office room is east of the Learning Lab room. In other words, I’ve stated a relation between two objects in the game. Finally, I state that a shredder is in the Office. Once again, I’ve asserted a relation between objects. Relations are a key organizing principle of Inform but also one you’ll find you use consistently without having to worry about it.
If you have a programming background and want more details, you’ll know that object-based languages tend to have two relation types, usually called “is-a” and “has-a”. A “has-a” relation means that one object belongs to or is part of another object; this is usually referred to as composition. An “is-a” relation is where one object is a type of another object; this is usually referred to as inheritance. So it’s the difference between a Silverado is a Vehicle and has a Engine.
Inform relations are a bit different. Behind the scenes, they essentially consist of adding array properites to objects. Do not get mired in the details, but if you are curious, here’s what exists behind the scenes in our current source:
Array Map_Storage --> 0 0 0 0 0 0 I124_office 0 0 0 0 0 ! Exits from: I123_learning_lab 0 0 0 0 0 0 0 I123_learning_lab 0 0 0 0 ! Exits from: I124_office ;
Were you to dig in a lot deeper, you would find that in Inform directions (like “east”) do not actually connect rooms. Rather, there is a relation that exists that is called “mapped east of”. This is handled, behind the scenes, by what Inform calls an adjacency relation.
Let’s focus for a moment on the shredder. You’ll notice that I don’t say what it is. I just say that it is. So Inform knows to make the Learning Lab and the Office room objects because I state they are rooms. What does Inform do with the shredder, where I don’t state anything at all? Inform treats the shredder as a very generic kind called “thing”.
Let’s look behind the scenes again, this time at the object that represents the shredder:
Object -> I125_shredder "" class K2_thing with short_name BC_127 with vector 0 with list_together 0 has mark_as_thing with IK2_Count 1 with IK2_Link nothing with KD_Count 2 with name 'shredder' 'things//p' with action_bitmap 0 0 0 0 0 with description BC_128 with initial BC_129 with plural BC_130 with article BC_131 ;
Notice that the shredder is a class of K2_thing. Notice also that the shredder has a property of “mark_as_thing”.
A “thing” is pretty generic in Inform’s world model and Inform doesn’t really know much of what to do with such a generic thing. For example, can you set something on top of it? What about inside of it? Can you close it? Lock it? Eat it? Well, to Inform: no. However, you can have more specific kinds of thing that do have or allow those aspects. For example, let’s say I want an object in the Office that’s a container. Add this to the source text:
The Learning Lab is a room. The Office is a room. "This is the Office." It is east of the Learning Lab. A shredder is in the Office. A wastebasket is a container in the Office.
You could also create an object that can support (as opposed to contain) other objects. Add this:
The Learning Lab is a room. The Office is a room. "This is the Office." It is east of the Learning Lab. A shredder is in the Office. A wastebasket is a container in the Office. A desk is a supporter in the Office.
Here I’ve made statements that say the wastebasket and the desk are particular kinds of object. In game terms, this means I could put things in the wastebasket or on the desk, neither of which I could do with the shredder.
Try it out. Play the game and try these commands:
take the shredder
put the shredder in the wastebasket
put the shredder on the desk
You’ll notice that even though you haven’t written anything about how to take objects or put objects in or on other objects, Inform is handling that just fine. You might also notice with the last command that Inform realized you needed to be holding the shredder before you could put it on the desk and thus took the shredder first.
All of this automatic object handling is due to a library called Standard Rules that gets compiled along with your game. That library contains what I would call a Vanilla Reality World Model. The Standard Rules library is what contains the definitions of the basic kinds that you’ve been using (room, thing, container, etc), some common actions (taking, putting things on, etc) and rules that provide a basic sort of reality: things can’t be put in themselves, you can’t drop something you aren’t holding, you can’t pick up your own self, and so forth.
So, again, the reason the above commands work at all is due to the Standard Rules providing actions and default responses to those actions. Those actions and default actions are predicated entirely upon the kind with which the actions take place. For example, try these commands:
put the shredder on the wastebasket
put the shredder in the desk
open the shredder
get into the shredder
By default Inform does not allow these actions with the shredder because of the shredder’s own kind or the kind of other objects you are using the shredder to interact with. The wastebasket is not a supporter so it can’t have things put on it. (By default, anyway.) Likewise, the desk is not a container and so things can’t be put in it. The shredder has not been said to be “openable” thus Inform assumes it can’t be opened nor is it an enterable container so Inform assumes you can’t get into it. All of this can be modified by your own source text, but what you are seeing now is what you get out of the box. Try a few more commands and observe the effects:
take the desk
take the wastebasket
open the wastebasket
Notice that the desk can’t be taken. This is because Inform assumes that supporters will tend to be fixed in place. You can change that, but what you see is what you get by default. You can, however, take containers like the wastebasket because containers are assumed to be portable. Yet even though the wastebasket is a container and thus has an interior space, Inform doesn’t automatically treat a container as something that can be opened or closed.
Statements About the World
Notice how all of the statements in the source text are talking about kinds related to each other. With the exception of the shredder statement, these are very explicit statements. Why explicit? Because they state what they are. The Learning Lab is a room. The wastebasket is a container. I could have even made the shredder more explicit like this:
The shredder is a thing in the Office.
I didn’t do that because the shredder — and any other object — is implicitly a thing unless you tell Inform otherwise. However, it is possible to make the other statements implicit in your text descriptions and Inform will figure out what kinds of objects you want. To try this out, change your source text so that it looks like this:
The Learning Lab is a room. "This is the Learning Lab." East of the Learning Lab is an Office. A desk is in the Office. A shredder is on the desk. A wastebasket is in the Office. A piece of paper is in the wastebasket.
Notice a few things here.
- I never explicitly say that the Office is a room.
- I never explicitly say the desk is a supporter.
- I never explicitly say the wastebasket is a container.
However, Inform is able to deduce all of those aspects. To prove that, compile the game and try out the previous commands. You’ll find they all work just the same. Why does this work, though?
- I have stated that the Office is east of the Learning Lab. This implicitly makes Office a room.
- I have stated that the piece of paper is in the wastebasket. This implicitly makes the wastebasket a container.
- I have stated that the shredder is on the desk. This implicitly makes the desk a supporter.
Incidentally, you’ll be able to see that Inform crafts its descriptions to the player based on how the world model is set up. For example, if you play the current game and type
east you’ll see Inform describes the Office this way:
Office You can see a desk (on which is a shredder) and a wastebasket (in which is a piece of paper) here. >
When Inform compiles your game it essentially builds up a list of all the nouns or noun phrases that you mention in your text. This focus on noun phrases is why you can have names for objects that have multiple words, such as a “piece of paper”. Those nouns that are found in your source are then instantiated as particular instances of kinds. Those instances are then placed into the world as your source describes them (in containers, on supporters, etc) and then, finally, the nouns are then constructed as part of a description, as in “a desk (on which is a shredder)”.
All of this is why Inform can decide to print just “You can a wastebasket here” if the wastebasket is empty or “You can see a wastebasket (in which is a piece of paper) here.” How Inform crafts and prints out descriptions is actually a very involved topic and one I won’t tackle now.
Inform Tip! Descriptions to Inform are anything that provides a way to unambiguously talk about one or more objects. As such, descriptions are critical to Inform because it’s not only how Inform builds up its notion of what the world looks like but also how that world is presented to the player.
Source Text Conventions
One thing you should have taken away from the source variations I’ve shown you is that, like many programming languages, Inform lets you word your constructs in different ways. It’s up to you to pick an approach that you find consistent and workable. For example, going with the latest example, some people would not like that you can only tell what the wastebasket and desk actually are by looking at other objects. Yet other people prefer that approach, feeling that it makes the source more expressive.
Another example in this context goes back to when the source text stated where the Office was relative to the Learning Lab. Notice how I initially stated the relation like this:
It is east of the Learning Lab.
I breezed right by that earlier, not even explaining why it worked. Here Inform knew that “it” referred to the last object talked about in the source text. So that tells you Inform is understanding your source text via context, just as a traditional language would. A traditional programming language would perhaps use “this” or “self” in the above case of referring to “the current object.”
Note that I could have originally been more explicit with this statement about the Office:
The Office is east of the Learning Lab.
And, of course, you see with the latest example I had yet a third way to word it (“East of the Learning Lab is an Office”). Again, you have to decide what you prefer.
Yet another example comes in with the description text that I originally provided to the Learning Lab. I could have been more explicit about what that text was, like this:
The Learning Lab is a room. The description of the Learning Lab is "This is the Learning Lab".
By convention, Inform knows that if quoted text appears after a room statement, that quoted text should be treated as the description. But here you see that you can be more specific. People prefer different approaches for different reasons.
I don’t want to cover every aspect of Inform’s flexibility here; rather I want to call out that this flexibility is both a good and bad thing. It means that various authors will have their own conventions they prefer and thus you can look at the source text of different people and not realize that one construct you are looking at is simply a differently worded way of saying the same thing you saw in someone else’s text.
This kind of confusion happen a lot with programming languages that have numerous idioms. Consider Ruby, for example. This:
if file.eof? puts 'Reached end of file' end
is the same as this
puts 'Reached end of file' if file.eof?
which is the same as this
file.eof? && puts 'Reached end of file'
The situation of different code idioms expressing the same logic can be compounded by Inform which uses what appears to be full natural language. In reality, of course, Inform does not understand the full range of natural language. Rather, it uses a constrained form of natural language. However, that language can easily lead you into the trap of wording something as “good English allows”, without considering what Inform actually accepts.
I should also note that just as with any programming language, Inform does have certain conventions of how you should write your source text. Going into great detail of every nuance will probably not be enlightening but all you have to know to get started are these few things:
- Full statements (sentences) should end with a period.
- You’ll generally have a line break between statements.
- Multiple statements can be placed on the same line as long as each has a period.
- You can also put a paragraph break between statements.
The source text we’ve created together here has shown each of those aspects.
Isn’t Inform 7 Cool?!
This was a gentle start to Inform. I hope you find this tool and language as interesting I do. Even if games aren’t your thing or even if games are your thing but text games aren’t, I still think there’s a lot of mental exercise you can get out of Inform. The fact that you have to construct a game in sentences that read like natural language should be intriguing. To testers and developers, this should bring to mind the use of tools like Cucumber, SpecFlow, and others, wherein you specify requirements and tests as natural language that delegates down to code.
Even the very act of learning the idioms of Inform is interesting, at least to me. Inform is actually a hard system to document well simply because it is hard not to forward and backward reference a lot as you describe it to others. Learning to document Inform well is good practice for making a complex system understandable. In any event, expect more posts in this category in the days to come.