Inform 7 Home Page / Documentation
§13.16. What are relations for?
It is easy to say what verbs are for: they are to express relations. But what are relations for?
Inform 7's focus on relations between objects is unusual as an approach to interactive fiction; the concept does not exist in most design systems, or rather, it does but is submerged. Traditional design systems do, after all, have the spatial relations of being inside, on top of, and so on. It could well be said that these are the only relationships that inanimate objects ever have. A stone can be on top of a table, and if so then that expresses their entire association.
This is because the stone, and the table, have no opinions, emotions, knowledge or memory. If the stone is taken away and then put back, nothing has changed. People, on the other hand, tend to remember having met each other before; they like being in some places, but not others; their behaviour depends on who, or what, is nearby. Being conscious, they have internal states, unlike the stone. Relations are a simple but powerful way to express and talk about such connections, and although they have numerous uses in physical contexts too, they are at their most powerful when helping to make the characters of interactive fiction come alive.
|Start of Chapter 13: Relations|
|Back to §13.15. Temporary relations|
|Onward to Chapter 14: Adaptive Text and Responses: §14.1. Tense and narrative viewpoint|
Murder on the Orient Express
The following example creates two new relations, and two new verbs, in order to set up a tangled web of intrigue.
The silver bullet exculpates the player. The pipe ash exculpates Holmes. The poison pen letter exculpates Lord Peter. The poison pen letter exculpates Miss Marple. [Poor Dalgliesh. I guess he did it.]
Given this, we can then set up elaborate rules:
And so on: "if Dalgliesh suspects someone who is exculpated by something carried by the player...", for instance, makes a fitting final example for this chapter. The description
expresses a complicated idea in very few words, and in such a way that a passer-by looking at the source text would immediately see what was meant.
The moral is that relations allow sophisticated patterns of behaviour to be created in a way that reads back naturally as English.
What Not To Wear
We start by borrowing some of the same ideas from the Bogart example, but we're also going to make a kind called "garment-element". This kind will include both garments (objects of clothing) and body parts (things that can be covered by clothing); using it allows us to restrict the way our underlying and overlying relations apply, which will make them a bit faster at run-time.
Underlying relates various garment-elements to various garment-elements with fast route-finding. The verb to underlie means the underlying relation. The verb to be under implies the underlying relation.
Here we've expanded on the previous ideas of 'uppermost' because it is possible for an upper layer to reveal what lies beneath: a tie, a clear plastic trenchcoat, an open-knit sweater, etc. We'll make such items transparent.
Before taking off something which underlies something which is worn by the player:
while the noun underlies something (called the impediment) which is worn by the player:
say "(first removing [the impediment])[command clarification break]";
silently try taking off the impediment;
if the noun underlies the impediment, stop the action.
Covering relates a garment-element (called A) to a garment-element (called B) when the number of steps via the overlying relation from A to B is greater than 0. The verb to cover means the covering relation.
Before wearing something when a garment which covers the noun is worn by the player:
while the player wears a garment (called the impediment) which covers the noun:
say "(first removing [the impediment])[command clarification break]";
silently try taking off the impediment;
if the player is wearing the impediment, stop the action.
Instead of looking under something which is worn by the player:
if something (called the underwear) underlies the noun, say "[We] [peek] at [the underwear]. Yup, still there.";
otherwise say "Just [us] in there."
Instead of taking inventory:
say "[if the player carries something][We]['re] carrying [a list of things carried by the player][else][We]['re] empty-handed[end if][if the player wears something]. [We] [are] wearing [a list of uppermost garments worn by the player][end if]."
Here we draw in the idea that different clothes go over different areas of the body, and that they should be in competition with each other only if both sets of clothes belong at the same level over the same body area.
Before wearing something:
let N be the layering depth of the noun;
repeat with item running through things worn by the player:
if the layering depth of the item is N and the item covers a body-part which is covered by the noun:
say "(first taking off [the item])[command clarification break]";
silently try taking off the item;
if the player wears the item, stop the action.
This may seem like overkill, but it allows us to create garments that cover different subsets of the body -- pants and shirt vs. a dress, for instance.
To decide what number is the layering depth of (chosen garment - a thing):
let N be 0;
if the chosen garment covers a body-part (called base):
let N be the number of steps via the overlying relation from the chosen garment to the base;
decide on N.
To help with modeling, we'll give everyone body parts, broken down according to their relevance to clothing:
If we wanted to allow gloves, we might put in hands as well; but this is enough for now.
And now we make some categories of clothing:
A garment is a kind of garment-element. A garment can be transparent. A pair of pants, a pair of underpants, a foundation garment, a pair of socks, a pair of shoes, a jacket, a hat, a dress, and a shirt are kinds of garment.
When play begins:
now every pair of socks overlies every pair of feet;
now every pair of shoes overlies every pair of socks;
now every pair of underpants overlies every seat;
now every pair of pants overlies every pair of underpants;
now every foundation garment overlies every torso;
now every jacket overlies every shirt;
now every jacket overlies every dress;
now every hat overlies every head;
now every dress overlies every pair of underpants;
now every dress overlies every foundation garment.
The player carries some capris, some jeans, a corset, a plunge bra, a thong, boy-shorts, black satin D'Orsay pumps, brown leather boots, a camisole, a cocktail dress, a bolero, a cashmere shrug, a sheer wrap, and a linen tunic.
The woolly socks are a pair of socks.
The D'Orsay pumps and the brown leather boots are pairs of shoes.
The thong and the boy-shorts are pairs of underpants.
The capris and the jeans are pairs of pants.
The tunic is a shirt.
The camisole, the corset, and the plunge bra are foundation garments.
The cocktail dress is a dress.
The bolero, the cashmere shrug, and the sheer wrap are jackets. The shrug and the wrap are transparent.
Mathematical view of relations
Inform uses the term "relation" in a broader sense than mathematics. Properly speaking, the term "relation" in its mathematical sense only applies to the case where the domain for the left and right objects are the same: for simplicity's sake, let us talk only about the case where they are.
In mathematics, the properties most often looked for in a relation are that it should be:
(a) Reflexive: A <=> A for every A. This is not especially useful for Inform, and seldom appears in practical examples.
(b) Symmetric: A <=> B if and only if B <=> A. Generally, Inform relations are not symmetric, but there are two important cases which are:
These are automatically symmetric, so that to assert one way round is to assert the other as well.
(c) Transitive: A <=> B and B <=> C means that A <=> C as well. Again, Inform relations are not generally transitive. In many relations, there can be long chains of things, each perhaps related to the one in front and the one behind, so that there is some indirect sense in which the two ends of the chain are connected to each other: but they are not related as such. For instance, a journey across the map might pass through ten rooms, each adjacent to the last and next, but the two ends would not themselves be adjacent. The concept we need is the "transitive closure" of the original relation, defined as the smallest transitive relation including the original. If R is a relation between "things", then the following:
is the transitive closure of R. In particular,
calculates the transitive closure of adjacency. Here, though, the way we normally understand "accessible from" suggests that it would be better to write:
which is reflexive as well as transitive. The usefulness of Inform's "next step via R from A to B" construction, in a wide variety of settings, reflects the importance of transitivity as an idea.
A relation which has all three properties of being reflexive, symmetric and transitive is called an "equivalence relation". (If all the map connections are two-way, then the accessibility relation above is symmetric and therefore a full equivalence relation: but if not, it may not be.) Inform has a special construction for making equivalence relations:
This language - "in groups" - relies on the standard theorem that every equivalence relation on a set naturally defines a partition of that set, and vice versa. The "groups" referred to are what are normally called "equivalence classes". (Inform does little with these equivalence classes: it might be interesting to do so, in effect forming quotient kinds.)
Graph-theory view of relations
One way to look at a relation is to regard it as a directed graph: that is, a collection of things ("vertices") with arrows drawn between them ("edges"). We write our items A, B, C, ... on a piece of paper: then, if A relates to B, we draw an arrow pointing from A to B, and so on. If we made this drawing for the adjacency relation, we would more or less have reconstructed the map (or at least a simplified one which does not care about precise directions, like the famous diagram of the London Underground). But the drawing can be made for any relation. If we define:
then, in the corresponding graph, each "vertex" will have at most one arrow leading away from it - though there could be many (or none) leading towards. Conversely, a one-to-various relation produces a graph where each vertex has at most one arrow coming in. A one-to-one relation means that the picture consists of some vertices on their own, with no arrows, a few perhaps with looped arrows leading from and to themselves, and then a collection of pairs joined by arrows. On the other hand, a various-to-various relation is just a free-for-all, with no restrictions on the arrows. The relations:
always have the property of working both ways round, and these are easiest to visualise by forgetting the direction of the arrows, so that they just become lines joining the vertices.
Inform uses a different algorithm for finding routes ("the next step via R from A to B") in each of these cases, and internally it stores relations in different formats in the different cases, because it makes a big difference to the efficiency of Inform to minimise the storage required for a relation and the time taken to explore it.
All the cases are benign except for "various to various" - the most useful - and for its closely related symmetrical version, "relates... to each other". Inform cannot afford to assume that the relation will be "sparse" (that is: that no vertex will have more than a certain number of arrows, or that the total number of arrows will be small), because it has no idea how the arrows will come and go during play. It therefore uses 1 bit of storage for each pair of objects. This sounds harmless, but if there are 200 rooms, there are 40,000 pairs of rooms, which means a 5000-byte allocation of storage (plus a handful of bytes as overhead). Gratuitous various-to-various relations are therefore not a good idea.
There is a standard algorithm for calculating shortest paths through a directed graph, but Inform does not always use it, because there is not always memory to store the required matrix of partial results. Inform's slow method, likely to be used on the Z-machine, requires a storage overhead which is equal to the number of vertices, not the square of that number, but the worst-case running time can be bad: if there are N vertices, and the diameter of graph (the longest distance between vertices) is D, then the running time is proportional to D times N. The worst case in finding routes from A to B is when almost every vertex can reach B, some across long trails, but A cannot. In the case of finding routes across the game's map, this must be multiplied further by the number of possible directions - usually 16.
This does not sound too awful, but if one is trying to find (say) "the most distant room from A", that means a further loop and now the running time will be D times N squared. Extension writers will need to be careful of this kind of thing: it is easy to write highly cool prototypes which work terribly slowly on larger, more realistic maps.