Turbo Pascal Text Adventure Primer cover: BEACON, the adventure the primer builds in Turbo Pascal 2.0, mid-game on the Tatung Einstein
← Back to Modules
module
24

Appendix II: Worked Solutions

One tested answer to each exercise. There are other right answers: if yours does what the exercise asks, it is right.

S3. Strings Up Close

3.1

program Chop;
type
  Str20 = string[20];
var
  S: Str20;

procedure Trim(var S: Str20);
begin
  while (Length(S) > 0) and
        (S[Length(S)] = ' ') do
    S[0] := Pred(S[0]);
end;

begin
  S := 'LAMP     ';
  Writeln('[', S, '] ', Length(S));
  Trim(S);
  Writeln('[', S, '] ', Length(S));
end.

What you should see:

[LAMP     ] 9
[LAMP] 4

3.2

program Back;
var
  S: string[20];
  I: Integer;
begin
  S := 'LANTERN';
  for I := Length(S) downto 1 do
    Write(S[I]);
  Writeln;
end.

What you should see:

NRETNAL

3.3

program Rooms;
var
  Names: array[1..50] of string[30];
begin
  Writeln('One name: ',
          SizeOf(Names[1]), ' bytes');
  Writeln('All fifty: ',
          SizeOf(Names), ' bytes');
end.

What you should see:

One name: 31 bytes
All fifty: 1550 bytes

S4. Reading The Command, Two Ways

4.1 Start from TWOWAYS, the section's program.

Change:

    else if (Ch in [' '..'Z'])

to:

    else if (Ch in [' ', 'A'..'Z'])

What you should see:

Readln> SKIP
[SKIP]
GetLine> GO  NORTH
[GO  NORTH]

4.2 Start from TWOWAYS, the section's program.

After the line

    end

add:

    else if Ch = #24 then
      while Length(S) > 0 do
      begin
        Write(#8, ' ', #8);
        S[0] := Pred(S[0]);
      end

What you should see:

Readln> SKIP
[SKIP]
GetLine> LOOK
[LOOK]

4.3 Start from TWOWAYS, the section's program.

Take out:

type
  Str30 = string[30];

Change:

  Line: Str30;

procedure GetLine(var S: Str30);
var
  Ch: Char;

to:

  Line: string[30];

Change:

  S := '';
  repeat
    Read(Kbd, Ch);
    Ch := UpCase(Ch);
    if (Ch in [#8, #25])
       and (Length(S) > 0) then
    begin
      Write(#8, ' ', #8);
      S[0] := Pred(S[0]);
    end
    else if (Ch in [' '..'Z'])
       and (Length(S) < 30) then
    begin
      Write(Ch);
      S := S + Ch;
    end;
  until Ch = #13;
  Writeln;
end;

begin
  Write('Readln> ');

to:

  Write('Command> ');
  BufLen := 10;

Change:

  Writeln('[', Line, ']');
  Write('GetLine> ');
  GetLine(Line);
  Writeln('[', Line, ']');

to:

  Writeln('[', Line, '] ', Length(Line));

What you should see:

Command> TAKE THE L
[TAKE THE L] 10

S5. Tidying It Up

5.1 Start from TIDIER, the section's program.

After the line

end;

add:

function Words(S: Str40): Integer;
var
  I, N: Integer;
begin
  if S = '' then
    N := 0
  else
    N := 1;
  for I := 1 to Length(S) do
    if S[I] = ' ' then
      N := N + 1;
  Words := N;
end;

Change:

    Writeln('[', Line, ']');

to:

    Writeln('[', Line, '] ',
            Words(Line), ' words');

What you should see:

[TAKE THE LAMP] 3 words
[N] 1 words
[LOOK THEN GO NORTH] 4 words
[TURN DIAL TO] 3 words
[] 0 words

5.2 Start from TIDIER, the section's program.

Change:

    Ch := UpCase(S[I]);

to:

    Ch := S[I];
    if Ch in ['a'..'z'] then
      Ch := Chr(Ord(Ch) - 32);

What you should see:

[TAKE THE LAMP]
[N]
[LOOK THEN GO NORTH]
[TURN DIAL TO]
[]

5.3 Start from TIDIER, the section's program.

After the line

    Tidy(Line);

add:

    if Pos('PLEASE ', Line) = 1 then
      Delete(Line, 1, 7);

What you should see:

[OPEN THE DOOR]
[GO NORTH]
[PLEASED TO MEET YOU]
[]

S6. Splitting Into Words, Two Ways

6.1 Start from SPLIT, the section's program.

After the lines

procedure Show;
var
  I: Integer;
begin

add:

  Writeln;

Change:

    Write('[', W[I], ']');
  Writeln;

to:

    Writeln(I, ': ', W[I]);

What you should see:

Go
Pos:
1: TAKE
2: THE
3: BRASS
4: LANTERN
Walk:
1: TAKE
2: THE
3: BRASS
4: LANTERN

6.2

program Ends;
type
  Str40 = string[40];
  Str12 = string[12];
var
  Line: Str40;
  W: array[1..20] of Str12;
  N, I, K: Integer;

procedure SplitPos(S: Str40);
var
  P: Integer;
begin
  N := 0;
  S := S + ' ';
  while S <> '' do
  begin
    P := Pos(' ', S);
    if P > 1 then
    begin
      N := N + 1;
      W[N] := Copy(S, 1, P - 1);
    end;
    Delete(S, 1, P);
  end;
end;

procedure SplitWalk(var S: Str40);
var
  I: Integer;
begin
  N := 0;
  for I := 1 to Length(S) do
    if S[I] <> ' ' then
    begin
      if (I = 1) or (S[I - 1] = ' ') then
      begin
        N := N + 1;
        W[N] := '';
      end;
      W[N] := W[N] + S[I];
    end;
end;

procedure SplitEnds(var S: Str40);
var
  I, Start: Integer;
begin
  N := 0;
  I := 1;
  while I <= Length(S) do
  begin
    while (I <= Length(S)) and
          (S[I] = ' ') do
      I := I + 1;
    Start := I;
    while (I <= Length(S)) and
          (S[I] <> ' ') do
      I := I + 1;
    if I > Start then
    begin
      N := N + 1;
      W[N] := Copy(S, Start, I - Start);
    end;
  end;
end;

begin
  Line := 'TAKE THE  BRASS LANTERN';
  Writeln('Go');
  for K := 1 to 500 do
    SplitPos(Line);
  Writeln('Pos done');
  for K := 1 to 500 do
    SplitWalk(Line);
  Writeln('Walk done');
  for K := 1 to 500 do
    SplitEnds(Line);
  Writeln('Ends done');
  for I := 1 to N do
    Write('[', W[I], ']');
  Writeln;
end.

What you should see:

Go
Pos done
Walk done
Ends done
[TAKE][THE][BRASS][LANTERN]

About 6 seconds for 500, slower than both: building the word with one Copy saves the letter-by-letter +, but the loops round it, written in Pascal, cost more.

6.3 Start from SPLIT, the section's program.

After the lines

  Write('Walk: ');
  Show;

add:

  Line := 'PUT THE KEY IN THE LOCK';
  SplitPos(Line);
  K := 0;
  for N := N downto 1 do
    if W[N] = 'THE' then
      K := K + 1;
  Writeln('THE ', K, ' times');

What you should see:

Go
Pos: [TAKE][THE][BRASS][LANTERN]
Walk: [TAKE][THE][BRASS][LANTERN]
THE 2 times

S7. Recognising Words

7.1

program Ambig;
const
  Count = 12;
  Sig = 2;
type
  Str12 = string[12];
const
  Vocab: array[1..Count] of Str12 =
    ('NORTH', 'SOUTH', 'TAKE', 'DROP',
     'LOOK', 'LANTERN', 'LAMP',
     'LOGBOOK', 'MATCHES', 'KEY',
     'CROWBAR', 'OIL');
var
  W: Str12;

function Whole(W: Str12): Integer;
var
  I, Found: Integer;
begin
  Found := 0;
  for I := 1 to Count do
    if Vocab[I] = W then
      Found := I;
  Whole := Found;
end;

function First(W: Str12): Integer;
var
  I, Found, Hits: Integer;
begin
  Found := 0;
  Hits := 0;
  for I := 1 to Count do
    if Copy(Vocab[I], 1, Sig) =
       Copy(W, 1, Sig) then
    begin
      Found := I;
      Hits := Hits + 1;
    end;
  if Hits > 1 then
    Found := -1;
  First := Found;
end;

begin
  repeat
    Write('Word? ');
    Readln(W);
    Writeln('Whole ', Whole(W),
            '  First ', First(W));
  until W = '';
end.

What you should see:

Word? LANTERN
Whole 6  First -1
Word? LA
Whole 0  First -1
Word? OIL
Whole 12  First 12
Word? LO
Whole 0  First -1
Word?
Whole 0  First 0

7.2 Start from KNOW, the section's program.

Change:

  Sig = 4;

to:

  Sig = 6;

After the lines

  First := Found;
end;

add:

var
  I: Integer;

After the lines


begin

add:

  for I := 1 to Count do
    Vocab[I] := Copy(Vocab[I], 1, Sig);

After the line

    Readln(W);

add:

    W := Copy(W, 1, Sig);

What you should see:

Word? LANTERNXYZ
Whole 6  First 6
Word? LANTER
Whole 6  First 6
Word? LANTEX
Whole 0  First 0
Word? KEY
Whole 10  First 10
Word?
Whole 0  First 0

7.3 Start from KNOW, the section's program.

Change:

    Writeln('Whole ', Whole(W),
            '  First ', First(W));

to:

    if First(W) > 0 then
      Writeln('You mean ',
              Vocab[First(W)])
    else
      Writeln('I don''t know ', W);

What you should see:

Word? LANT
You mean LANTERN
Word? LANTERNS
You mean LANTERN
Word? LAMP
You mean LAMP
Word? KEYS
I don't know KEYS
Word? MATCH
You mean MATCHES
Word? LOGS
I don't know LOGS
Word?
I don't know

S8. Words Into Numbers

8.1

program Examine;
type
  Str12 = string[12];
  Verb = (Nothing, Go, Take, Drop,
          Look, Inv, Quit, Exam);
const
  Count = 13;
  Words: array[1..Count] of Str12 =
    ('GO', 'WALK', 'TAKE', 'GET',
     'DROP', 'LOOK', 'L', 'INVENTORY',
     'I', 'QUIT', 'STOP',
     'EXAMINE', 'X');
  Means: array[1..Count] of Verb =
    (Go, Go, Take, Take, Drop, Look,
     Look, Inv, Inv, Quit, Quit,
     Exam, Exam);
var
  W: Str12;
  V: Verb;

function Find(W: Str12): Verb;
var
  I: Integer;
begin
  Find := Nothing;
  for I := 1 to Count do
    if Words[I] = W then
      Find := Means[I];
end;

begin
  repeat
    Write('> ');
    Readln(W);
    V := Find(W);
    Write('Token ', Ord(V), ': ');
    case V of
      Go:   Writeln('You walk.');
      Take: Writeln('Taken.');
      Drop: Writeln('Dropped.');
      Look: Writeln('You look.');
      Inv:  Writeln('Empty hands.');
      Quit: Writeln('Goodbye.');
      Exam: Writeln('You see nothing special.');
      Nothing:
        Writeln('I don''t know ', W);
    end;
  until V = Quit;
end.

What you should see:

Token 7: You see nothing special.
Token 7: You see nothing special.
Token 6: Goodbye.

8.2 Start from TOKENS, the section's program.

After the line

  V: Verb;

add:

  Total: array[Verb] of Integer;
  I: Integer;

After the lines


begin

add:

  for V := Nothing to Quit do
    Total[V] := 0;
  for I := 1 to Count do
    Total[Means[I]] := Total[Means[I]] + 1;
  for V := Go to Quit do
    Write(Total[V], ' ');
  Writeln;

What you should see:

2 2 1 2 2 2
Token 2: Taken.
Token 2: Taken.
Token 4: You look.
Token 5: Empty hands.
Token 0: I don't know JUMP
Token 6: Goodbye.

8.3 Start from TOKENS, the section's program.

After the line

     Look, Inv, Inv, Quit, Quit);

add:

  Name: array[Verb] of Str12 =
    ('NOTHING', 'GO', 'TAKE', 'DROP',
     'LOOK', 'INVENTORY', 'QUIT');

Change:

    Write('Token ', Ord(V), ': ');

to:

    Write(W, ' means ', Name[V], ': ');

What you should see:

GET means TAKE: Taken.
TAKE means TAKE: Taken.
L means LOOK: You look.
I means INVENTORY: Empty hands.
JUMP means NOTHING: I don't know JUMP
STOP means QUIT: Goodbye.

S9. Finding A Word Faster

9.1 Start from FASTER, the section's program.

Change:

  Count, K, N: Integer;

to:

  Count, K, N, Tries: Integer;

After the lines

  while (Found = 0) and (I <= Count) do
  begin

add:

    Tries := Tries + 1;

After the line

    Mid := (Lo + Hi) div 2;

add:

    Tries := Tries + 1;

Change:

  for K := 1 to 300 do
    N := Straight('YELL');
  Writeln('Straight: ', N);
  for K := 1 to 300 do
    N := Binary('YELL');
  Writeln('Binary: ', N);

to:

  Tries := 0;
  N := Straight('YELL');
  Writeln('Straight: ', Tries);
  Tries := 0;
  N := Binary('YELL');
  Writeln('Binary: ', Tries);

What you should see:

121 words
Straight: 121
Binary: 7

9.2 Start from FASTER, the section's program.

Change:

  for K := 1 to 300 do
    N := Straight('YELL');
  Writeln('Straight: ', N);
  for K := 1 to 300 do
    N := Binary('YELL');
  Writeln('Binary: ', N);

to:

  N := 0;
  for K := 2 to Count do
    if Vocab[K - 1] >= Vocab[K] then
    begin
      Writeln('Out of order: ', Vocab[K]);
      N := N + 1;
    end;
  Writeln(N, ' out of order');

What you should see:

121 words
0 out of order

9.3 Start from FASTER, the section's program.

After the line

  F: Text;

add:

  W: Str10;

Change:

  for K := 1 to 300 do
    N := Straight('YELL');
  Writeln('Straight: ', N);
  for K := 1 to 300 do
    N := Binary('YELL');
  Writeln('Binary: ', N);

to:

  repeat
    Write('Word? ');
    Readln(W);
    N := Binary(W);
    if N > 0 then
      Writeln(W, ' is word ', N)
    else
      Writeln('Not known');
  until W = '';

What you should see:

121 words
Word? LANTERN
LANTERN is word 63
Word? ZEBRA
Not known
Word? ABOUT
ABOUT is word 1
Word?
Not known

(typed: LANTERN, ZEBRA, ABOUT, then ENTER)

S10. Understanding The Sentence

10.1 Start from SENTENCE, the section's program.

After the line

  V, N1, P, N2: Integer;

add:

procedure Tidy(var S: Str40);
var
  T: Str40;
  I: Integer;
  Ch: Char;
begin
  T := '';
  for I := 1 to Length(S) do
  begin
    Ch := UpCase(S[I]);
    if not (Ch in ['A'..'Z']) then
      Ch := ' ';
    if (Ch <> ' ') or ((T <> '')
       and (T[Length(T)] <> ' ')) then
      T := T + Ch;
  end;
  S := T;
end;

After the line

    Readln(Line);

add:

    Tidy(Line);

What you should see:

TAKE LAMP
UNLOCK DOOR WITH KEY
There is no verb.

10.2 Start from SENTENCE, the section's program.

After the line

     Noise);

add:

  Same: array[1..Count] of Byte =
    (1, 1, 3, 4, 5, 6, 7, 8, 9, 10,
     11, 12, 13, 14, 15, 16);

Change:

          Verb: V := K;

to:

          Verb: V := Same[K];

What you should see:

TAKE LAMP
UNLOCK DOOR WITH KEY
What do you want to TAKE?
LOOK
I don't know SWORD
There is no verb.
FILL LAMP WITH OIL
There is no verb.

10.3 Start from SENTENCE, the section's program.

After the line

        Writeln('There is no verb.')

add:

      else if (P > 0) and (N2 = 0) then
        Writeln(Words[P], ' what?')

What you should see:

WITH what?
OPEN DOOR WITH CROWBAR
There is no verb.

S11. Text In The Program

11.1 Start from INARRAY, the section's program.

Change:

  Msg: array[1..3] of Str25 =

to:

  Msg: array[1..4] of Str25 =

Change:

     'A wooden jetty.');

to:

     'A wooden jetty.',
     'A cramped shed.');

Change:

  for N := 1 to 3 do

to:

  for N := 1 to 4 do

What you should see:

You are on the beach.
A small cove.
A wooden jetty.
A cramped shed.

11.2 Start from INARRAY, the section's program.

Change:

  Str25 = string[25];

to:

  Str25 = string[255];

What you should see:

You are on the beach.
A small cove.
A wooden jetty.

Code: 865 bytes, against 177: each of the three entries now takes 256 bytes, 230 more than before.

11.3 Start from INCODE, the section's program.

After the line

    3: Writeln('A wooden jetty.');

add:

  else
    Writeln('No message ', N);

Change:

  for N := 1 to 3 do

to:

  for N := 1 to 5 do

What you should see:

You are on the beach.
A small cove.
A wooden jetty.
No message 4
No message 5

S12. A File Of Messages

12.1 Start from FROMFILE, the section's program.

After the lines

    Readln(T, Line);
  end;
end;

add:

var
  Line: Str255;

Change:

  Writeln('Go');
  Say(1);
  Say(27);
  Say(14);

to:

  Reset(T);
  while not Eof(T) do
  begin
    Readln(T, Line);
    if Copy(Line, 1, 5) = '*ROOM' then
      Writeln(Copy(Line, 7, 30));
  end;

What you should see:

Beach
Cove
Jetty
Store Shed
Cliff Path
Front Room
Kitchen
Bedroom
Lighthouse Base
Stairs
Lamp Room
Gallery

12.2 Start from FROMFILE, the section's program.

After the lines

    Readln(T, Line);
  end;
end;

add:

var
  Line: Str255;
  Lines, Chars: Integer;

Change:

  Writeln('Go');
  Say(1);
  Say(27);
  Say(14);

to:

  Reset(T);
  Lines := 0;
  Chars := 0;
  while not Eof(T) do
  begin
    Readln(T, Line);
    Lines := Lines + 1;
    Chars := Chars + Length(Line);
  end;

After the line

  Close(T);

add:

  Writeln(Lines, ' lines, ', Chars,
          ' characters');

What you should see:

71 lines, 3399 characters

12.3

program FromFile;
type
  Str255 = string[255];
var
  T: Text;

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(Name: Str255);
var
  Line: Str255;
  Found: Boolean;
begin
  Reset(T);
  Found := False;
  while not Found and not Eof(T) do
  begin
    Readln(T, Line);
    Found := (Copy(Line, 1, 1) = '*')
      and (Pos(Name, Line) > 0);
  end;
  Readln(T, Line);
  while Copy(Line, 1, 1) <> '*' do
  begin
    if (Line <> '') and
       not (Line[1] in ['0'..'9']) then
      Wrap(Line);
    Readln(T, Line);
  end;
end;

begin
  Assign(T, 'BEACON.TXT');
  Writeln('Go');
  Say('Logbook');
  Say('Ship');
  Close(T);
end.

What you should see:

Go
The keeper's log. The last entries
read: "Oct 12. Glass falling. Lamp
trimmed, oil low. Spare can in the
store, but the door is stuck fast
again."
"Oct 13. Gale. Going over to the
mainland for oil. Locked the tower. Key
in my drawer as usual."
The ship is close now. You can see her
lights rising and falling in the swell.

S13. Straight To The Message

13.1 Start from SEEKMSG, the section's program.

After the line

  Msg: Str255;

add:

  Total: Integer;

Change:

  Writeln('Go');
  Say(1);
  Say(27);
  Say(14);

to:

  Total := 0;
  while not Eof(F) do
  begin
    Read(F, Msg);
    Write(Length(Msg):4);
    Total := Total + Length(Msg);
  end;
  Writeln;
  Writeln('Text: ', Total, ' of ',
          FileSize(F) * SizeOf(Msg));

What you should see:

 209 122  92  93 172 113 108  76 131  86
 151 164  36 243  24  49  68  53  72  49
 237  53  34  50  48  41  78
Text: 2652 of 6912

13.2 Start from SEEKMSG, the section's program.

After the line

  Msg: Str255;

add:

  N: Integer;

Change:

  Writeln('Go');
  Say(1);
  Say(27);
  Say(14);

to:

  repeat
    Write('Message? ');
    Readln(N);
    if (N >= 1) and (N <= FileSize(F))
    then
      Say(N);
  until N = 0;

What you should see:

Message? 15
The iron door is locked.
Message? 99
Message? 3
A wooden jetty, slick with spray. A
rowing boat bumps against the piles.
The beach is north.
Message? 0

13.3 Start from SEEKMSG, the section's program.

After the line

  Msg: Str255;

add:

  T: Text;

Change:

  Writeln('Go');
  Say(1);
  Say(27);
  Say(14);

to:

  Assign(T, 'MSG.TXT');
  Rewrite(T);
  while not Eof(F) do
  begin
    Read(F, Msg);
    Writeln(T, Msg);
  end;
  Close(T);

After the line

  Close(F);

add:

  Writeln('Done');

What you should see:

Done

D then lists MSG TXT, and the disc has 104k left: 6k less, 2k for the program and 4k for the text.

S14. Three Letters In Two Bytes

14.1 Start from SQUEEZE, the section's program.

After the line

      Same := False;

add:

    Write(Length(Msg):4, 2 * NW:4);
    if K mod 4 = 0 then
      Writeln;

After the lines

    Bytes := Bytes + 2 * NW;
  end;

add:

  Writeln;

What you should see:

 209 142 122  84  92  64  93  64
 172 118 113  80 108  76  76  52
 131  90  86  60 151 104 164 112
  36  26 243 184  24  18  49  34
  68  48  53  36  72  50  49  36
 237 162  53  38  34  24  50  36
  48  34  41  28  78  54
Characters: 2652
Packed bytes: 1854
All came back: TRUE
Go

14.2 Start from SQUEEZE, the section's program.

After the line

  Same: Boolean;

add:

  Escapes: Integer;

After the lines

    else
    begin

add:

      Escapes := Escapes + 1;

After the line

  Same := True;

add:

  Escapes := 0;

After the line

  Writeln('All came back: ', Same);

add:

  Writeln('Escaped: ', Escapes);

What you should see:

Characters: 2652
Packed bytes: 1854
All came back: TRUE
Escaped: 14
Go

14.3 Start from SQUEEZE, the section's program.

After the line

  W[NW] := W[NW] or $8000;

add:

end;

procedure Show;
var
  I, J, C, Mode, Hi: Integer;
  Done: Boolean;
begin
  Mode := 0;
  I := 0;
  repeat
    I := I + 1;
    Done := W[I] < 0;
    for J := 2 downto 0 do
    begin
      C := (W[I] shr (5 * J)) and 31;
      case Mode of
        0: case C of
             0: Write(' ');
             1..26: Write(Chr(C + 96));
             27: Mode := 1;
             28: Write('.');
             29: Write(',');
             30: Mode := 2;
           end;
        1: begin
             Write(Chr(C + 64));
             Mode := 0;
           end;
        2: begin
             Hi := C;
             Mode := 3;
           end;
        3: begin
             Write(Chr(Hi shl 5 + C));
             Mode := 0;
           end;
      end;
    end;
  until Done;
  Writeln;

Change:

  for K := 1 to 20 do
    Back := Unpack;
  Writeln('Unpacked');
  Writeln(Copy(Back, 1, 38));

to:

  for K := 1 to 3 do
    Show;
  Writeln('Shown');

What you should see:

y from the rocks. You have saved her.
You strike a match and hold it to the wi
ck. With a soft roar the great lamp blaz
es into life, and its beam sweeps out ac
ross the water. Far below, the ship's li
ghts swing slowly round as she turns awa
y from the rocks. You have saved her.
You strike a match and hold it to the wi
ck. With a soft roar the great lamp blaz
es into life, and its beam sweeps out ac
ross the water. Far below, the ship's li
ghts swing slowly round as she turns awa
y from the rocks. You have saved her.
Shown

Three Shows take about 2.8 seconds, printing included. Show writes straight to the screen, so the lines break at the 40th column, not at spaces.

S15. Common Words By Number

15.1 Start from COMMON, the section's program.

After the line

  Same: Boolean;

add:

  Used: array[1..Count] of Integer;

After the line

      T := T + Chr(127 + Hit);

add:

      Used[Hit] := Used[Hit] + 1;

After the line

  Same := True;

add:

  for K := 1 to Count do
    Used[K] := 0;

After the line

  Writeln('All came back: ', Same);

add:

  for K := 1 to Count do
    Write(Used[K]:4);
  Writeln;

What you should see:

Characters: 2652
Encoded bytes: 2089
All came back: TRUE
  51  23  11  14  18  11  14   6   5   4
   4   4   8  16   7   3
Go

15.2 Start from COMMON, the section's program.

Change:

  Writeln('Go');
  for K := 1 to 20 do
    Back := Decode(Code);
  Writeln('Decoded');
  Writeln(Copy(Back, 1, 38));

to:

  Seek(F, 0);
  Read(F, Msg);
  Code := Encode(Msg);
  for K := 1 to Length(Code) do
    if Code[K] >= #128 then
      Write('{', Ord(Code[K]) - 127, '}')
    else
      Write(Code[K]);
  Writeln;

What you should see:

Characters: 2652
Encoded bytes: 2089
All came back: TRUE
{6}are on {14}strip {7}shingle at {1}foo
t {7}{1}cliffs. Wreckage {16}your boat r
olls {13}{1}surf. A path climbs north. {
2}beach runs west {15}{14}cove {4}south
{15}{14}jetty, {4}{14}store shed stands
{15}{1}east.

15.3 Start from COMMON, the section's program.

Take out:

  Code := Encode(Msg);

After the line

  Writeln('Go');

add:

  for K := 1 to 5 do
    Code := Encode(Msg);
  Writeln('Five done');

What you should see:

Characters: 2652
Encoded bytes: 2089
All came back: TRUE
Go
Five done

Five encodings take about 10 seconds: two seconds each.

S16. How The Real Games Did It

16.1 Start from ZWORD, the section's program.

After the line

  Write(W, ': ');

add:

  for I := 1 to 6 do
    Write(C[I], ' ');
  Write('= ');

What you should see:

Word? MAILBOX
MAILBOX: 18 6 14 17 7 20 = 48 CE C4 F4
Word? LAMP
LAMP: 17 6 18 21 5 5 = 44 D2 D4 A5
Word? LANTERN
LANTERN: 17 6 19 25 10 23 = 44 D3 E5 57
Word?

16.2

program Unword;
var
  A, B, I, C: Integer;

procedure Letters(X: Integer);
var
  J: Integer;
begin
  for J := 2 downto 0 do
  begin
    C := (X shr (5 * J)) and 31;
    if C >= 6 then
      Write(Chr(C + 59));
  end;
end;

begin
  A := $48CE;
  B := $C4F4;
  Letters(A);
  Letters(B);
  Writeln;
  A := $44D2;
  B := $D4A5;
  Letters(A);
  Letters(B);
  Writeln;
end.

What you should see:

MAILBO
LAMP

16.3 Start from ZWORD, the section's program.

After the lines

  Writeln;
end;

add:

var
  F: Text;
  Prev, Cut: Str12;
  N: Integer;

Change:

  repeat
    Write('Word? ');
    Readln(W);
    if W <> '' then
      Entry(W);
  until W = '';

to:

  Assign(F, 'VOCAB.TXT');
  Reset(F);
  Prev := '';
  N := 0;
  while not Eof(F) do
  begin
    Readln(F, W);
    Cut := Copy(W, 1, 6);
    if Cut = Prev then
    begin
      Writeln(W, ' is ', Cut);
      N := N + 1;
    end;
    Prev := Cut;
  end;
  Close(F);
  Writeln(N, ' clashes');

What you should see:

0 clashes

No two of VOCAB.TXT's words share their first six letters, so Zork's way would work for it too.

S17. The World As Data

Each answer is a change to BEACON1, the program as the section left it.

17.1

Change:

  Here := 1;
  Look;

to:

  for Here := 1 to Rooms do
    Writeln(Here, ' ', Map[Here].Name);

What you should see: Prints 1 Beach to 12 Gallery, one to a line.

17.2

After the lines

    Exits: array[1..6] of Byte;
  end;

add:

const
  Dir: array[1..6] of string[5] =
    ('North', 'South', 'East',
     'West', 'Up', 'Down');

After the line

  Map: array[1..Rooms] of Room;

add:

  D: Integer;

After the line

  Look;

add:

  for D := 1 to 6 do
    if Map[Here].Exits[D] > 0 then
      Writeln(Dir[D], ' to ',
        Map[Map[Here].Exits[D]].Name);

What you should see: After the beach's description: North to Cliff Path, South to Jetty, East to Store Shed, West to Cove.

17.3

Change:

  Here := 1;
  Look;

to:

  Writeln(FileSize(Msg),
          ' messages in BEACON.MSG');

What you should see: 27 messages in BEACON.MSG.

S18. Moving And Looking

Each answer is a change to BEACON2, the program as the section left it.

18.1

After the line

procedure Walk(D: Integer);

add:

const
  Way: array[1..6] of Byte =
    (35, 44, 15, 52, 50, 11);

Change:

    Writeln('You can''t go that way.')

to:

  begin
    Write('You can go:');
    for D := 1 to 6 do
      if Map[Here].Exits[D] > 0 then
        Write(' ', Words[Way[D]]);
    Writeln('.');
  end

What you should see: In the shed, E: You can go: WEST.

18.2

After the line

  Line: Str40;

add:

  Moves: Integer;

After the line

  Quit := False;

add:

  Moves := 0;

After the line

    GetLine(Line);

add:

    Moves := Moves + 1;

After the line

  until Quit;

add:

  Writeln('Moves: ', Moves);

What you should see: N, S, Q: Moves: 3.

18.3

After the line

procedure Look;

add:

var
  I: Integer;
  N: Str16;

Change:

  Writeln(Map[Here].Name);

to:

  N := Map[Here].Name;
  for I := 1 to Length(N) do
    N[I] := UpCase(N[I]);
  Writeln(N);

What you should see: BEACH, CLIFF PATH and so on, in capitals.

S19. Things

Each answer is a change to BEACON3, the program as the section left it.

19.1

After the lines

    Writeln('  nothing.');
end;

add:

function Held: Integer;
var
  T, N: Integer;
begin
  N := 0;
  for T := 1 to Things do
    if Carried(T) then
      N := N + 1;
  Held := N;
end;

After the line

    Writeln('It isn''t here.')

add:

  else if Held >= 4 then
    Writeln('You can''t carry any more.')

What you should see: With the crowbar, lantern, oil can and logbook carried, TAKE MATCHES in the kitchen: You can't carry any more.

19.2

Change:

    Writeln('Dropped.');

to:

    Writeln('You drop ', Obj[T].Name,
            '.');

What you should see: DROP CROWBAR: You drop a crowbar.

19.3

After the line

    Say(27)

add:

  else if (N1 >= 20) and (N1 <= 25)
          and Near(N1 - 19) then
    Writeln('It is ', Obj[N1 - 19].Name,
            '.')

What you should see: On the jetty, EXAMINE LANTERN: It is a lantern.

S20. Locks, Lamps And Logbooks

Each answer is a change to BEACON4, the program as the section left it.

20.1

After the line

  Say(Here);

add:

  if (Here = 10) and Lit and Carried(2)
  then
    Writeln('Your lantern lights the',
            ' way up.');

What you should see: On the stairs with the lantern lit: the description, then Your lantern lights the way up.

20.2

After the lines

      Won := True;
    end;
  end

add:

  else if N1 = 24 then
    Writeln('A match flares and dies.')

What you should see: LIGHT MATCHES, carrying them: A match flares and dies.

20.3

After the lines

    Writeln('You see nothing special.');
end;

add:

procedure Hint;
begin
  if not ShedOpen then
    Writeln('The shed must open somehow.')
  else if not TowerOpen then
    Writeln('Has the keeper a key?')
  else if not Lit then
    Writeln('The stairs need a light.')
  else
    Writeln('The great lamp needs oil.');
end;

Change:

    19: Writeln('Nothing happens.');

to:

    19: Hint;

What you should see: XYZZY at the start: The shed must open somehow.; after the shed is open: Has the keeper a key?

S21. The Finished Game

Each answer is a change to BEACON5, the program as the section left it.

21.1

After the line

  Writeln('You took ', Moves, ' moves.');

add:

  Writeln('Puzzles solved: ',
          Ord(ShedOpen) + Ord(TowerOpen) +
          Ord(Lit) + Ord(Won), ' of 4');

What you should see: N, Q: You took 2 moves., Puzzles solved: 0 of 4.

21.2

After the line

  Load;

add:

  repeat

After the line

  Writeln('You took ', Moves, ' moves.');

add:

  Write('Play again (Y/N)? ');
  Read(Kbd, Ch);
  Writeln;
  until UpCase(Ch) <> 'Y';

What you should see: Q, then Y: the title again, and a new game. N ends it.

21.3 At the menu, O, C, Q, then C: Turbo compiles to .COM (Free: 43966 bytes for the answer to 21.2). Q, and at 0: type the program's name: the title appears, and N at the end brings you back to 0:.

A Way Through BEACON

For 20.x and 21.x, and for anyone stuck. From the beach:

W, TAKE CROWBAR, E, S, TAKE THE LANTERN, N, E, OPEN DOOR WITH CROWBAR, E, TAKE OIL, W, N, W, TAKE LOGBOOK, READ LOGBOOK, S, OPEN CUPBOARD, TAKE MATCHES, N, N, OPEN DRAWER, TAKE KEY, S, E, N, UNLOCK THE DOOR WITH THE KEY, U, LIGHT LANTERN, U, FILL LAMP WITH OIL, LIGHT LAMP.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.