top expert

a biting cat website

more repeats

other ways to repeat through things.

refresher.

Last time, we talked about repeating through objects and values. In this rather dull example, we ask Inform to list every possible color when color is “a kind of value.”

lab is a room.

color is a kind of value.
the colors are red, green, and blue.

instead of jumping:
	let n be zero;
	repeat with hue running through colors:
		increment n;
		say "color number [n]: [hue][line break]";

We can just as easily run through objects, specifying kinds or properties along the way.

lab is a room.

a hat is a kind of wearable thing.

a cap is a hat.
a derby is a hat.
a beenie is a hat.

instead of smelling:
	let n be zero;
	repeat with covering running through hats:
		unless covering is worn:
			increment n;
			say "unworn hat number [n]: [covering][line break]";

While these tools have many uses, I most often find myself using them to bulk move things around or apply properties to many things at once.

But wait… there’s more!

repeating through tables.

It’s often useful to check every entry in a table. Tables are very flexible; they can hold values, objects, and even actions. We might be using table to store texts, or track actions performed. They might be part of a custom scoring system. In my own game Portrait with Wolf, almost every bit of printed text is pulled from tables (you can view the source code here).

Let’s say, as a sort of silly example, that we want to keep track of everything the player EATs. Now, the EATING action is included in the Standard Rules, so let’s have a look there. As you can see, we have a few CHECK rules, a silent CARRY OUT rule, and a REPORT rule. Let’s define our food of choice—fruits sound fine, so let’s run with that—then think about where we can intervene.

a fruit is a kind of thing.
a fruit is edible.
			
an apple is a kind of fruit.
there are 2 apples in lab.
there is 1 apple  nowhere.
the description of apple is "A sweet honeycrisp, gold and red."

grape is a fruit in lab.
the description of grape is "Green and of perfect firmness."

orange is a fruit in lab.
the description of orange is "Delightfully tart and pleasantly sweet."

We’ll start with a kind, making members of that kind “edible.” Edible is built into the Standard rules, so we don’t have to get involved there. The CHECK rules aren’t necessarily of interest to us. They prevent the player from EATING inedible things; we have that covered. If the player wears something edible (!), Inform will attempt to remove it before EATING it. If the player does not carry the edible thing, Inform will attempt TAKING it.

Notice that “apple” is handled differently, being described as a “kind” with a number (2). This is in place so that we can try having the player eat more than one of the same kind of fruit. We’ll have a go at that below.

Inform will prevent the player from EATING food held by other characters as well.

That all seems fine, so we’ll leave it alone. The CARRY OUT rule banishes the eaten item (presuming it makes it through these CHECKs) to nowhere. That leaves us with a generic REPORT response. Let’s let the CARRY OUT rule run. Eaten foods should be gone, after all. We want to intervene between the CARRY OUT rule and the report. We can achieve that with an AFTER rule.

Before writing out some rules, though, let’s design the table. I want something very simple: just the fruit’s name, the fruit’s description, and a count of times eaten.

table of consumed items
fruit	text	count
(a text)	(a text)	(a number)
with 10 blank rows

Easy enough! If we manage to include 10 unique fruits in our project, we’ll need to add more blank rows. If you are wondering why we are using the printed name instead of the noun itself (Inform tables handle nouns just fine), it’s because we are dealing with duplicates. More on this below.

after eating a fruit:

Next, let’s set up a simple truth state for our rule to track whether something has been eaten before. This will keep us from having duplicate entries if the player has eaten the same kind of fruit more than once.

	let previously eaten be false;

OK. We have a code and a truth state. Let’s check the table after every action (that isn’t stopped by INSTEAD and the like):

	repeat through the table of consumed items:
		say line break;
		if fruit entry is the printed name of the noun:
			increment count entry;
			now previously eaten is true;

If the player eats an apple when they have previously eaten one, we will discover it when our code repeats through the table. Repeating through a table asks Inform to evaluate every filled row in a table, starting from the top.

In our code, if there is already an Apple in our table, the “count” entry will go up one. Additionally, “previously eaten” will switch from false to true. Inform will use this value to determine whether a new entry should be added to the table.

	if previously eaten is false:
		choose a blank row in the table of consumed items;
		now fruit entry is the printed name of noun;
		now text entry is the description of the noun;
		now count entry is one;
		say "Ah, such a delicious [noun]!";

After performing its check through the table, Inform will, if relevant, add a new fruit to an empty row. We can additionally add text for description and set the count to one.

Note that, by default, AFTER rules end the action processing sequence, preventing the generic REPORT rule from running. We’ve instead added our own simple feedback response.

That’s all well and good, but how do we get the information out? That’s down to another repeat loop. Let’s make an action first.

Since we’re not going to be typing this a lot, there’s no harm in using a verbose action name that we can read easily.

reviewing our fruit history is an action out of world applying to nothing.
understand "history" as reviewing our fruit history.

I always use “actions out of world” for this kind of information checking. On principle, I don’t think they should advance the turn count.

We’ll handle two cases here. First, one for an empty table:

carry out reviewing our fruit history when the number of filled rows in the table of consumed items is zero:
	say "Sadly, you have yet to consume any fruit.";

And one more for a filled table.

carry out reviewing our fruit history when the number of filled rows in the table of consumed items is greater than zero:
	repeat through the table of consumed items:
		say "[fruit entry in sentence case]: '[text entry]' ([count entry])[line break]";

Expected output:

Welcome
An Interactive Fiction
Release 1 / Serial number 251016 / Inform 7 v10.1.2 / D

lab
You can see two apples, grape and orange here.

>eat apple
(first taking the apple)
Ah, such a delicious apple!

>eat grape
(first taking grape)
Ah, such a delicious grape!

>eat orange
(first taking orange)
Ah, such a delicious orange!

>eat apple
(first taking the apple)
Ah, such a delicious apple!

>history
Apple: "A sweet honeycrisp, gold and red." (2)
Grape: "Green and of perfect firmness." (1)
Orange: "Delightfully tart and pleasantly sweet." (1)

And, finally, a borogove link for anyone interested in the complete project.

https://snippets.borogove.app/inform7/bx8ffw

next.

That’s not all! As a last bit of excitement, we’ll have a look at repeating with counters and lists.