§23.13. Writing and reading tables to external files
The main use for files is to store and retrieve data, and the most flexible form of data used by Inform is the Table, so facilities are provided which make it as easy as possible to write and read the contents of a table to files. If so, the file must contain just one single table: so to write multiple tables, we need to write multiple files, one for each.
To save the contents of a table to a file, we use the phrase:
write (external file) from (table name)
This phrase causes the entire contents of the given table to be written out to the given file. Note that files must have been declared, and must be referred to by their Inform names, not by textual filenames. Example:
write File of Glaciation Data from the Table of Antarctic Reserves
Any blank rows in the table are automatically moved to the bottom, and only the non-blank rows are written.
To load a file back into a table,
read (external file) into (table name)
This phrase causes the entire contents of the given table to be read in from the given file. Note that files must have been declared, and must be referred to by their Inform names, not by textual filenames. Example:
read File of Glaciation Data into the Table of Antarctic Reserves
Any rows left spare at the foot of the table are automatically blanked. On the other hand if the file is too large to fit into the table - with too many columns or too many rows - a run-time problem is produced.
We can check if a file already exists using:
if (external file) exists:
This condition is true if the file-system used by the player appears to contain a file with the right name. For example, if we declared:
The binary File of Glaciation Data is called "icedata".
and then tested
if the File of Glaciation Data exists, ...
then Inform would search for a file called "icedata". (The arrangements for where this might be stored, and its filename extension, vary from platform to platform.)
One unfortunate restriction must be kept in mind. Some of what is stored in tables is solid information whose meaning never changes: the number 342, for instance, means the same to everyone. But other information depends entirely on the current location of certain structures in memory - for instance, a rule is internally referred to by its memory location. This potentially changes each time Go or Replay is clicked, and so it is not safe to pass it from one copy to another, or from one project to another. The only tables which Inform allows us to write into files are those containing "safe" data: numbers, units, times of day and kinds of value with named alternatives. Scenes, rules or rulebooks, in particular, are not allowed.
The trick here is that we need a table with text in order to keep track of the players' names.
Part 1 largely replicates the source from "Identity Theft"; new material starts at Part 2.
"Rubies"
Use scoring.
Part 1 - Collecting Names
The player's forename is a text that varies. The player's full name is a text that varies.
When play begins:
now the command prompt is "What is your name? > ".
To decide whether collecting names:
if the command prompt is "What is your name? > ", yes;
no.
After reading a command when collecting names:
if the number of words in the player's command is greater than 5:
say "[paragraph break]Who are you, a member of the British royal family? No one has that many names. Let's try this again.";
reject the player's command;
now the player's full name is the player's command;
now the player's forename is word number 1 in the player's command;
now the command prompt is ">";
say "Hi, [player's forename]!";
say "[banner text]";
move the player to the location;
reject the player's command.
Instead of looking when collecting names: do nothing.
Rule for printing the banner text when collecting names: do nothing.
Rule for constructing the status line when collecting names: do nothing.
Part 2 - Adding the Leaderboard
File of Leaderboard is called "leaderboard".
When play begins:
if the File of Leaderboard exists:
read File of Leaderboard into the Table of Leaders;
sort the Table of Leaders in reverse scored amount order.
When play ends:
choose row 10 in the Table of Leaders; [we've sorted the table, so the lowest score will be the one at the bottom]
if the score is greater than scored amount entry:
now name entry is the player's forename;
now the scored amount entry is the score;
show leaderboard;
write the File of Leaderboard from the Table of Leaders.
To show leaderboard:
sort the Table of Leaders in reverse scored amount order;
say "Current leading scores: [paragraph break]";
say fixed letter spacing;
repeat through Table of Leaders:
if scored amount entry is greater than 0:
say " [name entry]";
let N be 25 minus the number of characters in name entry; [here we want to space out the scores so they make a neat column]
if N is less than 1, now N is 1;
say N spaces;
say "[scored amount entry][line break]";
say variable letter spacing.
To say (N - a number) spaces:
repeat with index running from 1 to N:
say " ".
Table of Leaders
scored amount | name |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
And now we introduce a scenario that allows different players to come up with different scores -- admittedly not a very interesting scenario, but it will do for now:
Part 3 - Scenario
Carry out taking something which is not handled:
increment score.
The Big Treasure Chamber is a room. It contains a ruby, an emerald, a gold tooth, an antique katana, and a silver coin.
Instead of waiting, end the story finally.
Test me with "get ruby / z".
|   ExampleRubies A scoreboard that keeps track of the ten highest-scoring players from one playthrough to the next, adding the player's name if he has done well enough.
|
The trick here is that we need a table with text in order to keep track of the players' names.
Part 1 largely replicates the source from "Identity Theft"; new material starts at Part 2.
"Rubies"
Use scoring.
Part 1 - Collecting Names
The player's forename is a text that varies. The player's full name is a text that varies.
When play begins:
now the command prompt is "What is your name? > ".
To decide whether collecting names:
if the command prompt is "What is your name? > ", yes;
no.
After reading a command when collecting names:
if the number of words in the player's command is greater than 5:
say "[paragraph break]Who are you, a member of the British royal family? No one has that many names. Let's try this again.";
reject the player's command;
now the player's full name is the player's command;
now the player's forename is word number 1 in the player's command;
now the command prompt is ">";
say "Hi, [player's forename]!";
say "[banner text]";
move the player to the location;
reject the player's command.
Instead of looking when collecting names: do nothing.
Rule for printing the banner text when collecting names: do nothing.
Rule for constructing the status line when collecting names: do nothing.
Part 2 - Adding the Leaderboard
File of Leaderboard is called "leaderboard".
When play begins:
if the File of Leaderboard exists:
read File of Leaderboard into the Table of Leaders;
sort the Table of Leaders in reverse scored amount order.
When play ends:
choose row 10 in the Table of Leaders; [we've sorted the table, so the lowest score will be the one at the bottom]
if the score is greater than scored amount entry:
now name entry is the player's forename;
now the scored amount entry is the score;
show leaderboard;
write the File of Leaderboard from the Table of Leaders.
To show leaderboard:
sort the Table of Leaders in reverse scored amount order;
say "Current leading scores: [paragraph break]";
say fixed letter spacing;
repeat through Table of Leaders:
if scored amount entry is greater than 0:
say " [name entry]";
let N be 25 minus the number of characters in name entry; [here we want to space out the scores so they make a neat column]
if N is less than 1, now N is 1;
say N spaces;
say "[scored amount entry][line break]";
say variable letter spacing.
To say (N - a number) spaces:
repeat with index running from 1 to N:
say " ".
Table of Leaders
scored amount | name |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
And now we introduce a scenario that allows different players to come up with different scores -- admittedly not a very interesting scenario, but it will do for now:
Part 3 - Scenario
Carry out taking something which is not handled:
increment score.
The Big Treasure Chamber is a room. It contains a ruby, an emerald, a gold tooth, an antique katana, and a silver coin.
Instead of waiting, end the story finally.
Test me with "get ruby / z".
The trick here is that we need a table with text in order to keep track of the players' names.
Part 1 largely replicates the source from "Identity Theft"; new material starts at Part 2.
"Rubies"
Use scoring.
Part 1 - Collecting Names
The player's forename is a text that varies. The player's full name is a text that varies.
When play begins:
now the command prompt is "What is your name? > ".
To decide whether collecting names:
if the command prompt is "What is your name? > ", yes;
no.
After reading a command when collecting names:
if the number of words in the player's command is greater than 5:
say "[paragraph break]Who are you, a member of the British royal family? No one has that many names. Let's try this again.";
reject the player's command;
now the player's full name is the player's command;
now the player's forename is word number 1 in the player's command;
now the command prompt is ">";
say "Hi, [player's forename]!";
say "[banner text]";
move the player to the location;
reject the player's command.
Instead of looking when collecting names: do nothing.
Rule for printing the banner text when collecting names: do nothing.
Rule for constructing the status line when collecting names: do nothing.
Part 2 - Adding the Leaderboard
File of Leaderboard is called "leaderboard".
When play begins:
if the File of Leaderboard exists:
read File of Leaderboard into the Table of Leaders;
sort the Table of Leaders in reverse scored amount order.
When play ends:
choose row 10 in the Table of Leaders; [we've sorted the table, so the lowest score will be the one at the bottom]
if the score is greater than scored amount entry:
now name entry is the player's forename;
now the scored amount entry is the score;
show leaderboard;
write the File of Leaderboard from the Table of Leaders.
To show leaderboard:
sort the Table of Leaders in reverse scored amount order;
say "Current leading scores: [paragraph break]";
say fixed letter spacing;
repeat through Table of Leaders:
if scored amount entry is greater than 0:
say " [name entry]";
let N be 25 minus the number of characters in name entry; [here we want to space out the scores so they make a neat column]
if N is less than 1, now N is 1;
say N spaces;
say "[scored amount entry][line break]";
say variable letter spacing.
To say (N - a number) spaces:
repeat with index running from 1 to N:
say " ".
Table of Leaders
scored amount | name |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
0 | "Smithee" |
And now we introduce a scenario that allows different players to come up with different scores -- admittedly not a very interesting scenario, but it will do for now:
Part 3 - Scenario
Carry out taking something which is not handled:
increment score.
The Big Treasure Chamber is a room. It contains a ruby, an emerald, a gold tooth, an antique katana, and a silver coin.
Instead of waiting, end the story finally.
Test me with "get ruby / z".
|