Mapping and solving example

Here’s a more detailed example of how to use IFM, using the example game Ruins to produce a full IFM map containing items and game-solving tasks.

Ruins originally existed only in snippets throughout Graham Nelson’s Inform Designer’s Manual until Roger Firth produced a playable version of it. It serves as a good demo of IFM capabilities, since it doesn’t give away any secrets from a “real” game. The source code for Ruins can be found bundled with the Inform 6 sources.

Mapping the game

OK, let’s go. First, let’s set the title for the map, which gets printed out (for example) at the top of each PostScript output page:

title "Ruins";

On starting the game, we see this:

Days of searching, days of thirsty hacking through the briars of the
forest, but at last your patience was rewarded. A discovery!

RUINS
An Interactive Worked Example
Copyright (c) 1995 by Graham Nelson.
Revisited 1998 by Roger Firth.
Release 2 / Serial number 981117 / Inform v6.31 Library 6/11 S

Dark Forest
In this tiny clearing, the pine-needle carpet is broken by stone-cut steps
leading down into the darkness. Dark olive trees crowd in on all sides, the
air steams with warm recent rain, midges hang in the air.

A speckled mushroom grows out of the sodden earth, on a long stalk.

Ooh, that mushroom looks interesting. Let’s map out what we have so far:

room "Dark Forest" tag Dark_Forest;
item "speckled mushroom" tag mushroom;

Let’s have a closer look at that mushroom:

>GET SPECKLED MUSHROOM
You stoop to pick the mushroom, neatly cleaving its thin stalk. As you
straighten up, you notice what looks like a snake in the grass.

You hear the distant drone of an aeroplane.

>EXAMINE SNAKE
A menacing, almost cartoon-like statuette of a pygmy spirit with an
enormous snake around its neck.

The plane is much louder, and seems to be flying very low. Terrified birds
rise in screeching flocks.

>GET STATUETTE
Taken.

You involuntarily crouch as the plane flies directly overhead, seemingly
only inches above the treetops. With a loud thump, something drops heavily
to the ground.

>LOOK

Dark Forest
In this tiny clearing, the pine-needle carpet is broken by stone-cut steps
leading down into the darkness. Dark olive trees crowd in on all sides, the
air steams with warm recent rain, midges hang in the air.

Your packing case rests here, ready for you to hold any important cultural
finds you might make, for shipping back to civilisation.

The roar dies away; calm returns to the forest.

We’ve found a statuette that was hidden until we picked the mushroom:

item "statuette" tag statue hidden need mushroom;

And a packing crate just fell out of the sky! Looks like that was going to happen regardless, so nothing to do, map-wise. Let’s continue exploring:

>D

Square Chamber
A sunken, gloomy stone chamber, ten yards across, whose floor is covered
with fine sandy dust. A shaft of sunlight cuts in from the steps above,
giving the chamber a diffuse light, but in the shadows low lintelled
doorways to east and south lead into the deeper darkness of the Temple.

Carved inscriptions crowd the walls and ceiling.

We went down to get here, and have to decide on a compass direction to represent this on the map; let’s choose south. This might clash with other rooms later, but we can always come back and change it if needed.

We can also see some exits to other rooms, and can indicate those too, for later reference:

room "Square Chamber" tag Chamber dir s go down exit s e;
item "carvings";

OK, let’s have a bit of a look around.

>EXAMINE INSCRIPTIONS
The carvings cut deep into the rocks from which the chamber is built,
forming swirling sinuous patterns.

>EXAMINE MUSHROOM
The mushroom is capped with blotches, and you aren't at all sure it's not a
toadstool.

>EXAMINE SUNLIGHT
The shaft of sunlight glimmers motes of dust in the air, making it seem
almost solid.

Hmm... mushroom, sunlight. Sunlight, mushroom. Hey, let’s do it!

>PUT MUSHROOM IN SUNLIGHT
You drop the mushroom on the floor, in the glare of the shaft of sunlight.
It bubbles obscenely, distends and then bursts into a hundred tiny insects
which run for the darkness in every direction, leaving strange trails in
the sandy floor. No trace of fungus remain.

Well, that was unexpected. Now what?

>EXAMINE TRAILS
The insect trails seem to resemble one particular group of carvings on the
wall.

>EXAMINE CARVINGS
You stare at a group of carvings in the middle of one wall, uncannily
resembling the insects' trail left in the sand, and feel your hand reaching
out in that direction.

>PRESS CARVINGS
The carvings slide inwards, revealing a small cavity.

>SEARCH CAVITY
In the cavity among the carvings is a huge iron key.

>GET IRON KEY
Taken.

Aha! A key. I predict there’ll be at least one door in this game. But I hope we didn’t need that mushroom any more...

Recording what we just did:

task "Put mushroom in sunlight" need mushroom lose it;
task "Press carvings" after last;
item "iron key" tag key hidden after last;

Let’s explore a bit more:

>S

Stooped Corridor
A low, square-cut corridor, running north to south, stooping over you.
Patches of moss emit a faint green fluorescent glow, just enough that you
can see your surroundings.
The passage is barred by a massive door of yellow stone.

>EXAMINE MOSS
The moss grows in rough clumps, surprisingly thick in places. Is that a
hint of red hidden among all the greenery?

>SEARCH MOSS
Something rolls from the moss onto the ground.

>LOOK

Stooped Corridor
A low, square-cut corridor, running north to south, stooping over you.
Patches of moss emit a faint green fluorescent glow, just enough that you
can see your surroundings.

The passage is barred by a massive door of yellow stone.

You can also see a blood-red ruby here.

>GET BLOOD-RED RUBY
Taken.

Haha, more not-very-well-hidden goodies. And look—a door! What a surprise. Let’s do some mapping:

room "Stooped Corridor" dir s;
item "moss";
task "Search moss";
item "blood-red ruby" tag ruby hidden after last;

OK, let’s use that key!

>UNLOCK DOOR WITH KEY
You unlock the stone door.

>OPEN DOOR
You open the stone door.

>S

Lofty Shrine
For an underground chamber, the Shrine is remarkably high, though its upper
half is hazy and difficult to see clearly. The craggy walls are polished
natural rock, in which tiny flecks of quartz catch the light of the
flickering candle.

The massive yellow stone door is open.

A great stone slab of a table dominates the Shrine.

On the slab altar is a flickering candle.

Behind the slab, a mummified priest stands waiting, barely alive at best,
impossibly venerable.

How atmospheric. Continuing with mapping:

task "Unlock door with key" need key;
task "Open door" after last;

room "Lofty Shrine" dir s after last;
item "stone slab";
item "mummified priest";

Let’s see what we have here:

>EXAMINE SLAB
It's big enough to lie on, though in the circumstances that might prove to
be a A Really Bad Idea.

>EXAMINE PRIEST
He is dessicated and hangs together only by will-power. Though his first
language is presumably local Mayan, you have the curious instinct that he
will understand your speech.

Hmm... let’s press him for information, then:

>ASK PRIEST ABOUT RUBY
"That is one of my people's sacred relics."

>ASK PRIEST ABOUT SLAB
"The King (life! propserity! happiness!) is buried deep under this Shrine,
where you will never go."

>ASK PRIEST ABOUT KEY
"That has been lost for generations. My gratitude to anyone who returns it
will be overwhelming."

OK, er, let’s give it back:

>PUT KEY ON SLAB
His eyes dimly agleam with gratitude, the priest takes the key and conceals
it among his rags. Then, lifting the candle, he carefully detaches a large
lump of the mottled wax, and gives it to you.

>EXAMINE WAX
On closer examination, the lump appears to be an old honeycomb.

Looks like it might be worth something. Time for a bit of mapping:

task "Put key on slab" need key lose it give wax;
item "wax" tag wax hidden;

Right, let’s go back and try another direction we haven’t been yet:

>N

Stooped Corridor

The massive yellow stone door is open.

>N

Square Chamber

Carved inscriptions crowd the walls and ceiling.

Strange trails swirl on the sandy floor.

>E
As you move into the eastern shadows, you seem to glimpse the word SENE
scratched on the lintel, but before you can stop to inspect it more
closely, you find yourself in...

Darkness
The darkness of ages presses in on you, and you feel claustrophobic.

Somewhere, tiny claws are scuttling.

Crikey. Don’t like the sound of that.

>E

Darkness

Somewhere, tiny claws are scuttling.

The scuttling draws a little nearer, and your breathing grows load and
hoarse.

>S

Darkness
Somewhere, tiny claws are scuttling.

The perspiration of terror runs off your brow. The creatures are almost
here!

OK, this is bad. Think before acting. What did the word SENE mean? Hmm, maybe it’s two words...

>SE

Darkness

Somewhere, tiny claws are scuttling.

>NE
Sensing a slight draught you move in that direction, stumbling over
something lying on the ground in the dark. Almost inadvertently you grab it
before gratefully emerging into the gloomy chamber.

Square Chamber

Carved inscriptions crowd the walls and ceiling.

Strange trails swirl on the sandy floor.

Now that was close. But what have we grabbed?

>I
You are carrying:
  a silver bangle
  a lump of wax
  a blood-red ruby
  a pygmy statuette

Ooh, a silver bangle. Plus, we didn’t die!

Let’s map what we just did. We moved east from the Square Chamber into the Web of Darkness. There are essentially two of those rooms, corresponding to the two right directions to move in. Let’s give the Web rooms a Dark style to show they’re dark (we can define what Dark means, style-wise, later):

room "Web of Darkness" style Dark dir e from Chamber oneway;
item "scuttling claws";

room "Web of Darkness" style Dark dir se oneway;
item "scuttling claws";

The act of going northeast gave us a bangle (we tripped over it and picked it up). There are two ways of doing this: with an explicit movement task that puts you back in the Square Chamber, or a “dummy” task that hands you the bangle in this room without you doing anything (using cmd none). Let’s use the first method:

item "silver bangle" hidden tag bangle;
task "Stumble over bangle" give bangle cmd "NE" goto Chamber;

This second room is a one-way trip back to the Square Chamber. As it stands, that won’t be apparent on the map. Let’s add the connection in the most direct way:

link last to Chamber dir ne n w 2 oneway;

Well, there doesn’t seem to be anywhere else to go. Let’s get all this stuff stashed!

>U

Dark Forest

Your packing case rests here, ready for you to hold any important cultural
finds you might make, for shipping back to civilisation.

>PUT STATUETTE IN CASE
Safely packed away.

[Your score has just gone up by ten points.]

>PUT BANGLE IN CASE
Safely packed away.
[Your score has just gone up by twenty points.]

>PUT RUBY IN CASE
Safely packed away.

[Your score has just gone up by thirty points.]

>PUT WAX IN CASE
Safely packed away.

The case is full, and you're feeling really homesick. Now, how to get out
of here?

A deep throbbing noise can be heard.

[Your score has just gone up by forty points.]

OK, we’ve stashed all the loot we found. But what’s that noise?

>WAIT
Time passes.

A helicopter appears, hovering overhead.

>WAIT
Time passes.

The helicopter lowers a rope; you tie it around the packing case, which is
hauled up into the air, then a rope ladder comes dangling down. With one
last look around the clearing, you climb the ladder into the waiting craft.
Back to civilisation, and a decent pint of Brakspear's!

    *** You have won ***

In that game you scored 100 out of a possible 100, in 44 turns, earning you
the rank of Master Archaeologist.

Huzzah! We found all the “cultural finds” and just need to get them to the museum. [1]

Let’s add some tasks that record storing all the treasure. This happens in the starting room, so we’ll just go back and put them just after the declaration for that room. We could just have a single task that requires all the treasure together and gets the full 100 points, but let’s spell out the points for each one:

task "Put statuette in case" tag pack_statue need statue lose it score 10;
task "Put bangle in case" tag pack_bangle need bangle lose it score 20;
task "Put ruby in case" tag pack_ruby need ruby lose it score 30;
task "Put wax in case" tag pack_wax need wax lose it score 40;

After the treasure is stashed, we just waited for the helicopter and won the game:

task "Wait for helicopter" after pack_statue pack_bangle pack_ruby pack_wax cmd "WAIT" 2 finish;

The only thing remaining to do, map-wise, is to define the display style we’ve used for the dark rooms. Let’s just set the room background colour to be darker. Note that we could also define the Dark style by putting it in a file called Dark.ifm, and then putting that file in a directory which is searched by IFM. That way, many maps could use the same style definition. Here’s the definition:

room_colour = "gray70" in style Dark;

Putting all these IFM snippets together (and indenting in my preferred style) the completed map looks like this:

# IFM map of 'Ruins'

title "Ruins";

room "Dark Forest"                      tag Dark_Forest;
  item "speckled mushroom"              tag mushroom;
  item "statuette"                      tag statue hidden need mushroom;

  task "Put statuette in case"          tag pack_statue need statue lose it score 10;
  task "Put bangle in case"             tag pack_bangle need bangle lose it score 20;
  task "Put ruby in case"               tag pack_ruby need ruby lose it score 30;
  task "Put wax in case"                tag pack_wax need wax lose it score 40;

  task "Wait for helicopter"            after pack_statue pack_bangle pack_ruby pack_wax 
                                        cmd "WAIT" 2 finish;

room "Square Chamber"                   tag Chamber dir s go down exit s e;
  item "carvings";

  task "Put mushroom in sunlight"       need mushroom lose it;
  task "Press carvings"                 after last;

  item "iron key"                       tag key hidden after last;

room "Stooped Corridor"                 dir s;
  item "moss";

  task "Search moss";
  item "blood-red ruby"                 tag ruby hidden after last;

  task "Unlock door with key"           need key;
  task "Open door"                      after last tag open_door;

room "Lofty Shrine"                     dir s after open_door;
  item "stone slab";
  item "mummified priest";

  task "Put key on slab"                need key lose it give wax;
  item "wax"                            tag wax hidden;

room "Web of Darkness"                  style Dark dir e from Chamber oneway;
  item "scuttling claws";

room "Web of Darkness"                  style Dark dir se oneway;
  item "scuttling claws";
  item "silver bangle"                  hidden tag bangle;

  task "Stumble over bangle"            give bangle cmd "NE" goto Chamber;
  link last to Chamber                  dir ne n w 2 oneway;

room_colour = "gray70" in style Dark;

Drawing the map

At any point during the mapping of the game, we could run IFM and get a map of where we’ve been (and where to explore next, since we marked room exits with exit). We can do that, for example, like this:

ifm -m -o ruins.ps ruins.ifm

and using our favourite PostScript viewer to view the map. Here’s what the completed Ruins map looks like:

_images/ruins.png

Listing items

We can see a complete item list using:

ifm -i ruins.ifm

Here’s what gets output with the completed Ruins map:

Item list for Ruins

blood-red ruby:
   hidden in Stooped Corridor
   obtained after:
      Search moss (Stooped Corridor)
   needed for:
      Put ruby in case (Dark Forest)

carvings:
   seen in Square Chamber

iron key:
   hidden in Square Chamber
   obtained after:
      Press carvings (Square Chamber)
   needed for:
      Unlock door with key (Stooped Corridor)
      Put key on slab (Lofty Shrine)

moss:
   seen in Stooped Corridor

mummified priest:
   seen in Lofty Shrine

scuttling claws:
   seen in Web of Darkness

scuttling claws:
   seen in Web of Darkness

silver bangle:
   hidden in Web of Darkness
   obtained after:
      Stumble over bangle (Web of Darkness)
   needed for:
      Put bangle in case (Dark Forest)

speckled mushroom:
   seen in Dark Forest
   needed for:
      Get statuette (Dark Forest)
      Put mushroom in sunlight (Square Chamber)

statuette:
   hidden in Dark Forest
   obtained after:
      Get speckled mushroom (Dark Forest)
   needed for:
      Put statuette in case (Dark Forest)

stone slab:
   seen in Lofty Shrine

wax:
   hidden in Lofty Shrine
   obtained after:
      Put key on slab (Lofty Shrine)
   needed for:
      Put wax in case (Dark Forest)

Generating a solution

We can get a basic walkthrough of the game using:

ifm -t ruins.ifm

and it looks like this:

Task list for Ruins

Dark Forest:
   Get speckled mushroom
   Get statuette
   Put statuette in case
      score: 10

Move to Square Chamber (D)

Square Chamber:
   Put mushroom in sunlight
   Press carvings
   Get iron key

Move to Stooped Corridor (S)

Stooped Corridor:
   Search moss
   Unlock door with key
   Open door
   Get blood-red ruby

Move to Lofty Shrine (S)

Lofty Shrine:
   Put key on slab
      note: Gives wax

Move to Stooped Corridor (N)
Move to Square Chamber (N)
Move to Dark Forest (U)

Dark Forest:
   Put ruby in case
      score: 30
   Put wax in case
      score: 40

Move to Square Chamber (D)
Move to Web of Darkness (E)
Move to Web of Darkness (SE)

Web of Darkness:
   Stumble over bangle
      cmd: NE
      note: Gives silver bangle
      note: Moves you to Square Chamber

Move to Dark Forest (U)

Dark Forest:
   Put bangle in case
      score: 20
   Wait for helicopter
      cmd: WAIT
      cmd: WAIT
      note: Finishes the game

Total distance travelled: 10

Total score: 100

As you can see, IFM’s solution is slightly different from the way we played it: it stashes the statue straight away. In the actual game, doing that this early wouldn’t work—the packing case hasn’t been dropped yet. Unless we’re trying to make a recording that will play back in Frotz or similar, this doesn’t really matter. If we did want to, we’d have to fix this and create a recording file using:

ifm -t -f rec ruins.ifm

This produces:

GET SPECKLED MUSHROOM
GET STATUETTE
PUT STATUETTE IN CASE
D
PUT MUSHROOM IN SUNLIGHT
PRESS CARVINGS
GET IRON KEY
S
SEARCH MOSS
UNLOCK DOOR WITH KEY
OPEN DOOR
GET BLOOD-RED RUBY
S
PUT KEY ON SLAB
N
N
U
PUT RUBY IN CASE
PUT WAX IN CASE
D
E
SE
NE
U
PUT BANGLE IN CASE
WAIT
WAIT

Another way to view the solution is using a task dependency graph. This uses IFM’s dot output format, like this:

ifm -t -o ruins.dot -f dot ruins.ifm
dot -Tps -o ruins-graph.ps ruins.dot

Here’s what Ruins looks like:

_images/ruins-graph.png

Yet another way to show this is by grouping tasks together according to the rooms they occur in, by setting the task_graph_rooms variable:

ifm -t -o ruins.dot -f dot -s task_graph_rooms=true ruins.ifm
dot -Tps -o ruins-graph.ps ruins.dot

This is what you get:

_images/ruins-graph-byroom.png

Tweaking the solution

If we want to wait for the packing case to appear before trying to put the statue in it, we could do it like this:

task "Wait for packing case" in Dark_Forest need statue cmd "WAIT" 2;

Also, The solution as it stands is not as short as it could be: the game solver takes a trip back up to the packing case to dump two treasures and only then goes to get the bangle. This is because the stashing-treasure tasks are marginally closer at that point.

What we’d like is for the solver to grab all the underground treasure before returning to the surface. This can be done by extending the length (i.e., movement cost) of the implicit link between above-ground and below-ground:

link Chamber length 10;

After adding this line, the solver behaves the way we want.

Footnotes

[1]Yeah, right. You can if you want. I’m off to Ebay.