A wild regex appears!
Mainframe Blues
From a presentation and interface point of view, Inform games emerged from the rarefied world of terminal applications. While terminals might support varied character sets, they are designed to print, one line at a time, unadorned text. There’s nothing wrong with that. It’s how Inform games do things, and this is an Inform blog. But if you’re a new author struggling to reach players on itch.io, you might think: “I wish I could post nicer-looking screenshots.”
You’re not alone! The mainframe terminal aesthetic might be a hard sell, excepting ironic, faux retro works. How can we spice things up? We can start by thinking about layout. Because of Inform’s line feed output, it doesn’t really “get” the concepts of tab stops. Earlier versions of Inform permitted the use of separate “windows” for storing different types of content but Inform 10 has no extensions for these presentation elements. I’m not qualified to say why this is, but we have reason to believe that Inform 11 will be much better in this regard.
Since there has been no release date announced for Inform 11, some of us might try to handle things ourselves.
table + faux = tableau?
Let’s try to come up with a way to print something that looks like a table. Every column should like up equally for a uniform look. How can we do it? We can try typing it out. Let’s say a column is, oh, eight characters or spaces wide. To keep a column looking tidy:
- type our word
- figure out the number of spaces needed to reach our column link (8 minus the number of letters in our word.
- add in the spaces.
- type a new word, repeat as needed.
By default, that should look like this.
apple fruit yes
car vehicle no
goat animal yes
That’s not it, is it? By default, Inform (and almost everything else) uses variable letter spacing. These proportional fonts have different letter widths based on the width of the letter. This means that the lower case “i” takes up less space than a capital case “Z”. Because of this difference, we can never get our letters to line up unless we switch a monospaced font. We can change these formatting options easily, by the way:
to say some monospaced code:
say "[fixed letter spacing]Some monospaced text.";
[or]
say fixed letter spacing;
say "Some monospaced code.";
We can just as easily change it back:
say "[variable letter spacing]Some proportional text."
These are long phrases. We can save ourselves some time by substituting abbreviations.
to say fls:
say fixed letter spacing.
[then we can say]
say "[fls]Some monospaced text.";
Backc to our earlier example: f we change our output type and count our spaces, we can get something better.
apple fruit yes
car vehicle no
goat animal yes
Better, yes? So we want to do a combination of counted spaces and monospaced text. There’s a problem, though. What if we have a lot of text to print, or if we are printing it automatically? We might be repeating through a table or list, for instance. Or values. We’d have no way to count our spaces manually. Instead, we’d have to get Inform to do it for us.
space counter 2025
How could we do it? How could Inform count our spaces for us? It won’t be easy, and in fact it’s pretty rich for beginners like us. I’ve tried to put together an example that can be copy/pasted into a project without too much challenge. You know the old saying, “fake it ’til you make it?” Copy the code and use it until it makes sense! Or, if it makes sense right away, make it better if you like. Here we go.
First, let’s get a table. I’ll copy it from my current WIP.
table of aphoses
aphosis active description alternate command shortcut count
FLEGECORS FALSE insect curse PLAGUE P 0
HYLUAL FALSE mountainfall ROCKFALL R 0
SLIMUAL FALSE slimefall SLIME SL 0
Sorry this looks so bad! Let’s see what we can do. The longest word in the first column, “FLEGECORS”, has nine characters. What would be a good column length? Let’s try 12.
OK, a 12 character column. Here’s the path I think we should take.
- Inform determines the number of characters in a word.
- Inform figures out the amount of empty spaces needed to line up the next column.
- Inform prints the text, then the spaces, then moves on to the next column.
This will combine things we’ve done before with new tricks. I’ll explain everything as we go.
Let’s make a what’s called a “phrase to decide”. In these decisions, we are telling Inform how to calculate or determine something on the fly. Here’s my phrase:
to decide which text is the tabbed presentation of (t - a text) with (C - a number) spaces:
By saying “which text,” we are asking Inform to come up with a text for us. We can use that text anywhere. It will be like any other substitution. If you thought that Inform could only do this kind of thing with numbers and values, you’re not alone! It took me a while to get here.
We have two variables to work with: (t – a text) and (C – a number). When we ask Inform to make this decision for us, we have to provide it with the text we want it to evaluate. N will represent the column width. We can change this as needed when we make our rules.
The next thing we want to do is figure out the number of spaces needed:
to decide which text is the tabbed presentation of (t - a text) with (C - a number) spaces:
now C is C minus the number of characters in t;
Since C is the column width, we’ll figure out the amount of space needed by subtracting the number of letters in the word from C. If we are sticking with 12 for a column width, “frob” (4 characters) would leave room for eight spaces. How do we get there? There are a number of ways, actually, but I’m going to do something weird. Bear with me, OK.
Let’s set up a constant. Constants are just what they sound like: they never change. We can make a constant and fill it with spaces.
void is always " ";
Void is just a text made of twenty space characters. Using our calculation, we can take/copy spaces from it as needed.
if void matches the regular expression "/s{1,[C]}":
Whew! That’s a lot to look at, isn’t it? Regular expressions are a powerful tool for finding patterns in text. Think of it as a very advanced form of “control-f” finding on a web page or word processing document. Let’s unpack this phrase.
“if void matches the regular expression” simply means that we are looking for a text that may or may not be in our “void” constant. Now, since void consists only of spaces, there isn’t a lot to look for. In fact, we just want to count out our spaces and get out. That’s what the next part does. The quoted part contains our parameters. This is the hard part of doing regular expressions. The different characters can be intimidating and confusing. But don’t worry! I’ve written this for easy copy/pasting.
“\s{1,[CC]}”
Bit by bit:
- The the “\s” indicates that we are looking for a space character. Since void is filled with them, we are bound to find some!
- The curved brackets {} are used to find a specific number of characters. This is how we will count out our line spaces.
- The numbers indicate a range of spaces. In this case, we want the highest number ranging from 1 to our C (the number of spaces needed to fill our column).
In other words: this regular expression is searching for the line space characters we need from void, based on the column width we have specified.
What’s next?
let V be "[text matching regular expression]";
decide on the substituted form of "[t][V]";
“Text matching regular expression” is just what it sounds like. It’s the text we found in our search: a number of line spaces based on our parameters in this case.
We can call that text “V” and print it together with our original text as “the substituted form of ‘[t][V]’”. A substituted form sounds tricky, but it’s just a way to say we are updating a text on the fly.
The “decide on” phrase means that the story has reached a decision. Without having to revisit the regular expression, we can use simple phrases like this in our code.
say the tabbed presentation of "jump" with eight spaces;
Here’s a working project to play with. Try adding this “to decide” definition to your own project and experimenting a bit!
lab is a room.
void is always " ";
instead of jumping:
say fixed letter spacing;
say the tabbed presentation of "jump" with eight spaces;
say "Wow!";
say the tabbed presentation of "listen" with eight spaces;
say "Neat."
to decide which text is the tabbed presentation of (t - a text) with (C - a number) spaces:
now C is C minus the number of characters in t;
if void matches the regular expression "/s{1,[C]}":
let V be "[text matching regular expression]";
decide on the substituted form of "[t][V]";
Output:
>jump
jump Wow!
listen Neat.
A strange journey, but that’s that. But wait, we haven’t even discussed automated printout from tables and such. Let’s do that next time, OK? We have a lot to think about already. Here’s a preview of what we’ll make next:
APHOSIS | DESCRIPTION | GRAMMAR | SHORTCUT
------------------------------------------------------------
FLEGECORS | insect curse | PLAGUE | P
HYLUAL | mountainfall | ROCKFALL | R
SLIMUAL | slimefall | SLIME | SL
More info re: Regular Expressions:
See my Portrait with Wolf code (see below) for regex with comments
Inform Dcumentation (might be hard to follow)
regex101: build, test, and debug regex
regex tutorial (intended to sell classes, but the first one is free)
p.s.
My spring thing games are out. I’ve written about my process for making them here! The source code is available, too.
Marbles, D, and the Sinister Spotlight
Portrait with Wolf
You can read my post-project essay here:
Animal Games: Spring Thing 2025
How do I feel about my games? I’m very proud of the progress I’ve made with Inform. I’ve worked hard to get better, and I think it’s paying off. I’m a little disappointed in the reception, though. The games didn’t take off in terms of player count or discussion. I think there are a handful of reasons for that. Maybe we can get into that someday, but not now. Let’s keep making IF!
