 Every example program so far has consisted only of 
a sequence of routines, each within beginning and end markers
Every example program so far has consisted only of 
a sequence of routines, each within beginning and end markers [ 
and ]. Such routines have no way of communicating with each 
other, and therefore of sharing information with each other, except by 
calling each other back and forth. This arrangement is not really suited 
to a large program whose task may be to simulate something complicated, 
such as the world of an adventure game: instead, some central registry 
of information is needed, to which all routines can have access. 
In the author's game ‘Curses’, centrally-held 
information ranges from the current score, held in a single variable 
called score, to Madame Sosostris's tarot pack, which 
uses an array of variables representing the cards on the pack, to a 
slide-projector held as an “object”: a bundle of variables 
and routines encoding the relevant rules of the game, such as that 
the whitewashed wall is only lit up when the slide projector is 
switched on.
Every Inform source program is a list of constructions, made using commands called “directives”. These are quite different from the statements inside routines, because directives create something at compilation time, whereas statements are only instructions for the interpreter to follow later, when the story file is being played.
In all there are 38 Inform directives, but most of 
them are seldom used, or else are just conveniences to help you organise 
your source code: for instance Include means “now 
include another whole file of source code here”, and there 
are directives for “if I've set some constant at the start of 
the code, then don't compile this next bit” and so on. The 10 
directives that matter are the ones creating data structures, and 
here they are:
[ Array Attribute Class Constant Extend Global Object Property Verb
The directive written [, meaning 
“construct a routine containing the following statements, 
up to the next ]”, was the subject of 
§1. The four directives to do
with objects, Attribute, Class, 
Object and Property, will be the subject of
§3. The two directives to do with laying 
out grammar, Verb and Extend, are intimately 
tied up with the needs of adventure games using the Inform library,
and are useless for any other purpose, so these are left until 
§30. That leaves just Array, 
Constant and Global.
The simplest construction you can make is of 
a Constant. The following program, an unsatisfying 
game of chance, shows a typical usage:
Constant MAXIMUM_SCORE = 100;
[ Main;
  print "You have scored ", random(MAXIMUM_SCORE),
      " points out of ", MAXIMUM_SCORE, ".^";
];
The maximum score value is used twice in the routine 
Main. The resulting story file is exactly the same as it 
would have been if the constant definition were not present, and 
MAXIMUM_SCORE were replaced by 100 in both places
where it occurs. But the advantage of using Constant is 
that it makes it possible to change this value from 100 to, say, 50 
with only a single change to the source code, and it makes the source 
code more legible.
People often write the names of constants in full 
capitals, but this is not compulsory. Another convention is that the 
= sign, which is optional, is often left out if the 
value is a piece of text rather than a number. If no value is specified 
for a constant, as in the line
Constant BETA_TEST_VERSION;
then the constant is created with value 0.
A constant can be used from anywhere in the source code after the line on which it is declared. Its value cannot be altered.
The variables in §1 were all “local variables”, each owned privately by its own routine, inaccessible to the rest of the program and destroyed as soon as the routine stops. A “global variable” is permanent and its value can be used or altered from every routine.
The directive for declaring a global variable is 
Global. For example:
Global score = 36;
This creates a variable called score, which 
at the start of the program has the value 36. (If no initial value 
is given, it starts with the value 0.)
A global variable can be altered or used from anywhere in the source code after the line on which it is declared.
An “array” is an indexed collection of 
variables, holding a set of numbers organised into a sequence. To 
see why this useful, suppose that a pack of cards is to be simulated. 
You could define 52 different variables with Global, with
names like Ace_of_Hearts, to hold the position of each 
card in the pack: but then it would be very tiresome to write a routine 
to shuffle them around.
Instead, you can declare an array:
Array pack_of_cards --> 52;
which creates a stock of 52 variables, called the “entries” of the array, and referred to in the source code as
pack_of_cards-->0 pack_of_cards-->1 ... pack_of_cards-->51
and the point of this is that you can read or alter 
the variable for card number i by calling it 
pack_of_cards-->i. 
Here is an example program, in full, for shuffling the pack:
Constant SHUFFLES = 100;
Array pack_of_cards --> 52;
[ ExchangeTwo x y z;
  !   Randomly choose two different numbers between 0 and 51:
  while (x==y) {
      x = random(52) - 1; y = random(52) - 1;
  }
  z = pack_of_cards-->x; pack_of_cards-->x = pack_of_cards-->y;
  pack_of_cards-->y = z;
];
[ Card n;
  switch(n%13) {
      0: print "Ace";
      1 to 9: print n%13 + 1;
      10: print "Jack";
      11: print "Queen";
      12: print "King";
  }
  print " of ";
  switch(n/13) {
      0: print "Hearts"; 1: print "Clubs";
      2: print "Diamonds"; 3: print "Spades";
  }
];
[ Main i;
  !   Create the pack in quot;factory order":
  for (i=0:i<52:i++) pack_of_cards-->i = i;
  !   Exchange random pairs of cards for a while:
  for (i=1:i<=SHUFFLES:i++) ExchangeTwo();
  print "The pack has been shuffled into the following order:^";
  for (i=0:i<52:i++)
      print (Card) pack_of_cards-->i, "^";
];
The cards are represented by numbers in the range 
0 (the Ace of Hearts) to 51 (the King of Spades). The pack itself has 
52 positions, from position 0 (top) to position 51 (bottom). The 
entry pack_of_cards-->i holds the number of the 
card in position i. A new pack as produced by the factory 
would come with Ace of Hearts on top (card 0 in position 0), running 
down to the King of Spades on the bottom (card 51 in position 51).
▲
A hundred exchanges is only just enough. Redefining SHUFFLES as 10,000 
takes a lot longer, while redefining it as 10 makes for a highly suspect 
result. Here is a more efficient method of shuffling (contributed 
by Dylan Thurston), perfectly random in just 51 exchanges.
pack_of_cards-->0 = 0;
for (i=1:i<52:i++) {
    j = random(i+1) - 1;
    pack_of_cards-->i = pack_of_cards-->j; pack_of_cards-->j = i;
}
· · · · ·
In the above example, the array entries are all created containing 0. Instead, you can give a list of constant values. For example,
Array small_primes --> 2 3 5 7 11 13;
is an array with six entries, small_primes-->0 
to small_primes-->5, initially holding 2, 3, 5, 7, 11 
and 13.
The third way to create an array gives some text as an initial value, occasionally useful because one popular use for arrays is as “strings of characters” or “text buffers”. For instance:
Array players_name --> "Frank Booth";
is equivalent to the directive:
Array players_name --> 'F' 'r' 'a' 'n' 'k' ' ' 'B' 'o' 'o' 't' 'h';
Literal text like "Frank Booth" is a constant, 
not an array, and you can no more alter its lettering than you could 
alter the digits of the number 124. The array players_name is 
quite different: its entries can be altered. But this means it cannot 
be treated as if it were a string constant, and in particular can't 
be printed out with print (string). See below for the right 
way to do this.
• WARNING
In the pack of cards example, the entries are indexed 0 to 51. It's 
therefore impossible for an interpreter to obey the following statement:
pack_of_cards-->52 = 0;
because there is no entry 52. Instead, the following message will be printed when it plays:
[** Programming error: tried to write to -->52 in the array “pack_of_cards”, which has entries 0 up to 51 **]
Such a mistake is sometimes called breaking the bounds of the array.
· · · · ·
The kind of array constructed above is sometimes called a “word array”. This is the most useful kind and many game designers never use the other three varieties at all.
▲
The first alternative is a “byte array”, which is identical 
except that its entries can only hold numbers in the range 0 to 255, 
and that it uses the notation -> instead of -->. This 
is only really useful to economise on memory usage in special circumstances,
usually when the entries are known to be characters, because ZSCII 
character codes are all between 0 and 255. The “Frank Booth” 
array above could safely have been a byte array.
▲
In addition to this, Inform provides arrays which have a little extra 
structure: they are created with the 0th entry holding the number 
of entries. A word array with this property is called a table; 
a byte array with this property is a string. 
For example, the table
Array continents table 5;
has six entries: continents-->0, which holds 
the number 5, and further entries continents-->1 
to continents-->5. If the program changed 
continents-->0 this would not magically change the 
number of array entries, or indeed the number of continents.
▲▲
One main reason you might want some arrangement like this is to write 
a general routine which can be applied to any array. Here is an example 
using string arrays:
Array password string "danger";
Array phone_number string "0171-930-9000";
...
print "Please give the password ", (PrintStringArray) password,
    " whenever telephoning Universal Exports at ",
    (PrintStringArray) phone_number, ".";
...
[ PrintStringArray the_array i;
  for (i=1: i<=the_array->0: i++) print (char) the_array->i;
];
Such routines should be written with care, as the normal checking of array bounds isn't performed when arrays are accessed in this indirect sort of fashion, so any mistake you make may cause trouble elsewhere and be difficult to diagnose.
▲▲ With all data structures (i.e., with objects, strings, routines and arrays) Inform calls by reference, not by value. So, for instance:
[ DamageStringArray the_array i;
  for (i=1: i<=the_array->0: i++) {
      if (the_array->i == 'a' or 'e' or 'i' or 'o' or 'u')
          the_array->i = random('a', 'e', 'i', 'o', 'u');
      print (char) the_array->i;
  }
];
means that the call DamageStringArray(password_string) 
will not just print (say) “dungor” but also alter the one 
and only copy of password_string in the story file.
Surprisingly, perhaps, given that Inform is a language for text adventure games, support for reading from the keyboard is fairly limited. A significant difference of approach between Inform and many other systems for interactive fiction is that mechanisms for parsing textual commands don't come built into the language itself. Instead, game designers use a standard Inform parser program which occupies four and a half thousand lines of Inform code.
Reading single key-presses, perhaps with time-limits, or for that matter reading the mouse position and state (in a Version 6 game) requires the use of Inform assembly language: see §42.
A statement called read does however 
exist for reading in a single line of text and storing it into a 
byte array:
read text_array 0;
You must already have set text_array->0 
to the maximum number of characters you will allow to be read. (If 
this is N, then the array must be defined with at least
N + 3 entries, the last of which guards against overruns.)
The number of characters actually read, not counting the carriage 
return, will be placed into text_array->1 and 
the characters themselves into entries from text_array->2 
onwards. For example, if the player typed “GET IN”:
| ->0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 
| max | characters | text typed by player, reduced to lower case | |||||
| 60 | 6 | 'g' | 'e' | 't' | ' ' | 'i' | 'n' | 
The following echo chamber demonstrates how to read from this array:
Array text_array -> 63;
[ Main c x;
  for (::) {
      print "^> ";
      text_array->0 = 60;
      read text_array 0;
      for (x=0:x<text_array->1:x++) {
          c = text_array->(2+x);
          print (char) c; if (c == 'o') print "h";
      }
  }
];
· · · · ·
▲
read can go further than simply reading in the text: 
it can work out where the words start and end, and if they are words 
registered in the story file's built-in vocabulary, known as the 
“dictionary”. To produce all this information, read 
needs to be supplied with a second array:
read text_array parse_array;
read not only stores the text (just 
as above) but breaks down the line into a sequence of words, in 
which commas and full stops count as separate words in their own right. 
(An example is given in Chapter IV, 
§30.) In advance of this 
parse_array->0 must havebeen set to W, the 
maximum number of words you want to parse. Any further text will be 
ignored. parse_array should have at least 4W 
+ 2 entries, because parse_array->1 is set to the 
actual number of words parsed, and then a four-entry block is written 
into the array for each word parsed. Numbering the words as 1, 2, 3,
…, the number of letters in word n is written into 
parse_array->(n*4), and the position of the start 
of the word in text_array. The dictionary value of 
the word, or zero if it isn't recognised, is stored as 
parse_array-->(n*2-1). The corresponding parsing 
array to the previous text array, for the command “GET IN”, 
looks like so:
| ->0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 
| max | words | first word | second word | ||||||
| 10 | 2 | 'get' | 2 | 3 | 'in' | 5 | 2 | ||
In this example both words were recognised. The 
word “get” began at position ->2 in 
the text array, and was 3 characters long; the word “in” 
began at ->5 and was 2 characters long. 
The following program reads in text and prints back an analysis:
Array text_array -> 63;
Array parse_array -> 42;
[ Main w x length position dict;
  w = 'mary'; w = 'had'; w = 'a//'; w = 'little'; w = 'lamb';
  for (::) {
      print "^> ";
      text_array->0 = 60; parse_array->0 = 10;
      read text_array parse_array;
      for (w=1:w<=parse_array->1:w++) {
          print "Word ", w, ": ";
          length = parse_array->(4*w);
          position = parse_array->(4*w + 1);
          dict = parse_array-->(w*2-1);
          for (x=0:x<length:x++)
              print (char) text_array->(position+x);
          print " (length ", length, ")";
          if (dict) print " equals '", (address) dict, "'^";
          else print " is not in the dictionary^";
      }
  }
];
Note that the pointless-looking first line of Main 
adds five words to the dictionary. The result is:
>MARY, hello
Word 1: mary (length 4) equals 'mary'
Word 2: , (length 1) is not in the dictionary
Word 3: hello (length 5) is not in the dictionary
▲
What goes into the dictionary? The answer is: any of the words given 
in the name of an object (see §3), 
any of the verbs and prepositions given in grammar by Verb 
and Extend directives (see §26), and anything 
given as a dictionary-word constant. The last is convenient because 
it means that code like
if (parse_array -->(n*2-1)) == 'purple';
does what it looks as if it should. When compiling 
this line, Inform automatically adds the word “purple” 
to the story file's dictionary, so that any read statement 
will recognise it.
• REFERENCES
Evin Robertson's function library "array.h" 
provides some simple array-handling utilities.  
•L. Ross Raszewski's function 
library "istring.h" offers Inform versions of 
the ANSI C string-handling routines, including strcmp(), 
strcpy() and strcat(). The further extension 
"znsi.h" allows the printing out of string 
arrays with special escape sequences like [B interpreted 
as “bold face.” (See also the same author's
"ictype.h".)  
•Adam Cadre's function library 
"flags.h" manages an array of boolean values 
(that is, values which can only be true or false) 
so as to use only one-sixteenth as much memory as a conventional array, 
though at some cost to speed of access.