
S12's file holds everything, and makes the player wait up to two seconds for each message. The wait comes from reading the file from the start. A typed file, the kind the Turbo course's S21 kept records in, has no such problem: Seek goes straight to any record. So the messages move into one.
F: file of Str255;
Each record is one string[255], and message N is record N - 1, since records count from 0. To print message N:
Seek(F, N - 1);
Read(F, Msg);
Wrap(Msg);
Five reads of the first message take about a tenth of a second; five of the 27th, about a quarter of one. From the text file they took four seconds and ten.
A program has to turn BEACON.TXT into the typed file once. MAKEMSG reads the text file line by line. Each * line starts a new message, so it writes the message it has been building, if any, and starts again. Each text line is added to the message, with a | between paragraphs so that Wrap can put the break back. The exits lines are left out.
program MakeMsg;
type
Str255 = string[255];
var
T: Text;
F: file of Str255;
Line, Msg: Str255;
N: Integer;
begin
Assign(T, 'BEACON.TXT');
Reset(T);
Assign(F, 'BEACON.MSG');
Rewrite(F);
N := 0;
while not Eof(T) do
begin
Readln(T, Line);
if Copy(Line, 1, 1) = '*' then
begin
if N > 0 then
Write(F, Msg);
N := N + 1;
FillChar(Msg, SizeOf(Msg), 0);
end
else if (N > 0) and (Line <> '')
and not (Line[1] in ['0'..'9'])
then
begin
if Msg <> '' then
Msg := Msg + '|';
Msg := Msg + Line;
end;
end;
Close(T);
Writeln(FileSize(F), ' messages');
Close(F);
end.
It prints 27 messages. BEACON.MSG is already on the primer's disc, made by exactly this program, so you need not run it; if you do, it makes the same file again.
FillChar(Msg, SizeOf(Msg), 0) fills all 256 bytes of Msg with zero, length byte and all, so Msg is the empty string. Why not simply Msg := ''?
Because Write(F, Msg) writes the whole variable: all 256 bytes, not just the characters in use. After Msg := '' the bytes past the length still hold the last message, and they go to the disc with the next one. A file of LAMP, SWORD and KEY written that way holds KEY followed by RD, left over from SWORD. The program never sees them, but they are on the disc. FillChar makes every unused byte zero.
A typed file of strings uses the declared length for every record. The 27 messages hold 2,652 characters between them, but the records take 6,912 bytes, and the file 7,040 on the disc. Over half of it is empty space.
On a disc with 110k free that does not matter, and a program that waits two seconds for every message matters a great deal. Part two's last two sections try to win the space back.
program SeekMsg;
type
Str255 = string[255];
var
F: file of Str255;
Msg: Str255;
procedure Wrap(S: Str255);
var
P: Integer;
begin
S := S + '|';
while S <> '' do
begin
P := Pos('|', S);
if P > 40 then
begin
P := 40;
while S[P] <> ' ' do
P := P - 1;
end;
Writeln(Copy(S, 1, P - 1));
Delete(S, 1, P);
end;
end;
procedure Say(N: Integer);
begin
Seek(F, N - 1);
Read(F, Msg);
Wrap(Msg);
end;
begin
Assign(F, 'BEACON.MSG');
Reset(F);
Writeln('Go');
Say(1);
Say(27);
Say(14);
Close(F);
end.
Starting from
A new work file SEEKMSG, on the primer's disc.
What you should see
The same three messages as S12, with no pause before any of them. The logbook comes out in two paragraphs, broken where the | is:
...store, but the door is stuck fast
again."
"Oct 13. Gale. Going over to the
mainland for oil. ...
Seek(F, N - 1) to Seek(F, N). What is printed first, and what happens when the program asks for message 27?Say(14) to Say(28). There are 27 messages. What happens?Writeln('Go') to Writeln(FileSize(F), ' messages').13.1 Print the length of every message, then the total, and how many bytes the records take altogether (FileSize(F) * SizeOf(Msg)).
13.2 Read message numbers typed at the keyboard and print each one, until 0. Ignore numbers that are not messages.
13.3 Copy every message out of BEACON.MSG into a new text file, MSG.TXT, one message to a line. Use D to see what it costs on the disc.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
I/O error 99 | Reading a record past the end of the file. The messages are numbered 1 to 27, and the records 0 to 26. |
| Every message is the next one along | Seek(F, N) for Seek(F, N - 1). |
I/O error 01 | BEACON.MSG is not on the disc. Run MAKEMSG (or S17's MAKEDAT) to make it. |
A file of records goes straight to any message with Seek: a few hundredths of a second, against up to two seconds reading a text file. The price is space: every record is the full declared length, over half of it empty here. FillChar clears a record before it is filled, so nothing left over goes to the disc.
S14, Three Letters In Two Bytes: winning the space back, Zork's way.
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.