home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol134 / animals.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1984-04-29  |  39.6 KB  |  1,192 lines

  1. PROGRAM animals;    {Requires Pascal/Z 3.3 or later, CP/M 2.2 or later}
  2.                     {$E+}
  3. CONST
  4.     filepfx  = 'BEASTS';
  5.     inviter  = 'Would you like to play the animal guessing game';
  6.     insulted = 'Well, exCUUUUSE ME!!  So you don''t want to play, huh?';
  7.     start1   = 'You think of an animal, and I''ll try to guess what it is.';
  8.     start2   = 'When you''re ready to begin, press the <RETURN> key.';
  9.     askagain = 'Would you like to play another round';
  10.     maxlen   = 240;
  11.     bufsize  = 256;
  12.     maxx     = 256;                     {No. entries per XFILE block  }
  13.  
  14. TYPE
  15.     x$shorti = 0..255;                  {One-byte integer             }
  16.     questx   = 0..maxlen;               {Index to a question text     }
  17.     bufx     = 1..bufsize;              {Index to a QFILE buffer      }
  18.     dirx     = 1..maxx;                 {Index to an XFILE block      }
  19.     recty    = (quest,ctl);
  20.     qstring  = string maxlen;
  21.     question = RECORD;                  {QUESTION logical record      }
  22.         ident    : integer;             {Record number (1..MAXINT)    }
  23.         typcode  : recty;               {Record type                  }
  24.         CASE recty OF
  25.             quest: (nextyes : integer;  {Next Q if answer = yes       }
  26.                     nextno  : integer;  {Next Q if answer = no        }
  27.                     query   : qstring); {Current question             }
  28.             ctl  : (lastq   : integer;  {Last recno in QFILE          }
  29.                     lastqbl : integer;  {Last QFILE block used        }
  30.                     lastxbl : integer;  {Last XFILE block used        }
  31.                     beastct : integer)  {No. animals known            }
  32.         END; {question record}
  33.  
  34.     buffer   = PACKED ARRAY [bufx] OF x$shorti;
  35.     qrec     = RECORD;
  36.         qentry   : buffer
  37.         END; {qrec record}
  38.     queryfile= file of qrec;
  39.  
  40.     xbuffr   = ARRAY [dirx] OF integer;
  41.     xrec     = RECORD;
  42.         xentry   : xbuffr
  43.         END; {xrec record}
  44.     directory= FILE OF xrec;
  45.  
  46.     filestring = string 14;
  47.     $string0   = string 0;
  48.     $string255 = string 255;
  49.     charset    = SET OF CHAR;
  50. {$L+}
  51. VAR
  52.     db       : text;        {Debugging output file                    }
  53.     dbugging : boolean;     {Is debugging active?                     }
  54.     moreokay : boolean;     {Indicator - keep playing?                }
  55.     runabort : boolean;     {Indicator - fatal error has occurred     }
  56.     zerochr  : char;        {One byte of binary zero                  }
  57.     vowels   : charset;     {Set of all vowels                        }
  58.     shiftup  : integer;     {Factor to shift from lower to upper case }
  59.     replytxt : qstring;     {Text of a console reply                  }
  60.     maxquery : integer;     {Maximum question number in file          }
  61.     highblok : integer;     {Relative block# of last QFILE block      }
  62.     highxblk : integer;     {Relative block# of last XFILE block      }
  63.     maxanimals : integer;   {No. animals file now knows               }
  64.     currblok   : integer;   {Relative block# - current QFILE block    }
  65.     currxblk   : integer;   {Relative block# - current XFILE block    }
  66.     qimage     : qrec;      {Current qfile block image                }
  67.     ximage     : xrec;      {Current xfile block image                }
  68.     currec     : question;  {Current question file record             }
  69.     i          : integer;
  70.  
  71.     qfile      : queryfile; {Questions file                           }
  72.     xfile      : directory; {Directory to Questions file              }
  73.  
  74. { - - - - - VIDEO TERMINAL CONTROL SEQUENCES - - - - - - - - - - - - -}
  75.     return    : CHAR;       {Return cursor to left edge of screen     }
  76.     bell      : CHAR;       {Ring bell (or alarm, if you prefer)      }
  77.     clear     : STRING 4;   {Clear screen                             }
  78.     reverse   : STRING 4;   {Shift to black-on-white display mode     }
  79.     invert    : STRING 4;   {Shift to white-on-black display mode     }
  80.     blink     : STRING 4;   {Start blinking-text area                 }
  81.     unblink   : STRING 4;   {End blinking-text area                   }
  82.     lndelete  : STRING 4;   {Delete current line                      }
  83.  
  84.  
  85. FUNCTION  length    (x: $string255):    integer;    EXTERNAL;
  86. FUNCTION  index     (x, y: $string255): integer;    EXTERNAL;
  87. PROCEDURE setlength (VAR x: $string0;  y: integer); EXTERNAL;
  88. {$L+}
  89. PROCEDURE setupvdt;
  90.  
  91. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  92. {* Initialize video terminal control sequences                       *}
  93. {* (This implementation is for Televideo 920C terminal)              *}
  94. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  95.  
  96. VAR
  97.     esc : CHAR;
  98.  
  99. BEGIN {setupvdt procedure}
  100.     esc     := CHR(27);
  101.     return  := CHR(13);
  102.     bell    := CHR(7);
  103.  
  104.     clear   := esc;
  105.     append(clear,'*');
  106.  
  107.     reverse := esc;
  108.     append(reverse,'j');
  109.  
  110.     invert  := esc;
  111.     append(invert,'k');
  112.  
  113.     blink   := esc;
  114.     append(blink,'^');
  115.  
  116.     unblink := esc;
  117.     append(unblink,'_');
  118.  
  119.     lndelete := esc;
  120.     append(lndelete,'R')
  121. END; {setupvdt procedure} {$L+}
  122. FUNCTION cnvrt (VAR arr: buffer;  pnt: bufx): integer;            {$C-}
  123.  
  124. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  125. {* Given buffer ARR, with PNT pointing to the leftmost of a pair of  *}
  126. {* entries in ARR, return the integer value of the two-byte pair     *}
  127. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  128.  
  129. CONST
  130.     maxint = 32767;
  131.  
  132. VAR
  133.     i : integer;
  134.  
  135. BEGIN {cnvrt function}
  136.     IF arr[pnt]>127
  137.       THEN
  138.         BEGIN
  139.           i := (256*(arr[pnt] MOD 128)) + arr[pnt+1];
  140.           cnvrt := i - maxint - 1
  141.         END
  142.       ELSE cnvrt := (256*arr[pnt]) + arr[pnt+1]
  143. END; {cnvrt function}
  144.  
  145. {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
  146.  
  147. PROCEDURE revert (VAR buff: buffer;  ptr: bufx;  x: integer);
  148. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  149. {* Given an integer X, store it as two bytes as location PTR in      *}
  150. {* buffer BUFF.  This procedure complements function CNVRT.          *}
  151. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  152.  
  153. BEGIN {revert}
  154.     buff[ptr]   := x DIV 256;
  155.     buff[ptr+1] := x MOD 256
  156. END; {revert procedure} {$L+}
  157. PROCEDURE error (errnumbr: integer);
  158.  
  159. CONST
  160.     set1 = 'I''ve just been told that error number ';
  161.     set2 = ' (whatever THAT means) has occurred.';
  162.     set3 = 'Ain''t that the pits?!!';
  163.     intro    = 'FATAL PROGRAM OR FILE ERROR.  DESCRIPTION:';
  164.     err1     = 'Invalid record number passed to GETRECORD procedure.';
  165.     err2     = 'Invalid block pointer found in .QQX file.';
  166.     err3     = 'Invalid block number passed to BLOKFETCH procedure.';
  167.     err4     = 'APPENDSEG1 procedure invoked for a too-full block.';
  168.     err5     = '.QQQ record not found where .QQX file says it should be.';
  169.     unknown  = '(Undefined error code)';
  170.  
  171. VAR
  172.     message  : string 75;
  173.  
  174. BEGIN {error procedure}
  175.     writeln;
  176.     writeln(set1, errnumbr:2, set2);
  177.     writeln(set3);
  178.     writeln;
  179.     writeln(intro);
  180.     IF errnumbr=1
  181.             THEN message := err1
  182.     ELSE IF errnumbr=2
  183.             THEN message := err2
  184.     ELSE IF errnumbr=3
  185.             THEN message := err3
  186.     ELSE IF errnumbr=4
  187.             THEN message := err4
  188.     ELSE IF errnumbr=5
  189.             THEN message := err5
  190.             ELSE message := unknown;
  191.     writeln('    ',message);
  192.     writeln;
  193.     runabort := true
  194. END; {error procedure} {$L+}
  195. FUNCTION getyes: boolean;
  196.  
  197. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  198. {* Secure from the console a reply of yes (y) or no (n).             *}
  199. {* Return "true" if yes, "false" otherwise.                          *}
  200. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  201.  
  202. LABEL 1;
  203.  
  204. CONST
  205.     suffix = '? (Y/N)  ';
  206.     prompt = '     Please reply yes (Y) or no (N):  ';
  207.     yes    = 'YES';
  208.     no     = 'NO';
  209.  
  210. VAR
  211.     reply    : string 10;
  212.     ans      : char;
  213.     gotreply : boolean;
  214.     messy    : BOOLEAN;
  215.  
  216. PROCEDURE keyin (VAR c:char); EXTERNAL;
  217.  
  218. BEGIN {getyes function}
  219.     write(suffix,invert);
  220.     gotreply := false;
  221.     messy    := FALSE;
  222.     WHILE gotreply=false DO
  223.       BEGIN {while}
  224.         keyin(ans);
  225.         IF ord(ans)=3       {Check for Control-C}
  226.           THEN GOTO 1;
  227.         CASE ans OF
  228.             'Y', 'y': BEGIN {YES processor}
  229.                         IF messy
  230.                           THEN WRITE(return,lndelete);
  231.                         WRITELN(yes);
  232.                         gotreply := TRUE;
  233.                         getyes := true
  234.                       END;  {YES processor}
  235.             'N', 'n': BEGIN {NO processor}
  236.                         IF messy
  237.                           THEN WRITE(return,lndelete);
  238.                         WRITELN(no);
  239.                         gotreply := TRUE;
  240.                         getyes := false
  241.                       END {NO processor}
  242.           END; {case}
  243.         IF NOT gotreply
  244.           THEN
  245.             BEGIN
  246.               IF messy
  247.                 THEN WRITE(return,lndelete,prompt);
  248.               WRITELN(bell,ans);
  249.               WRITE(blink,prompt,unblink);
  250.               messy := TRUE
  251.             END {then}
  252.       END; {while}
  253. 1:  {Exit here on Control-C }
  254. END;  {getyes function} {$L+}
  255. PROCEDURE shiftxt (VAR arr: buffer;
  256.                        org: bufx;
  257.                        len: bufx;
  258.                    VAR trg: qstring); {$C-}
  259. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  260. {* Append a sequence of characters from ARR to TRG.  Transcription   *}
  261. {* is of LEN consecutive bytes, beginning with byte ORG of ARR.      *}
  262. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  263.  
  264. VAR
  265.     i, j : integer;
  266.  
  267. BEGIN {shiftxt procedure}
  268.     i := 1;
  269.     j := org;
  270.     WHILE i<=len DO
  271.         BEGIN {while}
  272.             append(trg,CHR(arr[j]));
  273.             i := i + 1;
  274.             j := j + 1
  275.         END {while}
  276. END; {shiftxt procedure} {$L+}
  277. FUNCTION dirfetch (recno: integer): dirx;
  278. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  279. {* Given RECNO (logical record number of a desired QFILE record),    *}
  280. {* return the XIMAGE.XENTRY entry number for that record.            *}
  281. {*                                                                   *}
  282. {* Side effects:                                                     *}
  283. {*      highxblk - may be incremented +1                             *}
  284. {*      currxblk - set to relative block# of current index block     *}
  285. {*      ximage   - will contain the current index block              *}
  286. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  287.  
  288. VAR
  289.     xblkno   : integer;
  290.     i        : dirx;
  291.  
  292. BEGIN {dirfetch function}
  293.     xblkno := (recno DIV maxx) + 1;
  294.     IF xblkno=(highxblk+1)
  295.         THEN BEGIN
  296.                 currxblk := highxblk + 1;
  297.                 FOR i := 1 TO maxx DO
  298.                     ximage.xentry[i] := 0;
  299.                 WRITE(xfile:currxblk,ximage);
  300.                 highxblk := currxblk
  301.             END; {then}
  302.     IF xblkno>highxblk
  303.         THEN BEGIN
  304.                 error(2);
  305.                 xblkno := -1
  306.             END {then}
  307.         ELSE BEGIN
  308.                 IF xblkno<>currxblk
  309.                     THEN READ(xfile:xblkno,ximage);
  310.                 currxblk := xblkno
  311.             END; {else}
  312.     dirfetch := (recno MOD maxx) + 1
  313. END; {dirfetch function} {$L+}
  314. PROCEDURE blokfetch (blokno: integer;
  315.                  VAR buff  : qrec);
  316. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  317. {* Fetch a specified relative QFILE block into a given buffer        *}
  318. {*                                                                   *}
  319. {* Side effects:                                                     *}
  320. {*      highblok - may be incremented +1                             *}
  321. {*      currblok - set to block# of current qfile block              *}
  322. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  323.  
  324. VAR
  325.     i : bufx;
  326.  
  327. BEGIN {blokfetch procedure}
  328.     IF blokno=(highblok+1)
  329.         THEN BEGIN
  330.                 currblok := blokno;
  331.                 FOR i := 1 TO bufsize DO
  332.                     buff.qentry[i] := 0;
  333.                 WRITE(qfile:currblok,buff);
  334.                 highblok := currblok
  335.             END; {then}
  336.     IF (blokno<1) OR (blokno>highblok)
  337.         THEN error(3)
  338.         ELSE BEGIN
  339.                 IF blokno<>currblok
  340.                     THEN READ(qfile:blokno,buff);
  341.                 currblok := blokno
  342.             END {else}
  343. END; {blokfetch procedure} {$L+}
  344. FUNCTION findrec (recno: integer;  buff : buffer):  bufx;
  345.  
  346. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  347. {* Return a pointer to the starting byte of a requested record       *}
  348. {* number in a given buffer.                                         *}
  349. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  350.  
  351. VAR
  352.     i        : integer;
  353.     found    : boolean;
  354.  
  355. BEGIN {findrec function}
  356.     found := false;
  357.     i := 1;
  358.     WHILE ((i<(bufsize-3)) AND (buff[i]<>0) AND (NOT found)) DO
  359.         BEGIN {while}
  360.             IF cnvrt(buff,i+2)=recno
  361.                 THEN found := true
  362.                 ELSE i := i + buff[i]
  363.          END; {while}
  364.     IF NOT found
  365.         THEN error(5);
  366.     findrec := i
  367. END; {findrec function} {$L+}
  368. FUNCTION buildctl (VAR buff: qrec): question;
  369.  
  370. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  371. {* Given BUFF, with control record image, return the equivalent      *}
  372. {* control record.                                                   *}
  373. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  374.  
  375. VAR
  376.     equivalent : question;
  377.  
  378. BEGIN {buildctl function}
  379.     WITH buff, equivalent DO
  380.         BEGIN {with}
  381.             lastq   := cnvrt(qentry,6);
  382.             lastqbl := cnvrt(qentry,8);
  383.             lastxbl := cnvrt(qentry,10);
  384.             beastct := cnvrt(qentry,12)
  385.         END; {with}
  386.     buildctl := equivalent
  387. END; {buildctl function} {$L+}
  388. FUNCTION getrecord (recno  : integer): question;
  389.  
  390. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  391. {* Return from QFILE the RECNO record.                               *}
  392. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  393.  
  394. VAR
  395.     ptr      : bufx;
  396.     xptr     : dirx;
  397.     questn   : question;
  398. {$L+}
  399. FUNCTION buildquest (VAR buff: qrec;  pnt: bufx):  question;
  400.  
  401. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  402. {* Return the question-record that begins at position PNT of BUFF    *}
  403. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  404.  
  405. VAR
  406.     blokno     : integer;
  407.     equivalent : question;
  408.  
  409. BEGIN {buildquest function}
  410.     WITH equivalent, buff DO
  411.         BEGIN {with}
  412.             ident   := cnvrt(qentry,pnt+2);
  413.             typcode := quest;
  414.             nextyes := cnvrt(qentry,pnt+5);
  415.             nextno  := cnvrt(qentry,pnt+7);
  416.             setlength(query,0);
  417.             shiftxt(qentry,pnt+9,qentry[pnt]-9,query);
  418.             IF qentry[pnt+1]<>1
  419.                 THEN BEGIN
  420.                         blokno := currblok + 1;
  421.                         blokfetch(blokno,buff);
  422.                         IF NOT runabort
  423.                             THEN pnt := findrec(recno,qentry);
  424.                         IF NOT runabort
  425.                             THEN shiftxt(qentry,pnt+4,qentry[pnt]-4,query)
  426.                     END {then}
  427.         END; {with}
  428.     buildquest := equivalent
  429. END; {buildquest function} {$L+}
  430. BEGIN {getrecord function}
  431.     IF ((recno<0) OR (recno>maxquery))
  432.         THEN BEGIN
  433.                 WRITELN('INVALID RECORD NUMBER ',recno:1);
  434.                 error(1)
  435.             END {then}
  436.         ELSE WITH qimage, questn DO
  437.                 BEGIN {with}
  438.                     xptr := dirfetch(recno);
  439.                     IF NOT runabort
  440.                        THEN blokfetch(ximage.xentry[xptr],qimage);
  441.                     IF NOT runabort
  442.                         THEN ptr := findrec(recno,qentry);
  443.                     IF NOT runabort
  444.                         THEN BEGIN
  445.                                 ident := recno;
  446.                                 IF qentry[ptr+4]=ord(quest)
  447.                                     THEN typcode := quest
  448.                                     ELSE typcode := ctl;
  449.                                 CASE typcode OF
  450.                                     quest: questn := buildquest(qimage,ptr);
  451.                                     ctl  : questn := buildctl(qimage)
  452.                                 END {case}
  453.                             END {then}
  454.                 END; {with and else}
  455.     IF NOT runabort
  456.         THEN getrecord := questn
  457. END; {getrecord function} {$L+}
  458. PROCEDURE reshift (VAR buff    : buffer;
  459.                        tbyte   : bufx;
  460.                        source  : qstring;
  461.                        sbyte   : questx;
  462.                        len     : questx);
  463. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  464. {* Copy to BUFF, starting at TBYTE, LEN consecutive characters of    *}
  465. {* SOURCE, starting at byte SBYTE.  Pad BUFF with ZEROCHR.           *}
  466. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  467.  
  468. VAR
  469.     sptr     : questx;
  470.     tptr     : integer;
  471.  
  472. BEGIN {reshift procedure}
  473.     tptr := tbyte;
  474.     FOR sptr := sbyte TO (sbyte+len-1) DO
  475.       BEGIN {for}
  476.         buff[tptr] := ORD(source[sptr]);
  477.         tptr := tptr + 1
  478.       END; {for}
  479.     WHILE tptr<=bufsize DO
  480.       BEGIN
  481.         buff[tptr] := 0;
  482.         tptr := tptr + 1
  483.       END
  484. END; {reshift procedure} {$L+}
  485. PROCEDURE appendseg1 (txt      : qstring;
  486.                       nyes, nno: integer;
  487.                   VAR buff     : qrec;
  488.                       ptr      : bufx);
  489. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  490. {* In BUFF at point PTR, build segment 1 of the logical record       *}
  491. {* expressed by TXT, NYES, NNO.                                      *}
  492. {*                                                                   *}
  493. {* Side effects:                                                     *}
  494. {*      maxquery - becomes the new record's record-ID.               *}
  495. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  496.  
  497. LABEL 1;
  498.  
  499. TYPE
  500.     switcher = 0..1;
  501.  
  502. VAR
  503.     avl      : bufx;
  504.     need     : integer;
  505.     shiftlen : integer;
  506.     seglength: integer;
  507.     lastind  : switcher;
  508.  
  509. BEGIN {appendseg1 procedure}
  510.     need := length(txt) + 9;
  511.     avl  := bufsize - ptr + 1;
  512.     IF avl<9
  513.         THEN BEGIN
  514.                 error(4);
  515.                 GOTO 1
  516.             END;
  517.     WITH buff DO
  518.         BEGIN {with}
  519.             IF avl<need
  520.                 THEN seglength := avl
  521.                 ELSE seglength := need;
  522.             IF seglength=need
  523.                 THEN lastind := 1
  524.                 ELSE lastind := 0;
  525.             qentry[ptr]   := seglength;
  526.             qentry[ptr+1] := lastind;
  527.             revert(qentry,ptr+2,maxquery+1);
  528.             qentry[ptr+4] := ord(quest);
  529.             revert(qentry,ptr+5,nyes);
  530.             revert(qentry,ptr+7,nno);
  531.             IF avl<need
  532.                 THEN shiftlen := length(txt) - (need-avl)
  533.                 ELSE shiftlen := length(txt);
  534.             reshift(qentry,ptr+9,txt,1,shiftlen)
  535.         END; {with}
  536. 1:
  537. END; {appendseg1 procedure} {$L+}
  538. PROCEDURE addrecord (txt : qstring;
  539.                      nyes, nno: integer);
  540. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  541. {* Given the three data elements of a question record, append that   *}
  542. {* record to the question file.                                      *}
  543. {*                                                                   *}
  544. {* Side effects (updated as required):                               *}
  545. {*      xfile                                                        *}
  546. {*      highblok, highxblk, maxquery, maxanimals                     *}
  547. {*      qfile file control record                                    *}
  548. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  549.  
  550. LABEL 1;
  551.  
  552. VAR
  553.     newaddr  : integer;
  554.     xptr     : dirx;
  555. {$L+}
  556. FUNCTION appendrec (txt  : qstring;
  557.                      nyes, nno: integer): integer;
  558. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  559. {* Given the three data elements of a question record, append the    *}
  560. {* record to QFILE, assigning it record number MAXQUERY+1.  Return   *}
  561. {* block address.                                                    *}
  562. {*                                                                   *}
  563. {* Side effects:                                                     *}
  564. {*      maxquery - used but not changed.                             *}
  565. {*      highblok - may be incremented +1.                            *}
  566. {*      currblok - equal to new highblok.                            *}
  567. {*      qimage   - contains image of new highblok.                   *}
  568. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  569.  
  570. LABEL 1;
  571.  
  572. VAR
  573.     objblok  : integer;
  574.     i        : bufx;
  575.     available: integer;
  576.     required : bufx;
  577. {$L+}
  578. BEGIN {appendrec function}
  579.     WITH qimage DO
  580.         BEGIN {with}
  581.             required := length(txt) + 9;
  582.             available:= 0;
  583.             objblok  := highblok - 1;
  584.             WHILE available<9 DO
  585.                 BEGIN {while}
  586.                     objblok   := objblok + 1;
  587.                     blokfetch(objblok,qimage);
  588.                     IF runabort
  589.                         THEN GOTO 1;
  590.                     i := 1;
  591.                     WHILE ((i<bufsize) AND (qentry[i]<>0)) DO
  592.                         i := i + qentry[i];
  593.                     available := bufsize - i + 1
  594.                 END; {while}
  595.             appendseg1(txt,nyes,nno,qimage,i);
  596.             IF runabort
  597.                 THEN GOTO 1;
  598.             appendrec := objblok;
  599.             write(qfile:objblok,qimage);
  600.             IF qentry[i+1]<>1
  601.                 THEN BEGIN
  602.                         objblok := objblok + 1;
  603.                         blokfetch(objblok,qimage);
  604.                         IF runabort
  605.                             THEN GOTO 1;
  606.                         qentry[1] := required-available+4;
  607.                         qentry[2] := 1;
  608.                         revert(qentry,3,maxquery+1);
  609.                         reshift(qentry,5,txt,available-8,required-available);
  610.                         write(qfile:objblok,qimage)
  611.                     END; {then}
  612. 1:      END {with}
  613. END; {appendrec function} {$L+}
  614. BEGIN {addrecord procedure}
  615.     newaddr := appendrec(txt,nyes,nno);
  616.     IF runabort
  617.         THEN GOTO 1;
  618.     xptr := dirfetch(maxquery+1);
  619.     ximage.xentry[xptr] := newaddr;
  620.     write(xfile:highxblk,ximage);
  621.  
  622.     IF ((nyes=0) AND (nno=0))
  623.         THEN maxanimals := maxanimals + 1;
  624.     maxquery := maxquery + 1;
  625.     blokfetch(1,qimage);
  626.     IF runabort
  627.         THEN GOTO 1;
  628.     revert(qimage.qentry, 6,maxquery);
  629.     revert(qimage.qentry, 8,highblok);
  630.     revert(qimage.qentry,10,highxblk);
  631.     revert(qimage.qentry,12,maxanimals);
  632.     write(qfile:1,qimage);
  633. 1:
  634. END; {addrecord procedure} {$L+}
  635. PROCEDURE initializefiles;
  636.  
  637. VAR
  638.     qfilename : string 15;
  639.     xfilename : string 15;
  640. {$L+}
  641. PROCEDURE newfile;
  642.  
  643. CONST
  644.     firstquestion = 'Does it live in the water';
  645.     yesguess      = 'octopus';
  646.     noguess       = 'moose';
  647.  
  648. VAR
  649.     i        : dirx;
  650.     newq     : queryfile;
  651.     newx     : directory;
  652.  
  653. BEGIN {newfile procedure}
  654.     rewrite(qfilename,newq);
  655.     rewrite(xfilename,newx);
  656.     FOR i := 1 TO 4 DO
  657.         ximage.xentry[i] := 1;          {First 4 records to block 1   }
  658.     FOR i := 5 TO maxx DO
  659.         ximage.xentry[i] := 0;
  660.     write(newx,ximage);
  661.  
  662.     WITH qimage DO
  663.         BEGIN {with}
  664.             FOR i := 1 TO bufsize DO
  665.                 qentry[i] := 0;
  666.             qentry[1]  := 13;           {Control record length is 13  }
  667.             qentry[2]  := 1;            {This is last & only segment  }
  668.             qentry[5]  := ord(ctl);     {Identify as control rec  }
  669.             qentry[7]  := 3;            {Highest question# is 3       }
  670.             qentry[9]  := 1;            {Last question block used is 1}
  671.             qentry[11] := 1;            {Last index block used is 1   }
  672.             qentry[13] := 2             {File contains 2 animals      }
  673.         END; {with}
  674.     i := 14;
  675.     maxquery := 0;
  676.     appendseg1(firstquestion,2,3,qimage,i);
  677.     i := i + 9 + length(firstquestion);
  678.     maxquery := 1;
  679.     appendseg1(yesguess,0,0,qimage,i);
  680.     i := i + 9 + length(yesguess);
  681.     maxquery := 2;
  682.     appendseg1(noguess,0,0,qimage,i);
  683.     write(newq,qimage)
  684. END; {newfile procedure} {$L+}
  685. FUNCTION testexist:  boolean;
  686. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  687. {* Test for existence of disk files QFILENAME and XFILENAME.         *}
  688. {* Return FALSE if either one is missing, TRUE if both there.        *}
  689. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  690.  
  691. VAR
  692.     testxfile : directory;
  693.     testqfile : queryfile;
  694.     missing   : boolean;
  695.  
  696. BEGIN {testexist function}
  697.     reset(qfilename,testqfile);
  698.     reset(xfilename,testxfile);
  699.     missing := (eof(testqfile) OR eof(testxfile));
  700.     testexist := NOT missing
  701. END; {testexist function} {$L+}
  702. BEGIN {initializefiles procedure}
  703.     qfilename := filepfx;
  704.     append(qfilename,'.QQQ ');
  705.     xfilename := filepfx;
  706.     append(xfilename,'.QQX ');
  707.     IF NOT testexist
  708.         THEN newfile;
  709.  
  710.     reset(qfilename,qfile);
  711.     reset(xfilename,xfile);
  712.     currblok   := -1;
  713.     currxblk   := -1;
  714.     highblok   :=  1;
  715.     highxblk   :=  1;
  716.     maxquery   :=  3;
  717.     maxanimals :=  2;
  718.  
  719.     read(xfile:1,ximage);
  720.     currxblk := 1;
  721.     read(qfile:1,qimage);
  722.     currblok := 1;
  723.     currec   := buildctl(qimage);
  724.     maxquery   := currec.lastq;
  725.     highblok   := currec.lastqbl;
  726.     highxblk   := currec.lastxbl;
  727.     maxanimals := currec.beastct
  728. END; {initializefiles procedure} {$L+}
  729. PROCEDURE guessing;
  730.  
  731. LABEL 1;
  732.  
  733. CONST
  734.     bell      = 7;           {ordinal of ASCII code for terminal bell }
  735.     boast     = 'How about that - - - I WON!';
  736.     delay     = 8000;
  737.  
  738. VAR
  739.     guesstime : boolean;
  740.     success   : boolean;
  741.     nextquest : integer;
  742.     prevquest : integer;
  743.     querytxt  : string maxlen+1;
  744.     holdguess : qstring;
  745.     i         : integer;
  746. {$L+}
  747. FUNCTION voweler (noun: qstring):  qstring;
  748.  
  749. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  750. {* Given a noun, return a string with the correct choice of "a" or   *}
  751. {* "an" preceding the noun.                                          *}
  752. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  753.  
  754. VAR
  755.     holder : qstring;
  756.  
  757. BEGIN {voweler function}
  758.     IF noun[1] IN vowels
  759.         THEN holder := ' an '
  760.         ELSE holder := ' a ';
  761.     append(holder,noun);
  762.     voweler := holder
  763. END; {voweler function}
  764.  
  765. {- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}
  766.  
  767. PROCEDURE lowerize (VAR txt: qstring);
  768.  
  769. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  770. {* In a given string, change all upper-case letters to lower-case,   *}
  771. {* unless it looks like the mix is intended.                         *}
  772. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  773.  
  774. VAR
  775.     i      : integer;
  776.     letter : char;
  777.     sloppy : boolean;
  778.  
  779. BEGIN {lowerize procedure}
  780.     sloppy := true;
  781.     FOR i := 1 TO 4 DO
  782.         IF i<=length(txt)
  783.             THEN IF txt[i] in ['a'..'z']
  784.                     THEN sloppy := false;
  785.     IF sloppy
  786.         THEN FOR i := 1 TO length(txt) DO
  787.                 BEGIN {for}
  788.                     letter := txt[i];
  789.                     IF ((letter>='A') AND (letter<='Z'))
  790.                         THEN txt[i] := chr(ord(letter)-shiftup)
  791.                 END {for}
  792. END; {lowerize procedure} {$L+}
  793. PROCEDURE askabout (qtext: qstring);
  794.  
  795. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  796. {* Publish a given question.                                         *}
  797. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  798.  
  799. CONST
  800.     maxline  = 69;
  801.  
  802. VAR
  803.     i, j     : questx;
  804.     holder   : qstring;
  805.  
  806. BEGIN {askabout procedure}
  807.     write(reverse);
  808.     IF length(qtext)<=maxline
  809.       THEN write(qtext)
  810.       ELSE
  811.         BEGIN
  812.           i := maxline;
  813.           WHILE (i>(maxline-20)) AND (qtext[i]<>' ') DO
  814.             i := i - 1;
  815.           IF i>(maxline-20)
  816.             THEN
  817.               BEGIN
  818.                 setlength(holder,i-1);
  819.                 FOR j := 1 to (i-1) DO
  820.                   holder[j] := qtext[j];
  821.                 writeln(holder,invert);
  822.                 holder := '    ';
  823.                 append(holder,reverse);
  824.                 FOR j := (i+1) TO length(qtext) DO
  825.                   append(holder,qtext[j]);
  826.                 write(holder)
  827.               END {then}
  828.             ELSE write(qtext)
  829.         END {else}
  830. END; {askabout procedure} {$L+}
  831. PROCEDURE learning (oldguess  : qstring;
  832.                     prevquest : integer);
  833. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  834. {* Given an old (wrong) guess (in the form "a fish" or "an egret",   *}
  835. {* and the record number of the question that led to that guess,     *}
  836. {* secure from the player the correct answer, and a yes-or-no        *}
  837. {* question that would have led to it.  Insert the new question and  *}
  838. {* and animal into the question file linkage.                        *}
  839. {*                                                                   *}
  840. {* Side effects:                                                     *}
  841. {*      maxanimals - updated                                         *}
  842. {*      I/O variables as required (see subordinate procedures)       *}
  843. {*      currec (used to build new record & view old guess)           *}
  844. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  845.  
  846. CONST
  847.     humbler  = 'Oh!  I didn''t know about';
  848.     request1 = 'I''d like to learn more about animals.';
  849.     request2 = 'What''s a yes-or-no question to discriminate between';
  850.     clarify1 = 'Which answer to that question would mean';
  851.     clarify2 = ' - yes or no';
  852.     thanks   = 'Thank you!  Now I know ';
  853.  
  854. VAR
  855.     holdright  : qstring;
  856.     rightbeast : qstring;
  857.     newbeast   : boolean;
  858.     newquery   : qstring;
  859.     qhold      : qstring;
  860.  
  861.  
  862.  
  863.  
  864. PROCEDURE depunctuate (VAR dtext: qstring);
  865.  
  866. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  867. {* Trim off any terminating punctuation marks.                       *}
  868. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  869.  
  870. CONST
  871.     endset   = '.!?';
  872.  
  873. BEGIN {depunctuate procedure}
  874.     WHILE index(endset,dtext[length(dtext)])<>0 DO
  875.         setlength(dtext,length(dtext)-1)
  876. END; {depunctuate procedure} {$L+}
  877. FUNCTION getbeast: qstring;
  878.  
  879. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  880. {* Return the name of the animal the player had in mind.             *}
  881. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  882.  
  883. CONST
  884.     puzzled  = 'Really?  What sort of animal is it, then?';
  885.  
  886. VAR
  887.     altered  : boolean;
  888.     oldlen   : questx;
  889.     holder   : qstring;
  890.  
  891. {$L+}
  892. PROCEDURE markout (VAR btext: qstring;  word: qstring);
  893.  
  894. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  895. {* Given a BTEXT, find any instances of WORD appearing as distinct   *}
  896. {* words.  If there are any, eliminate from BTEXT all characters to  *}
  897. {* and including WORD.                                               *}
  898. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  899.  
  900. CONST
  901.     blank1 = ' ';
  902.  
  903. VAR
  904.     i, j     : questx;
  905.     offset   : questx;
  906.     padword  : qstring;
  907.     padlen   : questx;
  908.  
  909. BEGIN {markout procedure}
  910.     padword := word;
  911.     append(padword,blank1);
  912.     padlen  := length(padword);
  913.     WHILE index(btext,padword)=1 DO
  914.         BEGIN {while}
  915.             setlength(btext,length(btext)-padlen);
  916.             FOR i := 1 TO length(btext) DO
  917.                 btext[i] := btext[i+padlen];
  918.             WHILE btext[1]=blank1 DO
  919.                 BEGIN {while}
  920.                     setlength(btext,length(btext)-1);
  921.                     FOR i := 1 TO length(btext) DO
  922.                         btext[i] := btext[i+1]
  923.                 END {while}
  924.         END; {while}
  925.     padword := blank1;
  926.     append(padword,word);
  927.     append(padword,blank1);
  928.     padlen := length(padword);
  929.    j := index(btext,padword);
  930.     WHILE j<>0 DO
  931.         BEGIN {while}
  932.             offset := j + padlen - 1;
  933.             setlength(btext,length(btext)-offset);
  934.             FOR i := 1 TO length(btext) DO
  935.                  btext[i] := btext[offset+i];
  936.             WHILE btext[1]=blank1 DO
  937.                 BEGIN {while}
  938.                     setlength(btext,length(btext)-1);
  939.                     FOR i := 1 TO length(btext) DO
  940.                         btext[i] := btext[i+1]
  941.                 END; {while}
  942.             j := index(btext,padword)
  943.         END {while}
  944. END; {markout procedure} {$L+}
  945. BEGIN {getbeast function}
  946.     writeln(puzzled);
  947.     readln(holder);
  948.     depunctuate(holder);
  949.     lowerize(holder);
  950.     oldlen := length(holder);
  951.     altered := (holder[1]='A');
  952.     IF altered
  953.         THEN holder[1] := 'a';
  954.     markout(holder,'a');
  955.     markout(holder,'an');
  956.     IF (altered AND (oldlen=length(holder)))
  957.         THEN holder[1] := 'A';
  958.     getbeast := holder
  959. END; {getbeast function} {$L+}
  960. PROCEDURE insertquestion (qstn : qstring;
  961.                           ind  : boolean;
  962.                           ytxt : qstring;
  963.                           rec  : question;
  964.                           prev : integer);
  965. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  966. {* Insert a new question and guess into the question file, with      *}
  967. {* all required linkages.  QUESTN is the new question, YTXT is the   *}
  968. {* name of the new animal to be guessed.  If IND is true, then YTST  *}
  969. {* is the guess for a YES answer, and the animal in REC for NO;      *}
  970. {* otherwise, it's the other way around.  PREV is the question#      *}
  971. {* that led to this question;  the new question is to be substituted *}
  972. {* for REC in that question.                                         *}
  973. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  974.  
  975. LABEL 1;
  976.  
  977. VAR
  978.     newqstnum : integer;
  979.     newansnum : integer;
  980.     oldansnum : integer;
  981.     newyes    : integer;
  982.     newno     : integer;
  983. {$L+}
  984. PROCEDURE amendrec (recno, nyes, nno: integer);
  985.  
  986. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  987. {* For a given question record, update the NEXTYES and NEXTNO ptrs.  *}
  988. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  989.  
  990. LABEL 1;
  991.  
  992. VAR
  993.     blokno   : integer;
  994.     xptr     : dirx;
  995.     ptr      : bufx;
  996.  
  997. BEGIN {amendrec procedure}
  998.     xptr := dirfetch(recno);
  999.     IF runabort
  1000.         THEN GOTO 1;
  1001.     blokno := ximage.xentry[xptr];
  1002.     blokfetch(blokno,qimage);
  1003.     IF runabort
  1004.         THEN GOTO 1;
  1005.     ptr := findrec(recno,qimage.qentry);
  1006.     IF runabort
  1007.         THEN GOTO 1;
  1008.     revert(qimage.qentry,ptr+5,nyes);
  1009.     revert(qimage.qentry,ptr+7,nno);
  1010.     write(qfile:blokno,qimage);
  1011. 1:
  1012. END; {amendrec procedure} {$L+}
  1013. BEGIN {insertquestion procedure}
  1014.     newqstnum := maxquery + 1;
  1015.     newansnum := maxquery + 2;
  1016.     oldansnum := rec.ident;
  1017.     IF ind
  1018.         THEN BEGIN
  1019.                 newyes := newansnum;
  1020.                 newno  := oldansnum
  1021.             END {then}
  1022.         ELSE BEGIN
  1023.                 newyes := oldansnum;
  1024.                 newno  := newansnum
  1025.             END; {else}
  1026.     addrecord(qstn,newyes,newno);
  1027.     IF runabort
  1028.         THEN GOTO 1;
  1029.     addrecord(ytxt,0,0);
  1030.     IF runabort
  1031.         THEN GOTO 1;
  1032.     rec := getrecord(prev);
  1033.     IF runabort
  1034.         THEN GOTO 1;
  1035.     IF rec.nextyes=oldansnum
  1036.         THEN rec.nextyes := newqstnum
  1037.         ELSE rec.nextno  := newqstnum;
  1038.     amendrec(prev,rec.nextyes,rec.nextno);
  1039. 1:
  1040. END; {insertquestion procedure} {$L+}
  1041. BEGIN {learning procedure}
  1042.     rightbeast := getbeast;
  1043.     holdright  := voweler(rightbeast);
  1044.     writeln(humbler,holdright,'.');
  1045.     writeln(request1);
  1046.     qhold := request2;
  1047.     append(qhold,holdright);
  1048.     append(qhold,' and');
  1049.     append(qhold,oldguess);
  1050.     append(qhold,'?');
  1051.     askabout(qhold);
  1052.     writeln(invert);
  1053.     readln(newquery);
  1054.     depunctuate(newquery);
  1055.     lowerize(newquery);
  1056.     IF ((newquery[1]>='a') AND (newquery[1]<='z'))
  1057.         THEN newquery[1] := chr(ord(newquery[1])+shiftup);
  1058.     qhold := clarify1;
  1059.     append(qhold,holdright);
  1060.     append(qhold,clarify2);
  1061.     askabout(qhold);
  1062.     IF getyes
  1063.         THEN newbeast := true
  1064.         ELSE newbeast := false;
  1065.     insertquestion(newquery,newbeast,rightbeast,currec,prevquest);
  1066.     writeln;
  1067.     IF NOT runabort
  1068.         THEN writeln(thanks,maxanimals:1,' animals.')
  1069. END; {learning procedure} {$L+}
  1070. BEGIN {guessing procedure} {$C+}
  1071.     guesstime := false;
  1072.     nextquest := 1;
  1073.     WITH currec DO
  1074.         BEGIN {with}
  1075.             WHILE NOT guesstime DO
  1076.                 BEGIN {while}
  1077.                     currec := getrecord(nextquest);
  1078.                     IF runabort
  1079.                         THEN GOTO 1;
  1080.                     guesstime := (nextyes=0) AND (nextno=0);
  1081.                     IF NOT guesstime
  1082.                         THEN BEGIN
  1083.                                 prevquest := ident;
  1084.                                 askabout(query);
  1085.                                 IF getyes
  1086.                                     THEN nextquest := nextyes
  1087.                                     ELSE nextquest := nextno
  1088.                             END {then}
  1089.                 END; {while}
  1090.             querytxt  := 'Is it';
  1091.             holdguess := voweler(query);
  1092.             append(querytxt,holdguess);
  1093.             askabout(querytxt);
  1094.             IF getyes
  1095.                 THEN BEGIN
  1096.                         writeln;
  1097.                         writeln(chr(bell),boast);
  1098.                         FOR i := 1 TO delay DO;
  1099.                     END {then}
  1100.                 ELSE learning(holdguess,prevquest)
  1101.         END; {with}
  1102. 1:
  1103. END; {guessing procedure} {$L+}
  1104. PROCEDURE explain;
  1105.  
  1106. CONST
  1107.     l01a = '                      WELCOME to the Ani';
  1108.     l01b = 'mal Guessing Game!';
  1109.     l02  = 'Here''s how it works:';
  1110.     l03a = 'You think of some particular kind of ani';
  1111.     l03b = 'mal (like, say, an octopus), and I''ll';
  1112.     l04a = 'try to figure out what animal you''re thi';
  1113.     l04b = 'nking of, by asking you some yes-or-no';
  1114.     l05a = 'questions.  If I guess correctly, I win;';
  1115.     l05b = '  if you stump me, you win.  If you';
  1116.     l06a = 'want to win, you''d better pick a hard on';
  1117.     l06b = 'e, though --- I already know ';
  1118.     l06c = 'animals!';
  1119.     l07a = 'There is one catch.  I like winning a LO';
  1120.     l07b = 'T better than losing, so if you manage';
  1121.     l08a = 'to stump me with your animal, I''ll ask y';
  1122.     l08b = 'ou to teach me about that animal, so I';
  1123.     l09a = 'can get it right next time.  That way, I';
  1124.     l09b = ' get smarter every time I play!';
  1125.     l10a = 'A word about how we converse:  when I as';
  1126.     l10b = 'k a yes-or-no question, you can reply';
  1127.     l11a = 'by pressing just the Y key or the N key ';
  1128.     l11b = '(no need to spell out "yes" or "no").';
  1129.     l12a = 'For any other questions, please key in y';
  1130.     l12b = 'our answer, then press the <RETURN> key';
  1131.     l13a = ' (the gray key shaped sort of like a bac';
  1132.     l13b = 'kwards L).';
  1133.  
  1134. BEGIN {explain procedure}
  1135.     WRITELN(l01a,l01b);
  1136.     WRITELN;
  1137.     WRITELN(l02);
  1138.     WRITELN;
  1139.     WRITELN(l03a,l03b);
  1140.     WRITELN(l04a,l04b);
  1141.     WRITELN(l05a,l05b);
  1142.     WRITELN(l06a,l06b,maxanimals:1);
  1143.     WRITELN(l06c);
  1144.     WRITELN;
  1145.     WRITELN(l07a,l07b);
  1146.     WRITELN(l08a,l08b);
  1147.     WRITELN(l09a,l09b);
  1148.     WRITELN;
  1149.     WRITELN(l10a,l10b);
  1150.     WRITELN(l11a,l11b);
  1151.     WRITELN(l12a,l12b);
  1152.     WRITELN(l13a,l13b);
  1153.     WRITELN
  1154. END; {explain procedure} {$E+}
  1155. BEGIN {mainline procedure of program}
  1156.     runabort := false;
  1157.     vowels   := ['A','E','I','O','U','a','e','i','o','u'];
  1158.     shiftup  := ord('A') - ord('a');
  1159.     setupvdt;
  1160. {   rewrite('LST: ',db);  }
  1161. {   dbugging := false;    }
  1162.     initializefiles;
  1163.     WRITE(clear);
  1164.     explain;
  1165.     write(inviter);
  1166.     moreokay := getyes;
  1167.     IF NOT moreokay
  1168.       THEN
  1169.         BEGIN
  1170.           WRITELN;
  1171.           WRITELN(insulted)
  1172.         END; {then}
  1173.     WHILE moreokay DO
  1174.       BEGIN {while}
  1175.         writeln(clear,start1);
  1176.         writeln(start2);
  1177.         readln(replytxt);
  1178.         WRITE(clear);
  1179.         guessing;
  1180.         IF runabort
  1181.           THEN moreokay := false
  1182.           ELSE
  1183.             BEGIN
  1184.               WRITE(askagain);
  1185.               moreokay := getyes
  1186.             END {else}
  1187.       END; {while}
  1188.     IF runabort
  1189.       THEN writeln('TERMINATING DUE TO PROGRAM OR FILE ERROR')
  1190.       ELSE writeln('Okay!  Goodbye!')
  1191. END. {Animals program}
  1192.