home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / go / prog / goboard.sh < prev    next >
Encoding:
Linux/UNIX/POSIX Shell Script  |  1993-06-20  |  231.8 KB  |  8,478 lines

  1. #! /bin/sh
  2. # This is a shell archive, meaning:
  3. # 1. Remove everything above the #! /bin/sh line.
  4. # 2. Save the resulting text in a file.
  5. # 3. Execute the file with /bin/sh (not csh) to create:
  6. #    MANIFEST
  7. #    README
  8. #    go.pas
  9. #    goBoard.pas
  10. #    goCom.pas
  11. #    goMenu.pas
  12. #    goMgr.pas
  13. #    goPlayUtils.pas
  14. #    goPlayer.pas
  15. #    goTree.pas
  16. # This archive created: Mon Jan 22 17:42:31 1990
  17. export PATH; PATH=/bin:/usr/bin:$PATH
  18. if test -f 'MANIFEST'
  19. then
  20.     echo shar: "will not over-write existing file 'MANIFEST'"
  21. else
  22. cat << \SHAR_EOF > 'MANIFEST'
  23.    File Name        Archive #    Description
  24. -----------------------------------------------------------
  25.  MANIFEST                  1    This shipping list
  26.  README                    1    
  27.  go.pas                    4    
  28.  goBoard.pas               3    
  29.  goCom.pas                 1    
  30.  goMenu.pas                5    
  31.  goMgr.pas                 4    
  32.  goPlayUtils.pas           1    
  33.  goPlayer.pas              2    
  34.  goTree.pas                3    
  35. SHAR_EOF
  36. fi
  37. if test -f 'README'
  38. then
  39.     echo shar: "will not over-write existing file 'README'"
  40. else
  41. cat << \SHAR_EOF > 'README'
  42. This go board manager and rudimentary go player was written by
  43. Stoney Ballard at Perq Systems in 1983-1984.  It is written in
  44. Perq Pascal and utilizes some Perq libraries for I/O.  The code
  45. is offered here if someone is interested to convert it to Unix.
  46.  
  47. The wonderful part about it is that a game is recorded as a tree
  48. and can be played forward or backward, branching at any point
  49. where there were alternate moves.
  50.  
  51. For some time, this program was also used to generate the go
  52. boards displayed in the American Go Journal.  For this it used
  53. some large font digits which are now lost.
  54.  
  55. Fred Hansen
  56. SHAR_EOF
  57. fi
  58. if test -f 'go.pas'
  59. then
  60.     echo shar: "will not over-write existing file 'go.pas'"
  61. else
  62. cat << \SHAR_EOF > 'go.pas'
  63. {---------------------------------------------------------------}
  64. { Go Game Manager                                               }
  65. { Copyright (c) 1982 by Three Rivers Computer Corp.             }
  66. {                                                               }
  67. { Written: June 3, 1982 by Stoney Ballard                       }
  68. { Edit History:                                                 }
  69. {    June  3, 1982 Started                                      }
  70. {    June  4, 1982 Add dead group removal                       }
  71. {    June 10, 1982 Use new go file manager                      }
  72. {    Nov  10, 1982 Extensively Hacked Up                        }
  73. {    Dec  29, 1982 Changed "Erase Branch" to "Prune Branches"   }
  74. {    Jan   6, 1983 Added ^C escape from all readlns             }
  75. {---------------------------------------------------------------}
  76.  
  77. program Go;
  78.  
  79. exports
  80.  
  81. imports stream from stream;
  82.  
  83. procedure resetInput;
  84.  
  85. private
  86.  
  87. imports system from System;
  88. imports raster from raster;
  89. imports screen from screen;
  90. imports popUp from popUp;
  91. imports IO_Others from IO_Others;
  92. imports goCom from goCom;
  93. imports goMgr from goMgr;
  94. imports goTree from goTree;
  95. imports goBoard from goBoard;
  96. imports goMenu from goMenu; 
  97. imports memory from memory;
  98. imports perq_string from perq_string;
  99. imports goPlayer from goPlayer;
  100.  
  101. label
  102.   99;       (* the fatal error point *)
  103.  
  104. var
  105.   oCurPosX, oCurPosY: integer;
  106.   oScreenPtr: rasterPtr;
  107.  
  108.   procedure resetInput;
  109.   begin { resetInput }
  110.     streamKeyboardReset(input);
  111.   end { resetInput };
  112.  
  113.   procedure newTitle;
  114.   var
  115.     ts: string[128];
  116.     fn: string;
  117.     fl, fPos, tPos, i: integer;
  118.   begin { newTitle }
  119.     ts := 'Go  Version ';
  120.     ts := concat(ts, version);
  121.     getFNameString(fn);
  122.     fl := length(fn);
  123.     if fl > 0 then
  124.       begin
  125.         fPos := 81 - fl;
  126.         tPos := length(ts) + 1;
  127.         adjust(ts, 80);
  128.         for i := tPos to 80 do
  129.           ts[i] := ' ';
  130.         for i := fPos to fPos + fl - 1 do
  131.           ts[i] := fn[i - fPos + 1];
  132.       end;
  133.     changeTitle(ts);
  134.   end { newTitle };
  135.  
  136.   procedure initialize;
  137.   var
  138.     sseg: integer;
  139.  
  140.     procedure setupWindows;
  141.     var
  142.       ts: string;
  143.     begin { setupWindows }
  144.       createWindow(boardWin, bWinX, bWinY, bWinW, bWinH, ' ');
  145.       createWindow(menuWin, mWinX, mWinY, mWinW, mWinH, '');
  146.       createWindow(statWin, sWinX, sWinY, sWinW, sWinH, '');      
  147.       changeWindow(0);
  148.       gameFName := '';
  149.       newTitle;
  150.     end { setupWindows };
  151.  
  152.   begin { initialize }
  153.     createSegment(sseg, 192, 1, 192);
  154.     oScreenPtr := makePtr(sseg, 0, rasterPtr);
  155.     SReadCursor(oCurPosX, oCurPosY);
  156.     rasterop(rRpl, 768, 1024, 0, 0, SScreenW, oScreenPtr,
  157.                               0, 0, SScreenW, SScreenP);
  158.     IOSetFunction(CTCursCompl);
  159.     rasterop(RAndNot, 768, 1024, 0, 0, SScreenW, SScreenP,
  160.                                  0, 0, SScreenW, SScreenP);
  161.     setupWindows;
  162.     initMenu;
  163.     captures[black] := 0;
  164.     captures[white] := 0;
  165.     initGoTree;
  166.     initGoBoard;
  167.     makeGoTree;
  168.     initGoMgr;
  169.     gameFName := '';
  170.     numbEnabled := false;
  171.     treeDirty := false;
  172.     playLevel := 0;
  173.     debug := false;
  174.     printLarge := true;
  175.     initGoPlayer;
  176.   end { initialize };
  177.   
  178.   procedure doit;
  179.   var
  180.     done, foundIt, endLoop, gbg: boolean;
  181.     CtlCseen, playMyself, lastWasPass: boolean;
  182.     whoseTurn, whoWasLast: sType;
  183.     i, xi, yi, xs, ys: integer;
  184.     numDead, numHC, cmd: integer;
  185.     lastBuM: integer;
  186.     thisTag: tagPtr;
  187.     lastMove: pMRec;
  188.  
  189.     function getLine(var l: string): boolean;
  190.     label
  191.       1;
  192.     var
  193.       i, j, cx, cy: integer;
  194.  
  195.       handler ctlC;
  196.       begin { ctlC }
  197.         IOKeyClear;
  198.         streamKeyboardReset(input);
  199.         beep(error);
  200.         prompt('');
  201.         l := '';
  202.         getLine := false;
  203.         exit(getLine); 
  204.       end { ctlC }; 
  205.  
  206.       handler pastEOF(fn: pathName);
  207.       begin { pastEOF }
  208.         reset(input, fn);
  209.         sSetCursor(cx, cy);
  210.         write('    ');
  211.         sSetCursor(cx, cy);
  212.         goto 1;
  213.       end { pastEOF };
  214.  
  215.     begin { getLine }
  216.       sReadCursor(cx, cy);
  217.     1:
  218.       readln(l);
  219.       getLine := true;
  220.       j := 0;
  221.       for i := 1 to length(l) do
  222.         if ord(l[i]) >= 32 then
  223.           begin
  224.             j := j + 1;
  225.             l[j] := l[i];
  226.           end;
  227.       adjust(l, j);
  228.     end { getLine };
  229.  
  230.     procedure resetGame;
  231.     begin { resetGame }
  232.       clearBoard;
  233.       koX := -1;
  234.       koY := -1;
  235.       moveNum := 0;
  236.       curMove := treeRoot;
  237.       captures[black] := 0;
  238.       captures[white] := 0; 
  239.       showCaptures;
  240.       whoseTurn := black;
  241.       turnIs(black);
  242.       gameFname := '';
  243.       newTitle;
  244.       gameOver := false;
  245.       initGoMgr;
  246.     end { resetGame };
  247.  
  248.     procedure switchWho;
  249.     begin { switchWho }
  250.       if curMove = treeRoot then
  251.         whoseTurn := black
  252.       else if curMove^.id = remove then
  253.         whoseTurn := curMove^.who
  254.       else if curMove^.id = hcPlay then
  255.         whoseTurn := white
  256.       else if curMove^.who = black then
  257.         whoseTurn := white
  258.       else
  259.         whoseTurn := black;
  260.       turnIs(whoseTurn);
  261.     end { switchWho };
  262.  
  263.     procedure updateStatus;
  264.     begin { updateStatus }
  265.       dotLast;
  266.       showCaptures;
  267.       showComment;
  268.       showTag;
  269.       switchWho;
  270.     end { updateStatus };
  271.  
  272.     procedure doReadGame;
  273.     var
  274.       fName: pathName;
  275.  
  276.       handler badFileVersion;
  277.       begin { badFileVersion }
  278.         beep(error);
  279.         prompt('');
  280.         write(gameFName, ' is not compatable with this version of GO');
  281.         resetGame;
  282.         exit(doReadGame);
  283.       end { badFileVersion };
  284.  
  285.     begin { doReadGame }
  286.       if menuGoFile(fName) then
  287.         begin
  288.           prompt('Reading ');
  289.           write(fName, '.Go ...');
  290.           readTree(concat(fName, '.GO'));
  291.           resetGame;
  292.           gameFName := fName;
  293.           if treeRoot^.lastMove <> nil then
  294.             switchBranch(treeRoot^.lastMove);
  295.           treeDirty := false;
  296.           prompt('');
  297.           newTitle;
  298.         end;
  299.     end { doReadGame };
  300.  
  301.     procedure doWriteGame;
  302.     var
  303.       fs: string;
  304.       procedure addExt(var nam: string);
  305.       var
  306.         es: string;
  307.       begin { addExt }
  308.         if length(nam) > 3 then
  309.           begin
  310.             es := substr(nam, length(nam) - 2, 3);
  311.             convUpper(es);
  312.             if es <> '.GO' then
  313.               nam := concat(nam, '.Go');
  314.           end
  315.         else
  316.           nam := concat(nam, '.Go');
  317.       end { addExt };
  318.  
  319.       handler badGoWrite;
  320.       begin { badGoWrite };
  321.         beep(error);
  322.         prompt('Unable to write file ');
  323.         write(fs);
  324.         exit(doWriteGame);
  325.       end { badGoWrite };
  326.  
  327.     begin { doWriteGame }
  328.       IOKeyClear;
  329.       streamKeyboardReset(input);
  330.       if gameFName <> '' then
  331.         begin
  332.           prompt('Game File Name [');
  333.           write(gameFName, ']? ');
  334.         end
  335.       else
  336.         prompt('Game File Name? ');
  337.       if not getLine(fs) then
  338.         exit(doWriteGame);
  339.       if fs = '' then
  340.         if gameFName = '' then
  341.           begin
  342.             beep(error);
  343.             prompt('');
  344.             exit(doWriteGame);
  345.           end
  346.         else
  347.           fs := gameFName;
  348.       gameFName := fs;
  349.       addExt(fs);
  350.       prompt('Writing ');
  351.       write(fs, ' ...');
  352.       writeTree(fs, curMove);
  353.       treeDirty := false;
  354.       prompt('');
  355.       newTitle;
  356.     end { doWriteGame };
  357.  
  358.     function chooseAlt: boolean;
  359.     label
  360.       10;
  361.     var
  362.       bx, by, xs, ys: integer;
  363.       tm: pMRec;
  364.       hc0There: boolean;
  365.       hcMenu: pNameDesc;
  366.       res: resres;
  367.       numHC, i, j, numNHC: integer;
  368.  
  369.       handler outside;
  370.       begin { outside }
  371.         destroyNameDesc(hcMenu);
  372.         chooseAlt := false;
  373.         beep(error);
  374.         restoreCursor;
  375.         exit(chooseAlt);
  376.       end { outside };
  377.  
  378.     begin { chooseAlt }
  379.       chooseAlt := false;
  380.       switchWho;
  381.       waitNoButton;
  382.       tm := curMove^.flink;
  383.       numHC := 0;
  384.       numNHC := 0;
  385.       hc0There := false;
  386.       while tm <> nil do
  387.         begin
  388.           if tm^.id = hcPlay then
  389.             numHC := numHC + 1
  390.           else
  391.             begin
  392.               hc0There := true;
  393.               numNHC := numNHC + 1;
  394.             end;
  395.           tm := tm^.slink;
  396.         end;
  397.       if numHC > 0 then
  398.         begin
  399.           if hc0There then
  400.             numHC := numHC + 1;
  401.           allocNameDesc(numHC, 0, hcMenu);
  402.           hcMenu^.header := 'Handicap Alternates';
  403.           j := 1;
  404.           if hc0There then
  405.             begin
  406.               hcMenu^.commands[1] := '0';
  407.               j := 2;
  408.             end;
  409.           tm := curMove^.flink;
  410.           for i := j to numHC do
  411.             begin
  412.               while tm^.id <> hcPlay do
  413.                 tm := tm^.slink;
  414.     {$R-}
  415.               hcMenu^.commands[i] := ' ';
  416.               hcMenu^.commands[i][1] := chr(tm^.hcNum + ord('0'));
  417.     {$R=}
  418.               tm := tm^.slink;
  419.             end;
  420.           menu(hcMenu, false, 1, numHC, -1, -1, -1, res);
  421.           restoreCursor;
  422.           destroyNameDesc(hcMenu);
  423.           i := res^.indices[1];
  424.           destroyRes(res);
  425.           if hc0There then
  426.             if i = 1 then
  427.               begin
  428.                 if numNHC > 1 then
  429.                   goto 10;
  430.                 tm := curMove^.flink;
  431.                 while tm^.id <> move do
  432.                   tm := tm^.slink;
  433.                 forwardTo(tm);
  434.                 chooseAlt := true;
  435.                 exit(chooseAlt);
  436.               end
  437.             else
  438.               i := i - 1;
  439.           tm := curMove^.flink;
  440.           j := 0;
  441.           repeat
  442.             while tm^.id <> hcPlay do
  443.               tm := tm^.slink;
  444.             j := j + 1;
  445.             if j <> i then
  446.               tm := tm^.slink;
  447.           until j = i;
  448.           forwardTo(tm);
  449.           chooseAlt := true;
  450.         end
  451.       else
  452.         begin
  453.   10:
  454.           showAlts;
  455.           waitButton;
  456.           if passLocCur(tabRelX, tabRelY) then
  457.             begin
  458.               if passIsAlt then
  459.                 begin
  460.                   selPass;
  461.                   chooseAlt := true;
  462.                   waitNoButton;
  463.                   exit(chooseAlt);
  464.                 end;
  465.             end
  466.           else if bLocCur(tabRelX, tabRelY, bx, by, xs, ys) then
  467.             if board[bx][by].val = alternate then
  468.               begin
  469.                 selAlt(bx, by);
  470.                 chooseAlt := true;
  471.                 waitNoButton;
  472.                 exit(chooseAlt);
  473.               end;
  474.           remAlts;
  475.           beep(error);
  476.         end;
  477.       waitNoButton;
  478.     end { chooseAlt };
  479.  
  480.     procedure mForward;
  481.     var
  482.       gbg: boolean;
  483.     begin { mForward }
  484.       if gameOver then
  485.         restoreDead;
  486.       if atLeaf(curMove) then
  487.         beep(error)
  488.       else if atBranch(curMove) then
  489.         gbg := chooseAlt
  490.       else
  491.         forwardTo(curMove^.flink);
  492.     end { mForward };
  493.  
  494.     procedure doBkToS;
  495.     var
  496.       bx, by, sx, sy: integer;
  497.     begin { doBkToS }
  498.       prompt('Point at stone to backup to');
  499.       waitButton;
  500.       if bLocCur(tabRelX, tabRelY, bx, by, xs, ys) then
  501.         if board[bx][by].val <> empty then
  502.           begin
  503.             while not lastPlayAt(bx, by) do
  504.               backup1;
  505.             exit(doBkToS);
  506.           end;
  507.       beep(error);
  508.       waitNoButton;
  509.     end { doBkToS };
  510.  
  511.     procedure doPutTag;
  512.     var
  513.       ts: tagStr;
  514.       cm: pMRec;
  515.     begin { doPutTag }
  516.       if curMove = treeRoot then
  517.         beep(error)
  518.       else
  519.         begin
  520.           IOKeyClear;
  521.           streamKeyboardReset(input);
  522.           prompt('Tag String: ');
  523.           if not getLine(ts) then
  524.             exit(doPutTag);
  525.           if length(ts) > maxTagLen then
  526.             begin
  527.               beep(error);
  528.               prompt('Tags may be no longer than ');
  529.               write(maxTagLen:0, ' characters');
  530.             end
  531.           else if length(ts) = 0 then
  532.             begin
  533.               if curMove^.tag = nil then
  534.                 begin
  535.                   beep(error);
  536.                   prompt('');
  537.                 end
  538.               else
  539.                 begin
  540.                   delTag(curMove^.tag);
  541.                   prompt('Tag Deleted');
  542.                 end;
  543.             end
  544.           else if tagExists(ts) then
  545.             begin
  546.               beep(error);
  547.               prompt('That tag already exists');
  548.             end
  549.           else
  550.             begin
  551.               tagMove(curMove, ts);
  552.             end;
  553.         end;
  554.     end { doPutTag };
  555.  
  556.     procedure doGoToTag;
  557.     var
  558.       thisTag: tagPtr;
  559.     begin { doGoToTag }
  560.       thisTag := getTagMenu;
  561.       if thisTag <> nil then  
  562.         switchBranch(thisTag^.mPtr);
  563.     end { doGoToTag };
  564.  
  565.     procedure doPutCmt;
  566.     var
  567.       cs, curCmt: string;
  568.     begin { doPutCmt }
  569.       IOKeyClear;
  570.       streamKeyboardReset(input);
  571.       prompt('Comment: ');
  572.       if not getLine(cs) then
  573.         exit(doPutCmt);
  574.       if length(cs) = 0 then
  575.         if getComment(curMove, curCmt) then
  576.           prompt('Comment Deleted')
  577.         else
  578.           begin
  579.             beep(error);
  580.             prompt('');
  581.           end;
  582.       commentMove(curMove, cs);
  583.     end { doPutCmt };
  584.  
  585.     procedure doScore;
  586.     var
  587.       wScore, bScore, wr, br: integer;
  588.       done: boolean;
  589.       bx, by, xs, ys: integer;
  590.     begin { doScore }
  591.       putEnd;
  592.       done := false;
  593.       prompt('Point at dead groups, Press outside of board to stop');
  594.       repeat
  595.         waitButton;
  596.         if bLocCur(tabRelX, tabRelY, bx, by, xs, ys) then
  597.           begin
  598.             if board[bx, by].val <> empty then
  599.               delGroup(bx, by);
  600.           end
  601.         else
  602.           done := true;
  603.         showCaptures;
  604.         waitNoButton;
  605.       until done;
  606.       prompt('Counting Score ...');
  607.       scoreGame(wScore, bScore);
  608.       wScore := wScore - captures[black];
  609.       bScore := bScore - captures[white];
  610.       if wScore < 0 then
  611.         begin
  612.           wr := -wScore;
  613.           wScore := 0;
  614.         end
  615.       else
  616.         wr := 0;
  617.       if bScore < 0 then
  618.         begin
  619.           br := -bScore;
  620.           bScore := 0;
  621.         end
  622.       else
  623.         br := 0;
  624.       bScore := bScore + wr;
  625.       wScore := wScore + br;
  626.       prompt('Score is: ');
  627.       write('White = ', wScore:0, ', Black = ', bScore:0);
  628.       if wScore = bScore then
  629.         write(' - A Tie!')
  630.       else if wScore > bScore then
  631.         write(' - White Wins by ', (wScore - bScore):0)
  632.       else
  633.         write(' - Black Wins by ', (bScore - wScore):0)
  634.     end { doScore };
  635.  
  636.     procedure doEraseMove;
  637.     var
  638.       lm: pMRec;
  639.     begin { doEraseMove }
  640.       if gameOver then
  641.         restoreDead;
  642.       if curMove = treeRoot then
  643.         beep(error)
  644.       else
  645.         begin
  646.           lm := curMove;
  647.           backup1;
  648.           lm := delBranch(lm);
  649.           treeDirty := true;
  650.         end;
  651.     end { doEraseMove };
  652.  
  653.     procedure doPruneBranches;
  654.     var
  655.       lm, sm, tm: pMRec;
  656.       tp: tagPtr;
  657.       didPrune: boolean;
  658.     begin { doPruneBranches }
  659.       if gameOver then
  660.         restoreDead;
  661.       if not isBranch(curMove) then
  662.         beep(error)
  663.       else if not confirmed then
  664.         beep(error)
  665.       else
  666.         begin
  667.           didPrune := false;
  668.           wipeTreeMarks;
  669.           lm := curMove;
  670.           while lm <> treeRoot do
  671.             begin
  672.               lm^.mark := true;
  673.               lm := lm^.blink;
  674.             end;
  675.           tp := treeRoot^.lastTag;
  676.           while tp <> nil do
  677.             begin
  678.               lm := tp^.mPtr;
  679.               while lm <> treeRoot do
  680.                 begin
  681.                   lm^.mark := true;
  682.                   lm := lm^.blink;
  683.                 end;
  684.               tp := tp^.nextTag;
  685.             end;
  686.           lm := curMove;
  687.           while lm <> treeRoot do
  688.             begin
  689.               if lm^.blink^.flink^.slink <> nil then
  690.                 begin
  691.                   sm := lm^.blink^.flink;
  692.                   while sm <> nil do
  693.                     if not sm^.mark then
  694.                       begin
  695.                         tm := sm;
  696.                         sm := sm^.slink;
  697.                         tm := delBranch(tm);
  698.                         didPrune := true;
  699.                         treeDirty := true;
  700.                       end
  701.                     else
  702.                       sm := sm^.slink;
  703.                 end;
  704.               lm := lm^.blink;
  705.             end;
  706.           if not didPrune then
  707.             prompt('All Branches Were Tagged');
  708.         end;
  709.     end { doPruneBranches };
  710.  
  711.     handler ctlC;
  712.     begin { ctlC }
  713.       IOKeyClear;
  714.       CtlCseen := true;
  715.     end { ctlC }; 
  716.  
  717.   begin { doit }
  718.     resetGame;
  719.     done := false;
  720.     lastMove := nil;
  721.     CtlCseen := false;
  722.     playMyself := false;
  723.     lastWasPass := false;
  724.     IOSetModeTablet(relTablet);
  725.     IOCursorMode(trackCursor);
  726.     activate(mReadFile, true);
  727.     activate(mTogNums, true);
  728.     activate(mQuit, true);
  729.     activate(mPutCmt, true);
  730.     activate(mAutoPlay, true);
  731.     activate(mPlayMyself, true);
  732.     activate(mSetPlayLevel, true);
  733.     activate(mDebug, true);
  734.     activate(mRefBoard, true);
  735.     activate(mShoState, true);
  736.     activate(mBoardSize, true);
  737.     repeat
  738.       if curMove <> lastMove then
  739.         checkAtari(curMove);
  740.       updateStatus;
  741.       lastMove := curMove;
  742.       if not playMyself then
  743.         begin
  744.           activate(mPrintBoard, curMove <> treeRoot);
  745.           activate(mPrintDiag, curMove <> treeRoot);
  746.           activate(mStepToTag, stepTagPossible);
  747.           activate(mSetStepTag, treeRoot^.lastTag <> nil);
  748.           activate(mGotoTag, treeRoot^.lastTag <> nil);
  749.           activate(mInit, treeRoot^.flink <> nil);
  750.           activate(mWriteFile, treeRoot^.flink <> nil);
  751.           activate(mSetHc, curMove = treeRoot);
  752.           activate(mPass, curMove <> treeRoot);
  753.           activate(mScore, curMove <> treeRoot);
  754.           activate(mForToBr, hasBranch(curMove));
  755.           activate(mBackToBr, isBranch(curMove));
  756.           activate(mBackToStone, curMove <> treeRoot);
  757.           activate(mForToLeaf, curMove^.flink <> nil);
  758.           activate(mPutTag, curMove <> treeRoot);
  759.           activate(mGotoRoot, curMove <> treeRoot);
  760.           activate(mEraseMove, curMove <> treeRoot);
  761.           activate(mPruneBranches, isBranch(curMove));
  762.           activate(mBackOne, curMove <> treeRoot);
  763.           activate(mForOne, curMove^.flink <> nil);
  764.         end;
  765.       if CtlCseen then
  766.         cmd := mCtlC
  767.       else if playMyself then
  768.         cmd := mAutoPlay
  769.       else
  770.         repeat
  771.           cmd := getMenuCmd;
  772.         until cmd <> none;
  773.       prompt('');
  774.       case cmd of
  775.         mCtlC:
  776.           begin
  777.             playMyself := false;
  778.             CtlCseen := false;
  779.           end;
  780.         mPlaceStone:
  781.           begin
  782.             if gameOver then
  783.               restoreDead;
  784.             if bLocCur(tabRelX, tabRelY, xi, yi, xs, ys) then
  785.               begin
  786.                 if board[xi, yi].val <> empty then
  787.                   beep(error)
  788.                 else if (xi = koX) and (yi = koY) then
  789.                   beep(koV)
  790.                 else
  791.                   doMove(whoseTurn, xi, yi, xs, ys);
  792.               end
  793.             else
  794.               beep(error);
  795.             waitNoButton;
  796.           end;
  797.         mAutoPlay:
  798.           begin
  799.             if gameOver then
  800.               restoreDead;
  801.             prompt('Thinking...');
  802.             if curMove = treeRoot then
  803.               lastWasPass := false
  804.             else
  805.               lastWasPass := curMove^.id = pass;
  806.             if playMove(whoseTurn, xi, yi) then
  807.               begin
  808.                 if board[xi, yi].val <> empty then
  809.                   begin
  810.                     beep(error);
  811.                     prompt('Bad move at ');
  812.                     write((xi + 1):0, ', ', (yi + 1):0);
  813.                     playMyself := false;
  814.                     write(' - Generated by ', playreason);
  815.                   end
  816.                 else if (xi = koX) and (yi = koY) then
  817.                   begin
  818.                     beep(koV);
  819.                     prompt('ko violation at ');
  820.                     write((xi + 1):0, ', ', (yi + 1):0);
  821.                     write(' - Generated by ', playreason);
  822.                     playMyself := false;
  823.                   end
  824.                 else
  825.                   begin
  826.                     doMove(whoseTurn, xi, yi, 0, 0);
  827.                     if board[xi, yi].val = empty then
  828.                       begin
  829.                         prompt('self kill at ');
  830.                         write((xi + 1):0, ', ', (yi + 1):0);
  831.                         write(' - Generated by ', playreason);
  832.                         playMyself := false;
  833.                       end
  834.                     else
  835.                       commentMove(curMove, playReason);
  836.                   end;
  837.               end
  838.             else
  839.               begin
  840.                 doPass(whoseTurn);
  841.                 if lastWasPass then
  842.                   playMyself := false;
  843.               end;
  844.             waitNoButton;
  845.             prompt('');
  846.           end;
  847.         mPlayMyself:
  848.           playMyself := true;
  849.         mSetPlayLevel:
  850.           menuPlayLevel(playLevel, maxPlayLevel);
  851.         mShoState:
  852.           showPlayState(whoseTurn);
  853.         mInit:
  854.           if confirmed then
  855.             begin
  856.               makeGoTree;
  857.               resetGame;
  858.               treeDirty := false;
  859.             end
  860.           else
  861.             beep(error);
  862.         mSetHc:
  863.           if moveNum = 0 then
  864.             begin
  865.               if gameOver then
  866.                 restoreDead;
  867.               numHC := getHCMenu;
  868.               if numHC > 0 then
  869.                 doHCPlay(numHC)
  870.               else
  871.                 beep(error);
  872.             end
  873.           else
  874.             beep(error);
  875.         mPass:
  876.           begin
  877.             if gameOver then
  878.               restoreDead;
  879.             doPass(whoseTurn);
  880.           end;
  881.         mScore:
  882.           doScore;
  883.         mForToBr:
  884.           begin
  885.             if gameOver then
  886.               restoreDead;
  887.             if atLeaf(curMove) then
  888.               beep(error)
  889.             else if not atBranch(curMove) then
  890.                forwToBr;
  891.             if not atLeaf(curMove) then
  892.               gbg := chooseAlt;
  893.           end;
  894.         mBackToBr:
  895.           begin
  896.             if gameOver then
  897.               restoreDead;
  898.             if curMove = treeRoot then
  899.               beep(error)
  900.             else
  901.               backToBr;
  902.             if atBranch(curMove) then
  903.               gbg := chooseAlt;
  904.           end;
  905.         mBackToStone:
  906.           begin
  907.             if gameOver then
  908.               restoreDead;
  909.             if curMove = treeRoot then
  910.               beep(error)
  911.             else
  912.               doBkToS;
  913.           end;
  914.         mForToLeaf:
  915.           begin
  916.             if gameOver then
  917.               restoreDead;
  918.             if atLeaf(curMove) then
  919.               beep(error)
  920.             else
  921.               begin
  922.                 endLoop := false;
  923.                 repeat
  924.                   if atLeaf(curMove) then
  925.                     endLoop := true
  926.                   else if atBranch(curMove) then
  927.                     begin
  928.                       if not chooseAlt then
  929.                         begin
  930.                           endLoop := true;
  931.                           beep(error);
  932.                         end;
  933.                     end
  934.                   else
  935.                     forwToBr;                    
  936.                 until endLoop;
  937.               end;
  938.           end;
  939.         mPutTag:
  940.           doPutTag;
  941.         mGotoTag:
  942.           doGoToTag;
  943.         mGotoRoot:
  944.           switchBranch(treeRoot);
  945.         mPutCmt:
  946.           doPutCmt;
  947.         mReadFile:
  948.           if confirmed then
  949.             doReadGame;
  950.         mWriteFile:
  951.           doWriteGame;
  952.         mEraseMove:
  953.           doEraseMove;
  954.         mPruneBranches:
  955.           doPruneBranches;
  956.         mTogNums:
  957.           if not numbEnabled then
  958.             begin
  959.               numbEnabled := true;
  960.               showAllStones;
  961.               dotSX := -1;
  962.               putMString(mTogNums, 'Erase Numbers');
  963.             end
  964.           else
  965.             begin
  966.               numbEnabled := false;
  967.               showAllStones;
  968.               dotSX := -1;
  969.               dotLast;
  970.               putMString(mTogNums, 'Show Stone Numbers');
  971.             end;
  972.         mDebug:
  973.           if debug then
  974.             begin
  975.               debug := false;
  976.               putMString(mDebug, 'Turn Debug On');
  977.             end
  978.           else
  979.             begin
  980.               debug := true;
  981.               putMString(mDebug, 'Turn Debug Off');
  982.             end;
  983.         mBoardSize:
  984.           begin
  985.             printLarge := not printLarge;
  986.             if printLarge then
  987.               begin
  988.                 prompt('Will Print on Large Board Now');
  989.                 putMString(mBoardSize, 'Use Small Board');
  990.               end
  991.             else
  992.               begin
  993.                 prompt('Will Print on Small Board Now');
  994.                 putMString(mBoardSize, 'Use Large Board');
  995.               end;
  996.           end;
  997.         mPrintBoard:
  998.           printBoard(false);
  999.         mPrintDiag:
  1000.           printBoard(true);
  1001.         mStepToTag:
  1002.           begin
  1003.             if gameOver then
  1004.               restoreDead;
  1005.             if stepTag = nil then
  1006.               stepTag := getTagMenu;
  1007.             if stepTag <> nil then
  1008.               doStepTag
  1009.             else
  1010.               beep(error);
  1011.           end;
  1012.         mSetStepTag:
  1013.           begin
  1014.             thisTag := getTagMenu;
  1015.             if thisTag <> nil then
  1016.               stepTag := thisTag;
  1017.           end;
  1018.         mQuit:
  1019.           if confirmed then
  1020.             done := true;
  1021.         mBackOne:
  1022.           begin
  1023.             if gameOver then
  1024.               restoreDead
  1025.             else if curMove = treeRoot then
  1026.               beep(error)
  1027.             else
  1028.               backUp1;
  1029.           end;
  1030.         mForOne:
  1031.           begin
  1032.             if gameOver then
  1033.               restoreDead;
  1034.             mForward;
  1035.           end;
  1036.         mRefBoard:
  1037.           refreshBoard;
  1038.       end { case };
  1039.       if not playMyself then
  1040.         endCmd;
  1041.     until done;
  1042.   end { doit };
  1043.  
  1044.   procedure cleanup;
  1045.   begin { cleanup }
  1046.     screenReset;
  1047.     rasterOp(rRpl, 768, 1024, 0, 0, SScreenW, SScreenP,
  1048.                               0, 0, SScreenW, oScreenPtr);
  1049.     SSetCursor(oCurPosX, oCurPosY);
  1050.   end { cleanup };
  1051.  
  1052.   handler ctlC;
  1053.   begin { ctlC }
  1054.     IOKeyClear; 
  1055.   end { ctlC };
  1056.  
  1057. begin { Go } 
  1058.   initialize;
  1059.   doit;
  1060. 99:
  1061.   cleanUp;
  1062. end { Go }.
  1063. SHAR_EOF
  1064. fi
  1065. if test -f 'goBoard.pas'
  1066. then
  1067.     echo shar: "will not over-write existing file 'goBoard.pas'"
  1068. else
  1069. cat << \SHAR_EOF > 'goBoard.pas'
  1070. {---------------------------------------------------------------}
  1071. { goBoard.Pas                                                   }
  1072. {                                                               }
  1073. { Board Image Handler for Go                                    }
  1074. { Copyright (c) 1982 by Three Rivers Computer Corp.             }
  1075. {                                                               }
  1076. { Written: June 3, 1982 by Stoney Ballard                       }
  1077. { Edit History:                                                 }
  1078. {    June  3, 1982 Started                                      }
  1079. {    June  4, 1982 Add dead group removal                       }
  1080. {    June 10, 1982 Use new go file manager                      }
  1081. {    Nov   8, 1982 Split From Go.Pas                            }
  1082. {---------------------------------------------------------------}
  1083.  
  1084.  
  1085. module goBoard;
  1086.  
  1087. exports
  1088.  
  1089. imports goCom from goCom;
  1090. imports screen from screen;
  1091.  
  1092. type
  1093.   SoundType = (atari, koV, s3, s4, die, die2, die3, error);
  1094.  
  1095. exception gbFatal;
  1096.  
  1097. procedure initGoBoard;
  1098. procedure clearBoard;
  1099. procedure addHCStones(num: integer);
  1100. procedure placeStone(which: sType; lx, ly, ofx, ofy, moveNum: integer);
  1101. procedure placeAlt(which: sType; lx, ly, ofx, ofy: integer);
  1102. procedure remStone(lx, ly: integer);
  1103. procedure showPass(which: sType);
  1104. procedure remPass;
  1105. function passLocCur(cx, cy: integer): boolean;
  1106. function bLocCur(cx, cy: integer; var lx, ly, sx, sy: integer): boolean;
  1107. procedure beep(sound: SoundType);
  1108. procedure dotStone(lx, ly: integer);
  1109. procedure showAllStones;
  1110. procedure printBoard(isDiagram: boolean);
  1111. procedure showCaptures;
  1112. procedure turnIs(who: sType);
  1113. procedure refreshBoard;
  1114. procedure putBString(x, y: integer; s: string);
  1115.  
  1116. private
  1117.  
  1118. imports raster from raster;
  1119. imports io_unit from io_unit;
  1120. imports io_others from io_others;
  1121. imports memory from memory;
  1122. imports fileSystem from fileSystem;
  1123. imports perq_string from perq_string;
  1124. imports csdx from csdx;
  1125. imports goMgr from goMgr;
  1126. imports goTree from goTree;
  1127. imports goMenu from goMenu;
  1128. imports system from system;
  1129. imports go from go;
  1130.  
  1131. const
  1132.   sPicC = 15;
  1133.   sPicS = 32;
  1134.   hpPicS = 10;
  1135.   hpPicC = 4;
  1136.   patchS = 40;
  1137.   patchC = 19;
  1138.   picWW = 4;
  1139.   htHeight = 4;
  1140.   htWidth = 48;
  1141.   gridWidth = 32;
  1142.   pGridWidth = 34;   { for printing }
  1143.   xMargin = boardX + gridWidth;
  1144.   yMargin = boardY + gridWidth;
  1145.   pxMargin = pBoardX + pGridWidth;
  1146.   pyMargin = pBoardY + pGridWidth;
  1147.   gridBorder = gridWidth div 2;
  1148.   pGridBorder = pGridWidth div 2;
  1149.   gridXMargin = xMargin - gridBorder;
  1150.   gridYMargin = yMargin - gridBorder;
  1151.   pGridXMargin = pxMargin - pGridBorder;
  1152.   pGridYMargin = pyMargin - pGridBorder;
  1153.   htXMargin = xMargin - gridWidth; 
  1154.   htYMargin = yMargin - gridWidth; 
  1155.   phtXMargin = pxMargin - pGridWidth; 
  1156.   phtYMargin = pyMargin - pGridWidth; 
  1157.   boardHeight = 20 * gridWidth;
  1158.   pBoardHeight = 20 * pGridWidth;
  1159.   slopSize = 2;
  1160.   lineWidth = 2;
  1161.   extraXO = pxMargin;  { 96 }
  1162.   extraYO = 768;
  1163.   pedgeBX = pxMargin;  { 96 }
  1164.   pedgeBY = pyMargin + (19 * pGridWidth);  { 672 }
  1165.   pedgeLX = pBoardX;  { 64 }
  1166.   pedgeLY = pBoardY + (19 * pGridWidth);  { 640 }
  1167.   edgeBX = xMargin;  { 96 }
  1168.   edgeBY = yMargin + (19 * GridWidth);  { 672 }
  1169.   edgeLX = BoardX;  { 64 }
  1170.   edgeLY = BoardY + (19 * GridWidth);  { 640 }
  1171.   rCmtY = pBoardX + pBoardHeight + 32;
  1172.   lCmtY = rCmtY + 8 + charHeight;
  1173.   tFntWidth = 6;
  1174.   tFntHeight = 9;
  1175.   maxSMark = 2;
  1176.  
  1177. type
  1178.   htArray = array[0..3] of array[0..47] of integer;
  1179.   pHtArray = ^htArray;
  1180.  
  1181.   beepbuf = array[0..63] of integer;
  1182.   pBeepBuf = ^BeepBuf;
  1183.  
  1184. var
  1185.   hcDot: pPicBuf;
  1186.   htBuf: pHtArray;
  1187.   patch: array[1..9] of pPicBuf;
  1188.   StatPtr: IOStatPtr;
  1189.   statRec: IOStatus;
  1190.   sounds: array[atari..die3] of pBeepBuf;
  1191.   stones: array[sType] of pPicBuf;
  1192.   stoneCir: pPicBuf;
  1193.   stoneMarks: array[0..maxSMark] of pPicBuf;
  1194.   sysFont: fontPtr;
  1195.   goBNumFont: fontPtr;
  1196.   goSNumFont: fontPtr;
  1197.   goTNumFont: fontPtr;
  1198.   goSLetFont: fontPtr;
  1199.   printing: boolean;
  1200.   scrSavPtr: rasterPtr;
  1201.   sNumBase, sNumStart: integer;
  1202.   bigNums: boolean;
  1203.  
  1204. { merely beeps the given sound }
  1205. procedure beep(sound: SoundType);
  1206. var
  1207.   zilch: Double;
  1208.   rep, i: integer;
  1209.   savY, savB, savG, savW, savS: boolean;
  1210. begin { beep }
  1211.  if sound = error then
  1212.    IOBeep
  1213.  else
  1214.    begin
  1215.      savY := tabYellow;
  1216.      savW := tabWhite;
  1217.      savG := tabGreen;
  1218.      savB := tabBlue;
  1219.      savS := tabSwitch;
  1220.      IOSetModeTablet(offTablet);
  1221.      if sound = die then
  1222.        rep := 128 * 3
  1223.      else  
  1224.        rep := 128;
  1225.      UnitIO(Speech, RECAST(sounds[sound],IOBufPtr), IOWriteHiVol, rep,
  1226.             zilch, nil, StatPtr);
  1227.      IOSetModeTablet(relTablet);
  1228.      tabYellow := savY;
  1229.      tabWhite := savW;
  1230.      tabGreen := savG;
  1231.      tabBlue := savB;
  1232.      tabSwitch := savS;
  1233.    end;
  1234. end { beep };
  1235.  
  1236. procedure showCaptures;
  1237. var
  1238.   s: string;
  1239.  
  1240.   procedure dectos(val: integer);
  1241.   var
  1242.     numC, i: integer;
  1243.     ts: string;
  1244.     c: char;
  1245.   begin { dectos }
  1246.     if val = 0 then
  1247.       s := '0'
  1248.     else
  1249.       begin
  1250.         numC := 0;
  1251.         adjust(ts, 20);
  1252.         while val <> 0 do
  1253.           begin
  1254.             numC := numC + 1;
  1255.             ts[numC] := chr(val mod 10 + ord('0'));
  1256.             val := val div 10;
  1257.           end;
  1258.         adjust(s, numC);
  1259.         for i := 1 to numC do
  1260.           s[i] := ts[numC - i + 1];
  1261.       end;
  1262.   end { dectos };
  1263.  
  1264. begin { showCaptures }
  1265.   dectos(captures[black]);
  1266.   SSetCursor(captNBX, captNY);
  1267.   write(s:3);
  1268.   dectos(captures[white]);
  1269.   SSetCursor(captNWX, captNY);
  1270.   write(s:3);
  1271. end { showCaptures };
  1272.  
  1273. procedure turnIs(who: sType);
  1274. begin { turnIs }
  1275.   SSetCursor(turnX, turnY);
  1276.   if who = white then
  1277.     write('White to Play')
  1278.   else
  1279.     write('Black to Play');
  1280. end { turnIs };
  1281.  
  1282. procedure putBString(x, y: integer; s: string);
  1283. var
  1284.   xp, yp, sw, i: integer;
  1285.   fnt: fontPtr;
  1286. begin { putBString }
  1287.   setFont(goSNumFont);
  1288.   fnt := goSNumFont;
  1289.   for i := 1 to length(s) do
  1290.     if (s[i] >= '0') and
  1291.        (s[i] <= '9') then
  1292.       s[i] := chr(ord(s[i]) - #46 + #200);
  1293.   xp := x * gridWidth + xMargin;
  1294.   yp := y * gridWidth + yMargin;
  1295.   sw := 0;
  1296.   for i := 1 to length(s) do
  1297.     sw := sw + fnt^.index[lAnd(ord(s[i]), #177)].width;
  1298.   xp := xp - (sw div 2);
  1299.   yp := yp + (fnt^.height div 2) + 1;
  1300.   SChrFunc(0);
  1301.   SSetCursor(xp, yp);
  1302.   write(s:0);
  1303. end { putBString };
  1304.  
  1305. procedure putStone(cx, cy, mNum: integer; val: bVal);
  1306. const
  1307.   widthPad = 2;
  1308.   shPad = 3;
  1309.   bhPad = 1;
  1310. var
  1311.   x, y, org: integer;
  1312.   ns: string;
  1313.   sl, d, sw, n: integer;
  1314.   cv: integer;
  1315.   fnt: fontPtr;
  1316.   heightPad: integer;
  1317. begin { putStone }
  1318.   x := cx - sPicC;
  1319.   y := cy - sPicC;
  1320.   rasterop(RAndNot, sPicS, sPicS, x, y, SScreenW, SScreenP,
  1321.                                   0, 0, picWW, stones[black]);
  1322.   rasterop(ROr, sPicS, sPicS, x, y, SScreenW, SScreenP,
  1323.                               0, 0, picWW, stones[val]);
  1324.   if numbEnabled and (mNum > 0) then
  1325.     begin
  1326.       n := mNum - sNumBase;
  1327.       if n < 0 then
  1328.         exit(putStone);
  1329.       n := n + sNumStart;
  1330.       if bigNums then
  1331.         begin
  1332.           fnt := goBNumFont;
  1333.           heightPad := bhPad;
  1334.         end
  1335.       else
  1336.         begin
  1337.           fnt := goSNumFont;
  1338.           heightPad := shPad;
  1339.         end;
  1340.       if val = black then
  1341.         if bigNums then
  1342.           begin
  1343.             if n > 9 then
  1344.               org := ord('`')
  1345.             else
  1346.               org := ord('j');
  1347.           end
  1348.         else
  1349.           begin
  1350.             if n > 99 then
  1351.               org := #24
  1352.             else
  1353.               org := #0;
  1354.           end
  1355.       else if bigNums then
  1356.         begin
  1357.           if n > 9 then
  1358.             org := ord('@')
  1359.           else
  1360.             org := ord('J');
  1361.         end
  1362.       else
  1363.         begin
  1364.           if n > 99 then
  1365.             org := #12
  1366.           else
  1367.             org := #60;
  1368.         end;
  1369.       ns := '   ';
  1370.       sl := 0;
  1371.       sw := 0;
  1372.       if n >= 100 then
  1373.         d := 100
  1374.       else if n >= 10 then
  1375.         d := 10
  1376.       else
  1377.         d := 1;
  1378.       while d > 0 do
  1379.         begin
  1380.           sl := sl + 1;
  1381.           cv := (n div d) + org;
  1382.           ns[sl] := chr(cv + #200);
  1383.           sw := sw + fnt^.index[cv].width;
  1384.           n := n mod d;
  1385.           d := d div 10;
  1386.         end;
  1387.       adjust(ns, sl);
  1388.       x := cx - (sw div 2) + widthPad;
  1389.       y := cy + (fnt^.height div 2) + heightPad;
  1390.       setFont(fnt);
  1391.       SSetCursor(x, y);
  1392.       SChrFunc(6);
  1393.       write(ns);
  1394.       setFont(sysFont);
  1395.       SChrFunc(0);
  1396.     end;
  1397. end { putStone };
  1398.  
  1399. procedure showStone(lx, ly: integer);
  1400. var
  1401.   x, y: integer;
  1402. begin { showStone }
  1403.   with board[lx, ly] do
  1404.     begin
  1405.       if printing then
  1406.         if printLarge then
  1407.           begin
  1408.             x := lx * pGridWidth + pxMargin;
  1409.             y := ly * pGridWidth + pyMargin;
  1410.           end
  1411.         else { small board }
  1412.           begin
  1413.             x := lx * gridWidth + xMargin;
  1414.             y := ly * gridWidth + yMargin;
  1415.           end
  1416.       else { not printing }
  1417.         begin
  1418.           x := lx * gridWidth + xMargin + xOfs;
  1419.           y := ly * gridWidth + yMargin + yOfs;
  1420.         end;
  1421.       putStone(x, y, mNum, val);
  1422.     end;
  1423. end { showStone };
  1424.  
  1425. procedure showAllStones;
  1426. var
  1427.   i, j: integer;
  1428. begin { showAllStones }
  1429.   for j := 0 to maxPoint do
  1430.     for i := 0 to maxPoint do
  1431.       if board[i, j].val <> empty then
  1432.         showStone(i, j);
  1433. end { showAllStones };
  1434.  
  1435. procedure dotStone(lx, ly: integer);
  1436. var
  1437.   x, y: integer;
  1438. begin { dotStone }
  1439.   with board[lx, ly] do
  1440.     if val <> empty then
  1441.       begin
  1442.         x := lx * gridWidth + xMargin + xOfs;
  1443.         y := ly * gridWidth + yMargin + yOfs;
  1444.         rasterop(rNot, 2, 2, x, y, SScreenW, SScreenP,
  1445.                              x, y, SScreenW, SScreenP);
  1446.       end;
  1447. end { dotStone };
  1448.  
  1449. function bLocCur(cx, cy: integer; var lx, ly, sx, sy: integer): boolean;
  1450. var
  1451.   xic, yic: integer;
  1452. begin { bLocCur }
  1453.   bLocCur := false;
  1454.   if printing and printLarge then
  1455.     begin
  1456.       cx := cx - pGridXMargin;
  1457.       cy := cy - pGridYMargin;
  1458.     end
  1459.   else
  1460.     begin
  1461.       cx := cx - gridXMargin;
  1462.       cy := cy - gridYMargin;
  1463.     end;
  1464.   if (cx >= 0) and (cy >= 0) then
  1465.     begin
  1466.       if printing and printLarge then
  1467.         begin
  1468.           lx := cx div pGridWidth;
  1469.           ly := cy div pGridWidth;
  1470.           xic := lx * pGridWidth + pGridBorder;
  1471.           yic := ly * pGridWidth + pGridBorder;
  1472.         end
  1473.       else
  1474.         begin
  1475.           lx := cx div gridWidth;
  1476.           ly := cy div gridWidth;
  1477.           xic := lx * gridWidth + gridBorder;
  1478.           yic := ly * gridWidth + gridBorder;
  1479.         end;
  1480.       if (lx <= maxPoint) and (ly <= maxPoint) then
  1481.         begin
  1482.           if cx < xic - slopSize then
  1483.             cx := xic - slopSize
  1484.           else if cx > xic + slopSize then
  1485.             cx := xic + slopSize;
  1486.           if cy < yic - slopSize then
  1487.             cy := yic - slopSize
  1488.           else if cy > yic + slopSize then
  1489.             cy := yic + slopSize;
  1490.           sx := cx - xic;
  1491.           sy := cy - yic;
  1492.           bLocCur := true;
  1493.         end;
  1494.      end;
  1495. end { bLocCur };
  1496.  
  1497. procedure showPass(which: sType);
  1498. begin { showPass }
  1499.   SSetCursor(passX, passY);
  1500.   if which = black then
  1501.     write(' Black Passes ')
  1502.   else
  1503.     write(' White Passes ');
  1504.   passShowing := true;
  1505. end { showPass };
  1506.  
  1507. procedure remPass;
  1508. begin { remPass }
  1509.   SSetCursor(passX, passY);
  1510.   write('               ');
  1511.   passShowing := false;
  1512. end { remPass };
  1513.  
  1514. function passLocCur(cx, cy: integer): boolean;
  1515. begin { passLocCur }
  1516.   passLocCur :=  (cx >= passX) and (cx < (passX + passW)) and
  1517.                  (cy <= passY) and (cy > (passY - passH));
  1518. end { passLocCur };
  1519.  
  1520. procedure showAlt(lx, ly: integer; sv: sType);
  1521. begin { showAlt }
  1522.   with board[lx, ly] do
  1523.     begin
  1524.       lx := lx * gridWidth + xMargin - sPicC;
  1525.       ly := ly * gridWidth + yMargin - sPicC;
  1526.       rasterop(ROr, sPicS, sPicS, lx, ly, SScreenW, SScreenP,
  1527.                                   0, 0, picWW, stoneCir);
  1528.     end;
  1529. end { showAlt };
  1530.  
  1531. procedure placeStone(which: sType; lx, ly, ofx, ofy, moveNum: integer);
  1532. begin { placeStone }
  1533.   if passShowing then
  1534.     remPass;
  1535.   with board[lx, ly] do
  1536.     begin
  1537.       val := which;
  1538.       xOfs := ofx;
  1539.       yOfs := ofy;
  1540.       mNum := moveNum;
  1541.       showStone(lx, ly);
  1542.     end;
  1543. end { placeStone };
  1544.  
  1545. procedure placeAlt(which: sType; lx, ly, ofx, ofy: integer);
  1546. begin { placeAlt }
  1547.   with board[lx, ly] do
  1548.     begin
  1549.       val := alternate;
  1550.       xOfs := 0;
  1551.       yOfs := 0;
  1552.       mNum := -1;
  1553.       showAlt(lx, ly, which);
  1554.     end;
  1555. end { placeAlt };
  1556.  
  1557. procedure remStone(lx, ly: integer);
  1558. var
  1559.   x, y, i, j: integer;
  1560. begin { remStone }
  1561.   with board[lx, ly] do
  1562.     if val <> empty then
  1563.       begin
  1564.         val := empty;
  1565.         if ly = 0 then
  1566.           i := 1
  1567.         else if ly = maxPoint then
  1568.           i := 7
  1569.         else i := 4;
  1570.         if lx = maxPoint then
  1571.           i := i + 2
  1572.         else if lx > 0 then
  1573.           i := i + 1; 
  1574.         if printing and printLarge then
  1575.           begin
  1576.             x := (lx * pGridWidth) - patchC + pxMargin;
  1577.             y := (ly * pGridWidth) - patchC + pyMargin;
  1578.           end
  1579.         else
  1580.           begin
  1581.             x := (lx * gridWidth) - patchC + xMargin;
  1582.             y := (ly * gridWidth) - patchC + yMargin;
  1583.           end;
  1584.         rasterop(RRpl, patchS, patchS, x, y, SScreenW, SScreenP,
  1585.                                        0, 0, picWW, patch[i]);
  1586.         if ((lx = 3)  and (ly = 3))  or
  1587.            ((lx = 9)  and (ly = 3))  or
  1588.            ((lx = 15) and (ly = 3))  or
  1589.            ((lx = 3)  and (ly = 9))  or
  1590.            ((lx = 9)  and (ly = 9))  or
  1591.            ((lx = 15) and (ly = 9))  or
  1592.            ((lx = 3)  and (ly = 15)) or
  1593.            ((lx = 9)  and (ly = 15)) or
  1594.            ((lx = 15) and (ly = 15)) then
  1595.           if printing and printLarge then
  1596.             rasterop(ROr, hpPicS, hpPicS,
  1597.                      pxMargin + (pGridWidth * lx) - hpPicC,
  1598.                      pyMargin + (pGridWidth * ly) - hpPicC,
  1599.                      SScreenW, SScreenP,
  1600.                      0, 0, picWW, hcDot)
  1601.           else
  1602.             rasterop(ROr, hpPicS, hpPicS,
  1603.                      xMargin + (gridWidth * lx) - hpPicC,
  1604.                      yMargin + (gridWidth * ly) - hpPicC,
  1605.                      SScreenW, SScreenP,
  1606.                      0, 0, picWW, hcDot);
  1607.         for i := lx - 1 to lx + 1 do
  1608.           for j := ly - 1 to ly + 1 do
  1609.             if (i >= 0) and (i <= maxPoint) and
  1610.                (j >= 0) and (j <= maxPoint) then
  1611.               if (board[i, j].val = black) or
  1612.                  (board[i, j].val = white) then
  1613.                 begin
  1614.                   showStone(i, j);
  1615.                   if (i = dotSX) and (j = dotSY) then
  1616.                     dotStone(i, j);
  1617.                 end; 
  1618.       end;
  1619. end { remStone };
  1620.  
  1621. procedure addHCStones(num: integer);
  1622. begin { addHCStones }
  1623.   case num of
  1624.     2: 
  1625.       begin
  1626.         placeStone(black, 3, 15, 0, 0, 0);
  1627.         placeStone(black, 15, 3, 0, 0, 0);
  1628.       end;
  1629.     3:
  1630.       begin
  1631.         placeStone(black, 3, 15, 0, 0, 0);
  1632.         placeStone(black, 15, 3, 0, 0, 0);
  1633.         placeStone(black, 15, 15, 0, 0, 0);
  1634.       end;
  1635.     4:
  1636.       begin
  1637.         placeStone(black, 3, 15, 0, 0, 0);
  1638.         placeStone(black, 15, 3, 0, 0, 0);
  1639.         placeStone(black, 3, 3, 0, 0, 0);
  1640.         placeStone(black, 15, 15, 0, 0, 0);
  1641.       end;
  1642.     5:
  1643.       begin
  1644.         placeStone(black, 3, 3, 0, 0, 0);
  1645.         placeStone(black, 3, 15, 0, 0, 0);
  1646.         placeStone(black, 9, 9, 0, 0, 0);
  1647.         placeStone(black, 15, 3, 0, 0, 0);
  1648.         placeStone(black, 15, 15, 0, 0, 0);
  1649.       end;
  1650.     6:
  1651.       begin
  1652.         placeStone(black, 3, 3, 0, 0, 0);
  1653.         placeStone(black, 3, 15, 0, 0, 0);
  1654.         placeStone(black, 3, 9, 0, 0, 0);
  1655.         placeStone(black, 15, 9, 0, 0, 0);
  1656.         placeStone(black, 15, 3, 0, 0, 0);
  1657.         placeStone(black, 15, 15, 0, 0, 0);
  1658.       end;
  1659.     7:
  1660.       begin
  1661.         placeStone(black, 3, 3, 0, 0, 0);
  1662.         placeStone(black, 3, 15, 0, 0, 0);
  1663.         placeStone(black, 3, 9, 0, 0, 0);
  1664.         placeStone(black, 9, 9, 0, 0, 0);
  1665.         placeStone(black, 15, 9, 0, 0, 0);
  1666.         placeStone(black, 15, 3, 0, 0, 0);
  1667.         placeStone(black, 15, 15, 0, 0, 0);
  1668.       end;
  1669.     8:
  1670.       begin
  1671.         placeStone(black, 3, 3, 0, 0, 0);
  1672.         placeStone(black, 3, 9, 0, 0, 0);
  1673.         placeStone(black, 3, 15, 0, 0, 0);
  1674.         placeStone(black, 9, 3, 0, 0, 0);
  1675.         placeStone(black, 9, 15, 0, 0, 0);
  1676.         placeStone(black, 15, 3, 0, 0, 0);
  1677.         placeStone(black, 15, 9, 0, 0, 0);
  1678.         placeStone(black, 15, 15, 0, 0, 0);
  1679.       end;
  1680.     9:
  1681.       begin
  1682.         placeStone(black, 3, 3, 0, 0, 0);
  1683.         placeStone(black, 3, 9, 0, 0, 0);
  1684.         placeStone(black, 3, 15, 0, 0, 0);
  1685.         placeStone(black, 9, 3, 0, 0, 0);
  1686.         placeStone(black, 9, 9, 0, 0, 0);
  1687.         placeStone(black, 9, 15, 0, 0, 0);
  1688.         placeStone(black, 15, 3, 0, 0, 0);
  1689.         placeStone(black, 15, 9, 0, 0, 0);
  1690.         placeStone(black, 15, 15, 0, 0, 0);
  1691.       end;
  1692.     end;
  1693. end { addHCStones };
  1694.  
  1695. procedure drawBoard;
  1696. var
  1697.   i, j, c, lWidth, x, y, w: integer;
  1698.   xMarg, yMarg, gWid, eBX, eBY, eLX, eLY: integer;
  1699. begin { drawBoard }
  1700.   if printing then
  1701.     begin
  1702.       lWidth := 1;
  1703.       if printLarge then
  1704.         begin
  1705.           xMarg := pxMargin;
  1706.           yMarg := pyMargin;
  1707.           gWid := pGridWidth;
  1708.           eBX := pedgeBX;
  1709.           eBY := pedgeBY;
  1710.           eLX := pedgeLX;
  1711.           eLY := pedgeLY;
  1712.         end
  1713.       else
  1714.         begin
  1715.           xMarg := xMargin;
  1716.           yMarg := yMargin;
  1717.           gWid := gridWidth;
  1718.           eBX := edgeBX;
  1719.           eBY := edgeBY;
  1720.           eLX := edgeLX;
  1721.           eLY := edgeLY;
  1722.         end
  1723.     end
  1724.   else
  1725.     begin
  1726.       lWidth := lineWidth;
  1727.       xMarg := xMargin;
  1728.       yMarg := yMargin;
  1729.       gWid := gridWidth;
  1730.     end;
  1731.   if not printing then
  1732.     for i := (htYMargin div htHeight) to 
  1733.              ((htYMargin + boardHeight) div htHeight) - 1 do
  1734.       rasterop(RRpl, bWinW - (htXMargin * 2), htHeight,
  1735.                      htXMargin, i * htHeight, SScreenW, SScreenP,
  1736.                      htXMargin, 0, htWidth, htBuf)
  1737.   else
  1738.     rasterop(rAndNot, bWinW - (phtXMargin * 2), (bWinY + bWinH) - phtYMargin,
  1739.                       phtXMargin, phtYMargin, SScreenW, SScreenP,
  1740.                       phtXMargin, phtYMargin, SScreenW, SScreenP);
  1741.   for i := 1 to maxPoint - 1 do
  1742.     rasterop(ROrNot, (maxPoint * gWid) + lWidth, lWidth,
  1743.                      xMarg, yMarg + (i * gWid), SScreenW, SScreenP,
  1744.                      xMarg, yMarg + (i * gWid), SScreenW, SScreenP);
  1745.   for i := 1 to maxPoint - 1 do
  1746.     rasterop(ROrNot, lWidth, (maxPoint * gWid) + lWidth,
  1747.                      xMarg + (i * gWid), yMarg, SScreenW, SScreenP,
  1748.                      xMarg + (i * gWid), yMarg, SScreenW, SScreenP);
  1749.   rasterop(ROrNot, (maxPoint * gWid) + lineWidth, lineWidth,
  1750.                    xMarg, yMarg, SScreenW, SScreenP,
  1751.                    xMarg, yMarg, SScreenW, SScreenP);
  1752.   rasterop(ROrNot, (maxPoint * gWid) + lineWidth, lineWidth,
  1753.                 xMarg, yMarg + (maxPoint * gWid), SScreenW, SScreenP,
  1754.                 xMarg, yMarg + (maxPoint * gWid), SScreenW, SScreenP);
  1755.   rasterop(ROrNot, lineWidth, (maxPoint * gWid) + lineWidth,
  1756.                    xMarg, yMarg, SScreenW, SScreenP,
  1757.                    xMarg, yMarg, SScreenW, SScreenP);
  1758.   rasterop(ROrNot, lineWidth, (maxPoint * gWid) + lineWidth,
  1759.                 xMarg + (maxPoint * gWid), yMarg, SScreenW, SScreenP,
  1760.                 xMarg + (maxPoint * gWid), yMarg, SScreenW, SScreenP);
  1761.   rasterop(ROr, hpPicS, hpPicS,
  1762.                 xMarg + (gWid * 3) - hpPicC,
  1763.                 yMarg + (gWid * 3) - hpPicC,
  1764.                 SScreenW, SScreenP,
  1765.                 0, 0, picWW, hcDot);
  1766.   rasterop(ROr, hpPicS, hpPicS,
  1767.                 xMarg + (gWid * 9) - hpPicC,
  1768.                 yMarg + (gWid * 3) - hpPicC,
  1769.                 SScreenW, SScreenP,
  1770.                 0, 0, picWW, hcDot);
  1771.   rasterop(ROr, hpPicS, hpPicS,
  1772.                 xMarg + (gWid * 15) - hpPicC,
  1773.                 yMarg + (gWid * 3) - hpPicC,
  1774.                 SScreenW, SScreenP,
  1775.                 0, 0, picWW, hcDot);
  1776.   rasterop(ROr, hpPicS, hpPicS,
  1777.                 xMarg + (gWid * 3) - hpPicC,
  1778.                 yMarg + (gWid * 9) - hpPicC,
  1779.                 SScreenW, SScreenP,
  1780.                 0, 0, picWW, hcDot);
  1781.   rasterop(ROr, hpPicS, hpPicS,
  1782.                 xMarg + (gWid * 9) - hpPicC,
  1783.                 yMarg + (gWid * 9) - hpPicC,
  1784.                 SScreenW, SScreenP,
  1785.                 0, 0, picWW, hcDot);
  1786.   rasterop(ROr, hpPicS, hpPicS,
  1787.                 xMarg + (gWid * 15) - hpPicC,
  1788.                 yMarg + (gWid * 9) - hpPicC,
  1789.                 SScreenW, SScreenP,
  1790.                 0, 0, picWW, hcDot);
  1791.   rasterop(ROr, hpPicS, hpPicS,
  1792.                 xMarg + (gWid * 3) - hpPicC,
  1793.                 yMarg + (gWid * 15) - hpPicC,
  1794.                 SScreenW, SScreenP,
  1795.                 0, 0, picWW, hcDot);
  1796.   rasterop(ROr, hpPicS, hpPicS,
  1797.                 xMarg + (gWid * 9) - hpPicC,
  1798.                 yMarg + (gWid * 15) - hpPicC,
  1799.                 SScreenW, SScreenP,
  1800.                 0, 0, picWW, hcDot);
  1801.   rasterop(ROr, hpPicS, hpPicS,
  1802.                 xMarg + (gWid * 15) - hpPicC,
  1803.                 yMarg + (gWid * 15) - hpPicC,
  1804.                 SScreenW, SScreenP,
  1805.                 0, 0, picWW, hcDot);
  1806.   if not printing then
  1807.     begin
  1808.       SSetCursor(captBX, captY);
  1809.       write('Black Captures');
  1810.       SSetCursor(captWX, captY);
  1811.       write('White Captures');
  1812.     end
  1813.   else
  1814.     begin
  1815.       for i := 1 to maxPoint + 1 do
  1816.         begin
  1817.           if i > 9 then
  1818.             w := charWidth * 2
  1819.           else 
  1820.             w := charWidth;
  1821.           x := ((i - 1) * gWid) + eBX - (w div 2);
  1822.           y := eBY + charHeight;
  1823.           SSetCursor(x, y);
  1824.           write(i:0);
  1825.         end;
  1826.       for i := 0 to maxPoint do
  1827.         begin
  1828.           x := eLX - charWidth;
  1829.           y := eLY - ((maxPoint - i) * gWid) + (charHeight div 2);
  1830.           c := i + ord('A');
  1831.           if c >= ord('I') then
  1832.             c := c + 1;
  1833.           SSetCursor(x, y);
  1834.           SPutChr(chr(c));
  1835.         end;
  1836.     end;
  1837. end { drawBoard };
  1838.  
  1839. procedure clearBoard;
  1840. var
  1841.   i, j, xMarg, yMarg, gWid: integer;
  1842. begin { clearBoard }
  1843.   drawBoard;
  1844.   if printing and printLarge then
  1845.     begin
  1846.       xMarg := pxMargin;
  1847.       yMarg := pyMargin;
  1848.       gWid := pGridWidth;
  1849.     end
  1850.   else
  1851.     begin
  1852.       xMarg := xMargin;
  1853.       yMarg := yMargin;
  1854.       gWid := gridWidth;
  1855.     end;
  1856.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[1],
  1857.                                  xMarg + (0 * gWid) - patchC,
  1858.                                  yMarg + (0 * gWid) - patchC,
  1859.                                  SScreenW, SScreenP);
  1860.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[2],
  1861.                                  xMarg + (6 * gWid) - patchC,
  1862.                                  yMarg + (0 * gWid) - patchC,
  1863.                                  SScreenW, SScreenP);
  1864.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[3],
  1865.                                  xMarg + (18 * gWid) - patchC,
  1866.                                  yMarg + (0 * gWid) - patchC,
  1867.                                  SScreenW, SScreenP);
  1868.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[4],
  1869.                                  xMarg + (0 * gWid) - patchC,
  1870.                                  yMarg + (6 * gWid) - patchC,
  1871.                                  SScreenW, SScreenP);
  1872.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[5],
  1873.                                  xMarg + (6 * gWid) - patchC,
  1874.                                  yMarg + (6 * gWid) - patchC,
  1875.                                  SScreenW, SScreenP);
  1876.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[6],
  1877.                                  xMarg + (18 * gWid) - patchC,
  1878.                                  yMarg + (6 * gWid) - patchC,
  1879.                                  SScreenW, SScreenP);
  1880.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[7],
  1881.                                  xMarg + (0 * gWid) - patchC,
  1882.                                  yMarg + (18 * gWid) - patchC,
  1883.                                  SScreenW, SScreenP);
  1884.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[8],
  1885.                                  xMarg + (6 * gWid) - patchC,
  1886.                                  yMarg + (18 * gWid) - patchC,
  1887.                                  SScreenW, SScreenP);
  1888.   rasterop(RRpl, patchS, patchS, 0, 0, picWW, patch[9],
  1889.                                  xMarg + (18 * gWid) - patchC,
  1890.                                  yMarg + (18 * gWid) - patchC,
  1891.                                  SScreenW, SScreenP);
  1892.   for i := 0 to maxPoint do
  1893.     for j := 0 to maxPoint do
  1894.       board[i][j].val := empty;
  1895.   if not printing then
  1896.     remPass;
  1897. end { clearBoard };
  1898.  
  1899. procedure showPlayHistory(isDiagram: boolean);
  1900. var
  1901.   curRow, curCol, bx, by, bLim, curNum: integer;
  1902.   cm, scm, tm: pMRec;
  1903.   c: char;
  1904.   needWipe, lastCapt: boolean;
  1905.  
  1906.   procedure getMarks;
  1907.   var
  1908.     bx, by, lbx, lby, gx, gy, sMark, x, y, w: integer;
  1909.     curC: char;
  1910.     done: boolean;
  1911.   begin { getMarks }
  1912.     lbx := -1;
  1913.     lby := -1;
  1914.     curC := 'a';
  1915.     sMark := 0;
  1916.     prompt('Point at locations to place marks - press off board to stop');
  1917.     while tabSwitch do;
  1918.     done := false;
  1919.     setFont(goSLetFont);
  1920.     sChrFunc(rOr);
  1921.     repeat
  1922.       while not tabSwitch do;
  1923.       if bLocCur(tabRelX, tabRelY, bx, by, gx, gy) then
  1924.         begin
  1925.           if printLarge then
  1926.             begin
  1927.               x := bx * pGridWidth + pxMargin;
  1928.               y := by * pGridWidth + pyMargin;
  1929.             end
  1930.           else
  1931.             begin
  1932.               x := bx * GridWidth + xMargin;
  1933.               y := by * GridWidth + yMargin;
  1934.             end;
  1935.           if board[bx, by].val = empty then
  1936.             begin
  1937.               rasterop(rXor, 20, 30, x - 10, y - 15, SScreenW, SScreenP,
  1938.                                      x - 10, y - 15, SScreenW, SScreenP);
  1939.               w := goSLetFont^.index[ord(curC)].width - 2;
  1940.               SSetCursor(x - (w div 2), y + 7);
  1941.               write(curC);
  1942.               curC := chr(ord(curC) + 1);
  1943.             end
  1944.           else
  1945.             begin
  1946.               x := x - sPicC;
  1947.               y := y - sPicC;
  1948.               if (bx = lbx) and (by = lby) then
  1949.                 begin
  1950.                   if sMark <= maxSMark then
  1951.                     begin
  1952.                       rasterop(RXor, sPicS, sPicS, x, y, SScreenW, SScreenP,
  1953.                                              0, 0, picWW, stoneMarks[sMark]);
  1954.                       sMark := sMark + 1;
  1955.                     end
  1956.                   else
  1957.                     sMark := 0;
  1958.                 end
  1959.               else
  1960.                 sMark := 0;
  1961.               if sMark <= maxSMark then
  1962.                 rasterop(RXor, sPicS, sPicS, x, y, SScreenW, SScreenP,
  1963.                                              0, 0, picWW, stoneMarks[sMark]);
  1964.             end;
  1965.           lbx := bx;
  1966.           lby := by;
  1967.         end
  1968.       else
  1969.         done := true;
  1970.       while tabSwitch do;
  1971.     until done;
  1972.     sChrFunc(rRpl);
  1973.     setFont(sysFont);
  1974.     prompt('');
  1975.   end { getMarks };
  1976.  
  1977. begin { showPlayHistory }
  1978.   if not isDiagram then
  1979.     begin
  1980.       bLim := 99;
  1981.       sNumBase := 0;
  1982.       sNumStart := 0;
  1983.     end
  1984.   else
  1985.     bLim := 1000;
  1986.   curNum := 0;
  1987.   needWipe := true;
  1988.   wipeTreeMarks;
  1989.   cm := curMove;
  1990.   while cm <> treeRoot do
  1991.     begin
  1992.       cm^.mark := true;
  1993.       cm := cm^.blink;
  1994.     end;
  1995.   repeat
  1996.     if needWipe then
  1997.       begin
  1998.         rasterop(rAndNot, 768, 1024 - extraYO,
  1999.                  0, extraYO, SScreenW, SScreenP,
  2000.                  0, extraYO, SScreenW, SScreenP);
  2001.         curRow := 0;
  2002.         curCol := 0;
  2003.         showAllStones;
  2004.         needWipe := false;
  2005.       end;
  2006.     cm := cm^.flink;
  2007.     while not cm^.mark do
  2008.       cm := cm^.slink;
  2009.     with cm^ do
  2010.       case id of
  2011.         hcPlay:
  2012.           begin
  2013.             addHCStones(hcNum);
  2014.             curNum := 1;
  2015.           end;
  2016.         move:
  2017.           begin
  2018.             if board[mx, my].val <> empty then
  2019.               begin
  2020.                 bx := curCol * (20 * charWidth) + extraXO;
  2021.                 by := curRow * charHeight * 2 + extraYO + charHeight;
  2022.                 SSetCursor(bx, by);
  2023.                 if who = black then
  2024.                   write('Black ')
  2025.                 else
  2026.                   write('White ');
  2027.                 write((moveN - sNumBase):0, ' at ');
  2028.                 c := chr(my + ord('A'));
  2029.                 if c >= 'I' then
  2030.                   c := chr(ord(c) + 1);
  2031.                 write(c, '-', (mx + 1):0);
  2032.                 curRow := curRow + 1;
  2033.                 if (curRow * charHeight * 2 + extraYO + charHeight) > 1000 then
  2034.                   begin
  2035.                     curRow := 0;
  2036.                     curCol := curCol + 1;
  2037.                   end;
  2038.               end
  2039.             else
  2040.               placeStone(who, mx, my, 0, 0, moveN);
  2041.             curNum := moveN;
  2042.             lastCapt := false;
  2043.             repeat
  2044.               if cm^.flink = nil then
  2045.                 lastCapt := true
  2046.               else if cm^.flink^.id = remove then
  2047.                 begin
  2048.                   cm := cm^.flink;
  2049.                   if curNum < sNumBase then
  2050.                     remStone(cm^.mx, cm^.my);
  2051.                 end
  2052.               else
  2053.                 lastCapt := true;
  2054.             until lastCapt;
  2055.           end;
  2056.         pass:
  2057.           begin
  2058.             if not isDiagram then
  2059.               begin
  2060.                 bx := curCol * (20 * charWidth) + extraXO;
  2061.                 by := curRow * charHeight * 2 + extraYO + charHeight;
  2062.                 SSetCursor(bx, by);
  2063.                 if who = black then
  2064.                   write('Black ')
  2065.                 else
  2066.                   write('White ');
  2067.                 write((moveN - sNumBase):0, ' - Pass');
  2068.                 curRow := curRow + 1;
  2069.                 if (curRow * charHeight * 2 + extraYO + charHeight) > 1000 then
  2070.                   begin
  2071.                     curRow := 0;
  2072.                     curCol := curCol + 1;
  2073.                   end;
  2074.               end;
  2075.             curNum := moveN;
  2076.           end;
  2077.       end { case };
  2078.     if (curNum = bLim) or
  2079.        (cm = curMove) then
  2080.       begin
  2081.         if isDiagram then
  2082.           getMarks;
  2083.         csdx;
  2084.         if cm <> curMove then
  2085.           begin
  2086.             sNumBase := bLim + 1;
  2087.             bLim := bLim + 100;
  2088.             needWipe := true;
  2089.             clearBoard;
  2090.             scm := curMove;
  2091.             curMove := treeRoot;
  2092.             switchBranch(cm);
  2093.             curMove := scm;
  2094.             wipeTreeMarks;
  2095.             tm := curMove;
  2096.             while tm <> treeRoot do
  2097.               begin
  2098.                tm^.mark := true;
  2099.                tm := tm^.blink;
  2100.               end;
  2101.           end;
  2102.       end;               
  2103.   until cm = curMove;
  2104.   sNumBase := 0;
  2105.   sNumStart := 0;
  2106. end { showPlayHistory };
  2107.  
  2108. procedure printBoard(isDiagram: boolean);
  2109. label
  2110.   1;
  2111. var
  2112.   sseg: integer;
  2113.   neWas: boolean;
  2114.   cmSave: pMRec;
  2115.  
  2116.   procedure showFName;
  2117.   var
  2118.     fnX, fnY: integer;
  2119.     fs: string;
  2120.   begin { showFName }
  2121.     getFNameString(fs);
  2122.     if fs <> '' then
  2123.       begin
  2124.         fnY := charHeight + 8;
  2125.         fnX := 384 - (charWidth * length(fs) div 2);
  2126.         SSetCursor(fnX, fnY);
  2127.         write(fs);
  2128.       end;
  2129.   end { showFName };
  2130.  
  2131.   procedure showComments(isDiagram: boolean);
  2132.   var
  2133.     cx: integer;
  2134.     cs: string;
  2135.   begin { showComments }
  2136.     if not isDiagram then
  2137.       if getComment(treeRoot, cs) then
  2138.         begin
  2139.           cx := 384 - (charWidth * length(cs) div 2);
  2140.           SSetCursor(cx, rCmtY);
  2141.           write(cs);
  2142.         end;
  2143.     if getComment(curMove, cs) then
  2144.       begin
  2145.         cx := 384 - (charWidth * length(cs) div 2);
  2146.         if isDiagram then
  2147.           SSetCursor(cx, charHeight + 8)
  2148.         else
  2149.           SSetCursor(cx, lCmtY);
  2150.         write(cs);
  2151.       end;
  2152.   end { showComments };
  2153.  
  2154.   handler ctlC;
  2155.   begin { ctlC }
  2156.     IOKeyClear;
  2157.     resetInput;
  2158.     write(''); {control-G}
  2159.     prompt('');
  2160.     goto 1;
  2161.   end { ctlC };
  2162.  
  2163.   function readNum(pmpt: string): integer;
  2164.   label
  2165.     2;
  2166.   var
  2167.     n: integer;
  2168.  
  2169.     handler notNumber(fn: pathName);
  2170.     begin { notNumber }
  2171.       write(''); {control-G}
  2172.       prompt('Bad Number - try again: ');
  2173.       goto 2;
  2174.     end { notNumber };
  2175.  
  2176.     handler pastEOF(fn: pathName);
  2177.     begin { pastEOF }
  2178.       write(''); {control-G}
  2179.       goto 1;
  2180.     end { pastEOF };
  2181.  
  2182.   begin { readNum }
  2183.     prompt('');
  2184.   2:
  2185.     resetInput;
  2186.     write(pmpt);
  2187.     readln(n);
  2188.     readNum := n;
  2189.   end { readNum };
  2190.  
  2191. begin { printBoard }
  2192.   if curMove = treeRoot then
  2193.     begin
  2194.       write(''); {control-G}
  2195.       exit(printBoard);
  2196.     end;
  2197.   cmSave := curMove;
  2198.   if scrSavPtr = nil then
  2199.     begin
  2200.       createSegment(sseg, 192, 1, 192);
  2201.       scrSavPtr := makePtr(sseg, 0, rasterPtr);
  2202.     end;
  2203.   rasterop(rRpl, 768, 1024, 0, 0, SScreenW, scrSavPtr,
  2204.                             0, 0, SScreenW, SScreenP);
  2205.   rasterop(rAndNot, 768, 1024, 0, 0, SScreenW, SScreenP,
  2206.                                0, 0, SScreenW, SScreenP);
  2207.   printing := true;
  2208.   neWas := numbEnabled;
  2209.   numbEnabled := true;
  2210.   sNumBase := 0;
  2211.   sNumStart := 0;
  2212.   drawBoard;
  2213.   bigNums := false;
  2214.   showAllStones;
  2215.   if not isDiagram then
  2216.     begin
  2217.       showComments(false);
  2218.       showFName;
  2219.       csdx;
  2220.     end
  2221.   else
  2222.     begin
  2223.       sNumBase := readNum('Start Numbering at which stone? ');
  2224.       sNumStart := readNum('First Number is? ');
  2225.       prompt('');
  2226.     end;
  2227.   clearBoard;
  2228.   bigNums := true;
  2229.   if isDiagram then
  2230.     showComments(true);
  2231.   showPlayHistory(isDiagram);
  2232. 1:
  2233.   rasterop(rRpl, 768, 1024, 0, 0, SScreenW, SScreenP,
  2234.                             0, 0, SScreenW, scrSavPtr);
  2235.   printing := false;
  2236.   numbEnabled := neWas;
  2237.   bigNums := false;
  2238.   sNumBase := 0;
  2239.   sNumStart := 0;
  2240.   clearBoard;
  2241.   curMove := treeRoot;
  2242.   captures[black] := 0;
  2243.   captures[white] := 0;
  2244.   switchBranch(cmSave);
  2245.   curMove := cmSave;
  2246. end { printBoard };
  2247.  
  2248. procedure refreshBoard;
  2249. begin { refreshBoard }
  2250.   drawBoard;
  2251.   showAllStones;
  2252.   dotSX := -1;
  2253.   dotLast;
  2254. end { refreshBoard };
  2255.  
  2256. { initializes this module }
  2257. procedure initGoBoard;
  2258.  
  2259.   procedure beepInit;
  2260.   const
  2261.     size = (WordSize(beepBuf) * 7 + 255) div 256;
  2262.   var
  2263.     d: SoundType;
  2264.     i,j: integer;
  2265.     beepSeg: integer;
  2266.   begin { beepInit }
  2267.     createSegment(beepSeg, size, 1, size);
  2268.     new(0,4,StatPtr);
  2269.     for d := atari to die3 do
  2270.       new(beepSeg, 4, sounds[d]);
  2271.     for i := 0 to 63 do
  2272.       begin
  2273.         sounds[atari]^[i] := 511;
  2274.         case i mod 3 of
  2275.           0: sounds[koV]^[i] := -5;
  2276.           1: sounds[koV]^[i] := 34;
  2277.           2: sounds[koV]^[i] := 0;
  2278.         end;
  2279.         case i mod 4 of
  2280.           0: sounds[s3]^[i] := 1023;
  2281.           1: sounds[s3]^[i] := 0;
  2282.           2: sounds[s3]^[i] := -1;
  2283.           3: sounds[s3]^[i] := -1023;
  2284.         end;
  2285.        case i mod 5 of
  2286.           0: sounds[s4]^[i] := 43;
  2287.           1: sounds[s4]^[i] := 765;
  2288.           2: sounds[s4]^[i] := -432;
  2289.           3: sounds[s4]^[i] := -6;
  2290.           4: sounds[s4]^[i] := 345;
  2291.        end;
  2292.      end;
  2293.    for i := 0 to 1 do
  2294.      for j := 0 to 15 do
  2295.        begin
  2296.          sounds[die]^[i*32+j] := -1;
  2297.          sounds[die]^[i*32+16+j] := 0;
  2298.        end;
  2299.    for i := 0 to 63 do
  2300.      begin
  2301.        sounds[die2]^[i] := sounds[die]^[i];
  2302.        sounds[die3]^[i] := sounds[die]^[i];
  2303.      end;
  2304.   end { beepInit };
  2305.  
  2306.   procedure definePats;
  2307.   var
  2308.     i, j, blks, gbg: integer;
  2309.     fid: fileID;
  2310.   begin { definePats }
  2311.     fid := FSLookup('go.animate', blks, gbg);
  2312.     if fid = 0 then
  2313.       begin
  2314.         writeln('GO.ANIMATE not found');
  2315.         raise gbFatal;
  2316.       end
  2317.     else if blks < 8 then
  2318.       begin
  2319.         writeln('GO.ANIMATE too short');
  2320.         raise gbFatal;
  2321.       end;
  2322.     new(0, 4, stones[black]);
  2323.     FSBlkRead(fid, 0, recast(stones[black], pDirBlk));
  2324.     new(0, 4, stones[white]);
  2325.     FSBlkRead(fid, 1, recast(stones[white], pDirBlk));
  2326.     new(0, 4, hcDot);
  2327.     FSBlkRead(fid, 2, recast(hcDot, pDirBlk));
  2328.     new(0, 4, selCursor);
  2329.     FSBlkRead(fid, 3, recast(selCursor, pDirBlk));
  2330.     new(0, 4, stoneCir);
  2331.     FSBlkRead(fid, 4, recast(stoneCir, pDirBlk));
  2332.     new(0, 4, stoneMarks[0]);
  2333.     FSBlkRead(fid, 5, recast(stoneMarks[0], pDirBlk));
  2334.     new(0, 4, stoneMarks[1]);
  2335.     FSBlkRead(fid, 6, recast(stoneMarks[1], pDirBlk));
  2336.     new(0, 4, stoneMarks[2]);
  2337.     FSBlkRead(fid, 7, recast(stoneMarks[2], pDirBlk));
  2338.     new(0, 4, htBuf);
  2339.     for i := 0 to 47 do
  2340.       htBuf^[0, i] := #125252;
  2341.     for i := 0 to 47 do
  2342.       htBuf^[1, i] := 0;
  2343.     for i := 0 to 47 do
  2344.       htBuf^[2, i] := #125252;   { #52525 }
  2345.     for i := 0 to 47 do
  2346.       htBuf^[3, i] := 0;
  2347.     for i := 1 to 9 do
  2348.       new(0, 4, patch[i]);
  2349.   end { definePats };
  2350.  
  2351.   procedure setupFont;
  2352.   var
  2353.     bblks, sblks, tBlks, lBlks, bits, fontseg, i: integer;
  2354.     bFID, sFID, tFID, lFID: fileID;
  2355.     bp: pDirBlk;
  2356.   begin { setupFont }
  2357.     sysFont := getFont;
  2358.     bFID := FSLookup('goBNum.kst', bblks, bits);
  2359.     if bFID = 0 then
  2360.       begin
  2361.         writeln('goBNum.KST not found');
  2362.         raise gbFatal;
  2363.       end;
  2364.     sFID := FSLookup('goSNum.kst', sblks, bits);
  2365.     if sFID = 0 then
  2366.       begin
  2367.         writeln('goSNum.KST not found');
  2368.         raise gbFatal;
  2369.       end;
  2370.     tFID := FSLookup('goTNum.kst', tblks, bits);
  2371.     if sFID = 0 then
  2372.       begin
  2373.         writeln('goTNum.KST not found');
  2374.         raise gbFatal;
  2375.       end;
  2376.     lFID := FSLookup('goSLets.kst', lBlks, bits);
  2377.     if lFID = 0 then
  2378.       begin
  2379.         writeln('goSLets.KST not found');
  2380.         raise gbFatal;
  2381.       end;
  2382.     createSegment(fontseg, bblks + sblks + tBlks + lBlks, 1,
  2383.                   bblks + sblks + tBlks + lBlks);
  2384.     for i := 0 to bblks - 1 do
  2385.       begin
  2386.         bp := makePtr(fontSeg, i * 256, pDirBlk);
  2387.         FSBlkRead(bFID, i, bp);
  2388.       end;
  2389.     goBNumFont := makePtr(fontseg, 0, fontPtr);
  2390.     for i := 0 to sblks - 1 do
  2391.       begin
  2392.         bp := makePtr(fontSeg, (i + bblks) * 256, pDirBlk);
  2393.         FSBlkRead(sFID, i, bp);
  2394.       end;
  2395.     goSNumFont := makePtr(fontseg, bblks * 256, fontPtr);
  2396.     for i := 0 to tblks - 1 do
  2397.       begin
  2398.         bp := makePtr(fontSeg, (i + bblks + sBlks) * 256, pDirBlk);
  2399.         FSBlkRead(tFID, i, bp);
  2400.       end;
  2401.     goTNumFont := makePtr(fontseg, (bblks  + sBlks) * 256, fontPtr);
  2402.     for i := 0 to lBlks - 1 do
  2403.       begin
  2404.         bp := makePtr(fontSeg, (i + bblks + sBlks + tBlks) * 256, pDirBlk);
  2405.         FSBlkRead(lFID, i, bp);
  2406.       end;
  2407.     goSLetFont := makePtr(fontseg, (bblks  + sBlks + tBlks) * 256, fontPtr);
  2408.   end { setupFont };
  2409.  
  2410. begin { initGoBoard }
  2411.   printing := false;
  2412.   beepInit;
  2413.   definePats;
  2414.   setupFont;
  2415.   scrSavPtr := nil;
  2416.   sNumBase := 0;
  2417.   sNumStart := 0;
  2418.   bigNums := false;
  2419. end. { initGoBoard }
  2420.  
  2421. SHAR_EOF
  2422. fi
  2423. if test -f 'goCom.pas'
  2424. then
  2425.     echo shar: "will not over-write existing file 'goCom.pas'"
  2426. else
  2427. cat << \SHAR_EOF > 'goCom.pas'
  2428. {---------------------------------------------------------------------------}
  2429. { goCom.Pas                                                                 }
  2430. {                                                                           }
  2431. { Common Data for Go                                                        }
  2432. { Copyright (c) 1982 by Three Rivers Computer Corp.                         }
  2433. {                                                                           }
  2434. { Written: June 3, 1982 by Stoney Ballard                                   }
  2435. { Edit History:                                                             }
  2436. {    June  3, 1982 Started                                                  }
  2437. {    June  4, 1982 Add dead group removal                                   }
  2438. {    June 10, 1982 Use new go file manager                                  }
  2439. {    Nov   9, 1982 Split From Go.Pas                                        }
  2440. { V3.5 - Jan 11, 1983 Fixed bug in printer that screwed capture count       }
  2441. { V3.6 - Jan 14, 1983 Changed Scoring and board coordinates to conform to   }
  2442. {                     tournament rules                                      }
  2443. { V3.7 - Jan 17, 1983 added computer player!!!!                             }
  2444. { V3.8 - Mar  8, 1983 Added PrintDiagram                                    }
  2445. {                     Made board 34 grid for printing                       }
  2446. { V3.9 - May  3, 1983 Add board print size switch and command               }
  2447. {---------------------------------------------------------------------------}
  2448.  
  2449.  
  2450. module goCom;
  2451.  
  2452. exports
  2453.  
  2454. imports IO_Others from IO_Others;
  2455. imports fileDefs from fileDefs;
  2456.  
  2457. const
  2458.   version = '3.9';
  2459.  
  2460.   numPoints = 19;
  2461.   maxPoint = numPoints - 1;
  2462.   curC = 31;
  2463.   maxTagLen = 16;
  2464.  
  2465.   charHeight = 13;
  2466.   charWidth = 9;
  2467.  
  2468.   boardWin = 1;
  2469.   menuWin = 2;
  2470.   statWin = 3;
  2471.   bWinX = 0;
  2472.   bWinY = 0;
  2473.   bWinW = 768;
  2474.   bWinH = 768;
  2475.   mWinX = 0;
  2476.   mWinY = 768;
  2477.   mWinW = 768;
  2478.   mWinH = 192;
  2479.   sWinX = 0;
  2480.   sWinY = 960;
  2481.   sWinW = 768;
  2482.   sWinH = 64;
  2483.  
  2484.   promptX = sWinX + 32;
  2485.   lineY = 4;
  2486.   lineDel = 2;
  2487.   promptLine = 1;
  2488.   tagLine = 2;
  2489.   cmtLine = 3;
  2490.  
  2491.   boardX = bWinX + 64;
  2492.   boardY = bWinY + 32;
  2493.   pBoardX = bWinX + 44;  { for printing }
  2494.   pBoardY = bWinY + 24;
  2495.   
  2496.   passX = bWinX + 321;
  2497.   passY = bWinY + 712;  { 712 }
  2498.   passW = 126;
  2499.   passH = 13;
  2500.  
  2501.   captBX = bWinX + 64;
  2502.   captWX = bWinX + 578;
  2503.   captY = bWinY + 712;  { 712 }
  2504.  
  2505.   captNBX = captBX + 45;
  2506.   captNWX = captWX + 45;
  2507.   captNY = bWinY + 732; { 732 }
  2508.  
  2509.   turnX = bWinX + 325;
  2510.   turnY = bWinY + 752;  { 752 }
  2511.  
  2512.   none = -1;
  2513.   mInit = 1;
  2514.   mSetHc = 2;
  2515.   mPass = 3;
  2516.   mScore = 4;
  2517.   mForToBr = 5;
  2518.   mBackToBr = 6;
  2519.   mBackToStone = 7;
  2520.   mForToLeaf = 8;
  2521.   mPutTag = 9;
  2522.   mGotoTag = 10;
  2523.   mGotoRoot = 11;
  2524.   mPutCmt = 12; 
  2525.   mReadFile = 13;
  2526.   mWriteFile = 14;
  2527.   mPruneBranches = 15;
  2528.   mTogNums = 16;
  2529.   mPrintBoard = 17;
  2530.   mStepToTag = 18;
  2531.   mSetStepTag = 19;
  2532.   mQuit = 20;
  2533.   mBackOne = 21;
  2534.   mForOne = 22;
  2535.   mEraseMove = 23;
  2536.   mAutoPlay = 24;
  2537.   mPlayMyself = 25;
  2538.   mSetPlayLevel = 26;
  2539.   mDebug = 27;
  2540.   mRefBoard = 28;
  2541.   mShoState = 29;
  2542.   mPrintDiag = 30;
  2543.   mBoardSize = 31;
  2544.   mLast = 31;  { the last command in the menu }
  2545.   mPlaceStone = 32;  { this command is not in the menu }
  2546.   mCtlC = 33;   { nor is this }
  2547.  
  2548. type
  2549.   bVal = (black, white, empty, alternate); 
  2550.   sType = black..white;
  2551.   bRec = record
  2552.            val: bval;
  2553.            xOfs, yOfs: integer;
  2554.            mNum: integer;
  2555.            marked: boolean;
  2556.          end;
  2557.  
  2558.   boardArray = array[0..maxPoint] of array[0..maxPoint] of bRec;
  2559.  
  2560.   picBuf = array[0..63] of array[0..3] of integer;
  2561.   pPicBuf = ^picBuf;
  2562.  
  2563. var
  2564.   board: boardArray;
  2565.   captures: array[sType] of integer;
  2566.   moveNum: integer;
  2567.   koX, koY: integer;
  2568.   selCursor: curPatPtr;
  2569.   dotSX, dotSY: integer;
  2570.   passShowing: boolean;
  2571.   numbEnabled: boolean;
  2572.   treeDirty: boolean;
  2573.   gameFName: pathName;
  2574.   debug: boolean;
  2575.   printLarge: boolean;
  2576.  
  2577. private
  2578.  
  2579. procedure comBug;
  2580. begin { comBug }
  2581. end. { comBug }
  2582. SHAR_EOF
  2583. fi
  2584. if test -f 'goMenu.pas'
  2585. then
  2586.     echo shar: "will not over-write existing file 'goMenu.pas'"
  2587. else
  2588. cat << \SHAR_EOF > 'goMenu.pas'
  2589. {---------------------------------------------------------------}
  2590. { Go Menu Manager                                               }
  2591. { Copyright (c) 1982 by Three Rivers Computer Corp.             }
  2592. {                                                               }
  2593. { Written: December 3, 1982 by Stoney Ballard                   }
  2594. { Edit History:                                                 }
  2595. {                                                               }
  2596. {   Jan  5, 1983 - Fixed bug in menu select                     }
  2597. {   Jan 27, 1983 - added setPlayLevel                           }
  2598. {---------------------------------------------------------------}
  2599.  
  2600. module goMenu;
  2601.  
  2602. exports
  2603.  
  2604. imports fileDefs from fileDefs;
  2605. imports goTree from goTree;
  2606.  
  2607. procedure initMenu;
  2608. function getMenuCmd: integer;
  2609. procedure endCmd;
  2610. procedure putMString(cmd: integer; ms: string);
  2611. procedure activate(cmd: integer; act: boolean);
  2612. procedure restoreCursor;
  2613. function confirmed: boolean;
  2614. function menuGoFile(var fName: pathName): boolean;
  2615. procedure waitNoButton;
  2616. procedure waitButton;
  2617. procedure clearLine(ln: integer);
  2618. procedure prompt(s: string);
  2619. procedure showComment;
  2620. procedure showTag;
  2621. function getHCMenu: integer;
  2622. function getTagMenu: tagPtr;
  2623. procedure setMenuCursor;
  2624. procedure menuPlayLevel(var playLevel: integer; maxLevel: integer);
  2625.  
  2626. private
  2627.  
  2628. imports goCom from goCom;
  2629. imports goMgr from goMgr;
  2630. imports popUp from popUp;
  2631. imports raster from raster;
  2632. imports screen from screen;
  2633. imports IO_Others from IO_Others;
  2634. imports fileSystem from fileSystem;
  2635. imports fileUtils from fileUtils;
  2636. imports perq_String from perq_String;
  2637.  
  2638. const
  2639.   mWidth = 180;
  2640.   mHeight = 18;
  2641.   mLBorder = 12;
  2642.   mTBorder = 10;
  2643.   mVSpacing = mHeight + 4;
  2644.   mHSpacing = mWidth + 8;
  2645.   grHeight = mHeight - 2;
  2646.   grWidth = (((mWidth - 2 + 15) div 16 + 3) div 4) * 4;
  2647.  
  2648. type
  2649.   mStr = string[20];
  2650.  
  2651.   menuBox = record
  2652.               leftX, topY, rightX, botY: integer;
  2653.               isAct: boolean;
  2654.               str: mStr;
  2655.             end;
  2656.  
  2657.   greyPat = array[0..grHeight - 1] of array[0..grWidth - 1] of integer;
  2658.   pGreyPat = ^greyPat;
  2659.  
  2660. var
  2661.   mItems: array[1..mLast] of menuBox;
  2662.   curHiLi, curCmd: integer;
  2663.   mGreyP: pGreyPat;
  2664.   isMenuCursor: boolean;
  2665.   valDesc: pNameDesc;
  2666.   cnfDesc: pNameDesc;
  2667.   res: resRes;
  2668.   goFNames: array[1..1024] of string[25];
  2669.   tabXPos, tabYPos: integer;
  2670.  
  2671. procedure restoreCursor;
  2672. begin { restoreCursor }
  2673.   if isMenuCursor then
  2674.     IOLoadCursor(defaultCursor, 0, 0)
  2675.   else
  2676.     IOLoadCursor(selCursor, curC, curC);
  2677. end { restoreCursor };
  2678.  
  2679. procedure waitNoButton;
  2680. begin { waitNoButton }
  2681.   while tabYellow or tabWhite or tabGreen or tabBlue or tabSwitch do;
  2682. end { waitNoButton };
  2683.  
  2684. procedure waitButton;
  2685. begin { waitButton }
  2686.   while not tabSwitch do;
  2687. end { waitButton };
  2688.  
  2689. procedure menuPlayLevel(var playLevel: integer; maxLevel: integer);
  2690. var
  2691.   plMenu: pNameDesc;
  2692.   i: integer;
  2693.   res: resres;
  2694.  
  2695.   handler outside;
  2696.   begin { outside }
  2697.     destroyNameDesc(plMenu);
  2698.     write(''); {control-G}
  2699.     waitNoButton;
  2700.     exit(menuPlayLevel);
  2701.   end { outside };
  2702.  
  2703. begin { menuPlayLevel }
  2704.   allocNameDesc(maxLevel + 1, 0, plMenu);
  2705.   plMenu^.header := 'Play Level?';
  2706.   for i := 0 to maxLevel do
  2707.     begin
  2708. {$R-}
  2709.       plMenu^.commands[i + 1] := intToStr(i);
  2710. {$R=}
  2711.     end;
  2712.   menu(plMenu, false, 1, maxLevel + 1, -1, -1, -1, res);
  2713.   playLevel := res^.indices[1] - 1;
  2714.   destroyRes(res);
  2715.   destroyNameDesc(plMenu);
  2716. end { menuPlayLevel };
  2717.  
  2718. function getTagMenu: tagPtr;
  2719. var
  2720.   tp: tagPtr;
  2721.   nTags, tIdx, i: integer;
  2722.   tMenu: pNameDesc;
  2723.   res: resres;
  2724.  
  2725.   handler outside;
  2726.   begin { outside }
  2727.     destroyNameDesc(tMenu);
  2728.     write(''); {control-G}
  2729.     waitNoButton;
  2730.     exit(getTagMenu);
  2731.   end { outside };
  2732.  
  2733. begin { getTagMenu }
  2734.   getTagMenu := nil;
  2735.   tp := treeRoot^.lastTag;
  2736.   nTags := 0;
  2737.   while tp <> nil do
  2738.     begin
  2739.       nTags := nTags + 1;
  2740.       tp := tp^.nextTag;
  2741.     end;
  2742.   if nTags = 0 then
  2743.     write('') {control-G}
  2744.   else
  2745.     begin
  2746.       tp := treeRoot^.lastTag;
  2747.       allocNameDesc(nTags, 0, tMenu);
  2748.       tMenu^.header := 'Which Tag?';
  2749.       for i := nTags downTo 1 do
  2750.         begin
  2751. {$R-}
  2752.           tMenu^.commands[i] := tp^.sTag;
  2753. {$R=}
  2754.           tp := tp^.nextTag;
  2755.         end;
  2756.       menu(tMenu, false, 1, nTags, -1, -1, -1, res);
  2757.       restoreCursor;
  2758.       tIdx := nTags - res^.indices[1];
  2759.       destroyRes(res);
  2760.       destroyNameDesc(tMenu);
  2761.       tp := treeRoot^.lastTag;
  2762.       for i := 1 to tIdx do
  2763.         tp := tp^.nextTag;
  2764.       getTagMenu := tp;
  2765.     end;
  2766. end { getTagMenu };
  2767.  
  2768. procedure clearLine(ln: integer);
  2769. var
  2770.   lY: integer;
  2771. begin { clearLine }
  2772.   lY := winTable[statWin].winTY +
  2773.         (ln * (charHeight + lineDel)) + lineY - charHeight;
  2774.   rasterop(RAndNot, sWinW - promptX - 32, charHeight,
  2775.                     promptX, lY, SScreenW, SScreenP,
  2776.                     promptX, lY, SScreenW, SScreenP);
  2777. end { clearLine };
  2778.  
  2779. procedure posLine(ln: integer);
  2780. var
  2781.   lY: integer;
  2782. begin { posLine }
  2783.   clearLine(ln);
  2784.   lY := winTable[statWin].winTY + (ln * (charHeight + lineDel)) + lineY;
  2785.   SSetCursor(promptX, lY);
  2786. end { posLine };
  2787.  
  2788. procedure prompt(s: string);
  2789. begin { prompt }
  2790.   posLine(promptLine);
  2791.   write(s);
  2792. end { prompt };
  2793.  
  2794. procedure showTag;
  2795. var
  2796.   ts: string;
  2797. begin { showTag }
  2798.   posLine(tagLine);
  2799.   if getTag(curMove, ts) then
  2800.     write('Tag: ', ts);
  2801. end { showTag };
  2802.  
  2803. procedure showComment;
  2804. var
  2805.   cs: string;
  2806. begin { showComment }
  2807.   posLine(cmtLine);
  2808.   if getComment(curMove, cs) then
  2809.     write('Comment: ', cs);
  2810. end { showComment };
  2811.  
  2812. function getHCMenu: integer;
  2813. var
  2814.   res: resres;
  2815.  
  2816.   handler outside;
  2817.   begin { outside }
  2818.     restoreCursor;
  2819.     getHCMenu := none;
  2820.     write(''); {control-G}
  2821.     exit(getHCMenu);
  2822.   end { outside };
  2823.  
  2824. begin { getHCMenu }
  2825.   menu(valDesc, false, 1, 8, -1, -1, -1, res);
  2826.   restoreCursor;
  2827.   getHCMenu := res^.indices[1] + 1;
  2828.   destroyRes(res);
  2829. end { getHCMenu };
  2830.  
  2831. function menuGoFile(var fName: pathName): boolean;
  2832. var
  2833.   fi, i: integer;
  2834.   fid: fileID;
  2835.   fileMenu: pNameDesc;
  2836.   res: resres;
  2837.   scanP: ptrScanRecord;
  2838.  
  2839.   function isGoFName(var rName: string): boolean;
  2840.   var
  2841.     ts: string;
  2842.   begin { isGoFName }
  2843.     isGoFName := false;
  2844.     ts := rName;
  2845.     convUpper(ts);
  2846.     if length(ts) < 3 then
  2847.       exit(isGoFName);
  2848.     ts := subStr(ts, length(ts) - 2, 3);
  2849.     if ts = '.GO' then
  2850.       begin
  2851.         rName := subStr(rName, 1, length(rName) - 3);
  2852.         isGoFName := true;
  2853.       end;
  2854.   end { isGoFName };
  2855.  
  2856.   handler outside;
  2857.   begin { outside }
  2858.     destroyNameDesc(fileMenu);
  2859.     restoreCursor;
  2860.     menuGoFile := false;
  2861.     write(''); {control-G}
  2862.     exit(menuGoFile);
  2863.   end { outside };
  2864.  
  2865. begin { menuGoFile }
  2866.   new(scanP);
  2867.   scanP^.initialCall := true;
  2868.   scanP^.dirName := '';
  2869.   prompt('Scanning Directory...');
  2870.   fi := 0;
  2871.   while FSScan(scanP, fName, fid) do
  2872.     if isGoFName(fName) then
  2873.       begin
  2874.         fi := fi + 1;
  2875.         goFNames[fi] := fName;
  2876.       end;
  2877.   dispose(scanP);
  2878.   prompt('');
  2879.   if fi < 1 then
  2880.     begin
  2881.       prompt('No GO files found');
  2882.       menuGoFile := false;
  2883.       exit(menuGoFile);
  2884.     end;
  2885.   allocNameDesc(fi, 0, fileMenu);
  2886.   fileMenu^.header := 'Available Games';
  2887.   for i := 1 to fi do
  2888.     begin
  2889. {$R-}
  2890.       fileMenu^.commands[i] := goFNames[i];
  2891. {$R=}
  2892.     end;
  2893.   menu(fileMenu, false, 1, fi, -1, -1, -1, res);
  2894.   restoreCursor;
  2895.   destroyNameDesc(fileMenu);
  2896.   fName := goFNames[res^.indices[1]];
  2897.   destroyRes(res);
  2898.   menuGoFile := true;
  2899. end { menuGoFile };
  2900.  
  2901. function confirmed: boolean;
  2902.  
  2903.   handler outside;
  2904.   begin { outside }
  2905.     confirmed := false;
  2906.     restoreCursor;
  2907.     exit(confirmed);
  2908.   end { outside };
  2909.  
  2910. begin { confirmed }
  2911.   if treeDirty then
  2912.     begin
  2913.       menu(cnfDesc, false, 1, 2, -1, -1, -1, res);
  2914.       restoreCursor;
  2915.       confirmed := res^.indices[1] = 2;
  2916.       destroyRes(res);
  2917.     end
  2918.   else
  2919.     confirmed := true;
  2920. end { confirmed };
  2921.  
  2922. procedure activate(cmd: integer; act: boolean);
  2923. var
  2924.   dFun: lineStyle;
  2925. begin { activate }
  2926.   with mItems[cmd] do
  2927.     begin
  2928.       isAct := act;
  2929.       if isAct then
  2930.         dFun := drawLine
  2931.       else
  2932.         dFun := eraseLine;
  2933.       line(dFun, leftX, topY, rightX, topY, SScreenP);
  2934.       line(dFun, leftX, botY, rightX, botY, SScreenP);
  2935.       line(dFun, leftX, topY, leftX, botY, SScreenP);
  2936.       line(dFun, rightX, topY, rightX, botY, SScreenP);
  2937.     end;
  2938. end { activate };
  2939.  
  2940. function findItem(x, y: integer): integer;
  2941. var
  2942.   i: integer;
  2943. begin { findItem }
  2944.   for i := 1 to mLast do
  2945.     with mItems[i] do
  2946.       if isAct then
  2947.         if (x >= leftX) and (x <= rightX) and
  2948.            (y >= topY) and (y <= botY) then
  2949.           begin
  2950.             findItem := i;
  2951.             exit(findItem);
  2952.           end;
  2953.   findItem := none;
  2954. end { findItem };
  2955.  
  2956. procedure invertItem(cmd: integer);
  2957. begin { invertItem }
  2958.   with mItems[cmd] do
  2959.     rasterop(rNot, mWidth - 2, mHeight - 2,
  2960.                    leftX + 1, topY + 1, SScreenW, SScreenP,
  2961.                    leftX + 1, topY + 1, SScreenW, SScreenP);
  2962. end { invertItem };
  2963.  
  2964. procedure checkHighLight;
  2965. var
  2966.   cmd: integer;
  2967. begin { checkHighLight }
  2968.   cmd := findItem(tabXPos, tabYPos);
  2969.   if cmd <> curHiLi then
  2970.     begin
  2971.       if curHiLi <> none then
  2972.         invertItem(curHiLi);
  2973.       if cmd <> none then
  2974.         invertItem(cmd);
  2975.       curHiLi := cmd;
  2976.     end;
  2977. end { checkHighLight };
  2978.  
  2979. procedure writeMStr(cmd, cFunc: integer);
  2980. begin { writeMStr }
  2981.   SChrFunc(cFunc);
  2982.   with mItems[cmd] do
  2983.     begin
  2984.       SSetCursor(leftX + 9, botY - 2);
  2985.       write(str);
  2986.     end;
  2987.   SChrFunc(rRpl);
  2988. end { writeMStr };
  2989.  
  2990. procedure xorGrey(cmd: integer);
  2991. begin { xorGrey }
  2992.   if (cmd <> none) and (cmd <= mLast) then
  2993.     with mItems[cmd] do
  2994.       rasterop(rXor, mWidth - 2, mHeight - 2,
  2995.                      leftX + 1, topY + 1, SScreenW, SScreenP,
  2996.                      0, 0, grWidth, mGreyP);
  2997. end { xorGrey };
  2998.  
  2999. procedure selItem(cmd: integer);
  3000. begin { selItem }
  3001.   xorGrey(cmd);
  3002.   writeMStr(cmd, rOr);
  3003. end { selItem };
  3004.  
  3005. procedure deSelItem(cmd: integer);
  3006. begin { deSelItem }
  3007.   xorGrey(cmd);
  3008.   writeMStr(cmd, rAndNot);
  3009. end { deSelItem };
  3010.  
  3011. procedure setMenuCursor;
  3012. begin { setMenuCursor }
  3013.   if not isMenuCursor then
  3014.     begin
  3015.       IOLoadCursor(defaultCursor, 0, 0);
  3016.       isMenuCursor := true;
  3017.     end;
  3018. end { setMenuCursor };
  3019.  
  3020. function getMenuCmd: integer;
  3021. var
  3022.   cmd, nCmd: integer;
  3023.   gOn: boolean;
  3024. begin { getMenuCmd }
  3025.   tabXPos := tabRelX;
  3026.   tabYPos := tabRelY;
  3027.   with winTable[boardWin] do
  3028.     if (tabXPos >= winLX) and (tabXPos <= winRX) and
  3029.        (tabYPos >= winTY) and (tabYPos <= winBY) then
  3030.       begin
  3031.         if isMenuCursor then
  3032.           IOLoadCursor(selCursor, curC, curC);
  3033.         isMenuCursor := false;
  3034.       end
  3035.     else
  3036.       setMenuCursor;
  3037.   checkHighLight;
  3038.   if not tabSwitch then
  3039.     curCmd := none
  3040.   else if tabWhite then
  3041.     begin
  3042.       with mItems[mBackOne] do
  3043.         if isAct then
  3044.           begin
  3045.             cmd := mBackOne;
  3046.             if curHiLi <> cmd then
  3047.               begin
  3048.                 if curHiLi <> none then
  3049.                   invertItem(curHiLi);
  3050.                 invertItem(cmd);
  3051.               end;
  3052.             curHiLi := cmd;
  3053.             curCmd := cmd;
  3054.             selItem(cmd);
  3055.           end
  3056.         else
  3057.           write(''); {control-G}
  3058.       waitNoButton;
  3059.     end
  3060.   else if tabGreen then
  3061.     begin
  3062.       with mItems[mForOne] do
  3063.         if isAct then
  3064.           begin
  3065.             cmd := mForOne;
  3066.             if curHiLi <> cmd then
  3067.               begin
  3068.                 if curHiLi <> none then
  3069.                   invertItem(curHiLi);
  3070.                 invertItem(cmd);
  3071.               end;
  3072.             curHiLi := cmd;
  3073.             curCmd := cmd;
  3074.             selItem(cmd);
  3075.           end
  3076.         else
  3077.           write(''); {control-G}
  3078.       waitNoButton;
  3079.     end
  3080.   else { tabYellow or tabBlue }
  3081.     begin
  3082.       cmd := findItem(tabXPos, tabYPos);
  3083.       if cmd <> none then
  3084.         begin
  3085.           selItem(cmd);
  3086.           gOn := true;
  3087.           while tabSwitch do
  3088.             begin
  3089.               nCmd := findItem(tabRelX, tabRelY);
  3090.               if nCmd <> cmd then
  3091.                 begin
  3092.                   if gOn then
  3093.                     deSelItem(cmd);
  3094.                   gOn := false;
  3095.                 end
  3096.               else
  3097.                 begin
  3098.                   if not gOn then
  3099.                     selItem(cmd);
  3100.                   gOn := true;
  3101.                 end;  
  3102.             end;
  3103.           if gOn then
  3104.             begin
  3105.               curCmd := cmd;
  3106.             end
  3107.           else
  3108.             begin
  3109.               write(''); {control-G}
  3110.               curCmd := none;
  3111.             end;
  3112.           waitNoButton;
  3113.         end
  3114.       else
  3115.         with winTable[boardWin] do
  3116.           if (tabXPos >= winLX) and (tabXPos <= winRX) and
  3117.              (tabYPos >= winTY) and (tabYPos <= winBY) then
  3118.             curCmd := mPlaceStone
  3119.           else
  3120.             begin
  3121.               write(''); {control-G}
  3122.               curCmd := none;
  3123.               waitNoButton;
  3124.             end;
  3125.     end;
  3126.   getMenuCmd := curCmd;
  3127. end { getMenuCmd };
  3128.  
  3129. procedure endCmd;
  3130. begin { endCmd }
  3131.   if (curCmd <> none) and (curCmd <= mLast) then
  3132.     deSelItem(curCmd);
  3133.   curCmd := none;
  3134. end { endCmd };
  3135.  
  3136. procedure putMString(cmd: integer; ms: string);
  3137. begin { putMString }
  3138.   if (curCmd = cmd) and (cmd <= mLast) then
  3139.     begin
  3140.       deSelItem(cmd);
  3141.       curCmd := none;
  3142.     end;
  3143.   with mItems[cmd] do
  3144.     begin
  3145.       rasterOp(rAndNot, mWidth - 2, mHeight - 2,
  3146.                leftX + 1, topY + 1, SScreenW, SScreenP,
  3147.                leftX + 1, topY + 1, SScreenW, SScreenP);
  3148.       str := ms;
  3149.       writeMStr(cmd, rRpl);
  3150.       if curHiLi = cmd then
  3151.         invertItem(cmd);
  3152.     end;
  3153. end { putMString };
  3154.  
  3155. procedure initMenu;
  3156. var
  3157.   i, j: integer;
  3158.  
  3159.   procedure setItem(cmd, sx, sy: integer; cs: string);
  3160.   begin { setItem }
  3161.     with mItems[cmd] do
  3162.       begin
  3163.         leftX := (sx * mHSpacing) + mLBorder + mWinX;
  3164.         topY := (sy * mVSpacing) + mTBorder + mWinY;
  3165.         isAct := false;
  3166.         rightX := leftX + mWidth - 1;
  3167.         botY := topY + mHeight - 1;
  3168.         putMString(cmd, cs);
  3169.       end;
  3170.   end { setItem };
  3171.  
  3172. begin { initMenu }
  3173.   curHiLi := none;
  3174.   curCmd := none;
  3175.   setItem(mPass, 0, 0, 'Pass');
  3176.   setItem(mAutoPlay, 0, 1, 'Generate Move');
  3177.   setItem(mPlayMyself, 0, 2, 'Play Myself');
  3178.   setItem(mSetPlayLevel, 0, 3, 'Set Play Level');
  3179.   setItem(mSetHC, 0, 4, 'Set Handicap');
  3180.   setItem(mScore, 0, 5, 'Score');
  3181.   setItem(mQuit, 0, 6, 'Quit');
  3182.   setItem(mInit, 0, 7, 'Initialize');
  3183.   setItem(mBackOne, 1, 0, 'Backup One');
  3184.   setItem(mGotoRoot, 1, 1, 'Back to Start');
  3185.   setItem(mBackToBr, 1, 2, 'Back to Branch');
  3186.   setItem(mBackToStone, 1, 3, 'Back to Stone');
  3187.   setItem(mEraseMove, 1, 4, 'Erase Move');
  3188.   setItem(mPruneBranches, 1, 5, 'Prune Branches');
  3189.   setItem(mDebug, 1, 6, 'Turn Debug On');
  3190.   setItem(mWriteFile, 1, 7, 'Write File');
  3191.   setItem(mForOne, 2, 0, 'Forward One');
  3192.   setItem(mForToLeaf, 2, 1, 'Forward to Leaf');
  3193.   setItem(mForToBr, 2, 2, 'Forward to Branch');
  3194.   setItem(mStepToTag, 2, 3, 'Step Towards Tag');
  3195.   setItem(mGotoTag, 2, 5, 'Go To Tag');
  3196.   setItem(mRefBoard, 2, 6, 'Refresh Board');
  3197.   setItem(mReadFile, 2, 7, 'Read File');
  3198.   setItem(mPutTag, 3, 0, 'Put Tag');
  3199.   setItem(mPutCmt, 3, 1, 'Put Comment');
  3200.   setItem(mSetStepTag, 3, 2, 'Set Step Tag');
  3201.   setItem(mShoState, 3, 3, 'Show Player State');
  3202.   setItem(mTogNums, 3, 4, 'Show Stone Numbers');
  3203.   setItem(mBoardSize, 3, 5, 'Use Small Board');
  3204.   setItem(mPrintBoard, 3, 6, 'Print Board');
  3205.   setItem(mPrintDiag, 3, 7, 'Print Diagram');
  3206.   initPopUp;
  3207.   allocNameDesc(8, 0, valDesc);
  3208.   with valDesc^ do
  3209.     begin
  3210. {$R-}
  3211.       header := 'How Many?';
  3212.       commands[1] := '2';
  3213.       commands[2] := '3';
  3214.       commands[3] := '4';
  3215.       commands[4] := '5';
  3216.       commands[5] := '6';
  3217.       commands[6] := '7';
  3218.       commands[7] := '8';
  3219.       commands[8] := '9';
  3220. {$R=}
  3221.     end;
  3222.   allocNameDesc(2, 0, cnfDesc);
  3223.   with cnfDesc^ do
  3224.     begin
  3225.       header := 'Confirm';
  3226. {$R-}
  3227.       commands[1] := 'No';
  3228.       commands[2] := 'Yes';
  3229. {$R=}
  3230.     end;
  3231.   new(0, 4, mGreyP);
  3232.   i := 0;
  3233.   repeat
  3234.     for j := 0 to (grWidth - 1) do
  3235.       case (i mod 4) of
  3236.         0, 2:
  3237.           mGreyP^[i, j] := #177777;
  3238.         1:
  3239.           mGreyP^[i, j] := #125252;
  3240.         3:
  3241.           mGreyP^[i, j] := #052525;
  3242.       end;
  3243.     i := i + 1;
  3244.   until i > (grHeight - 1);
  3245.   isMenuCursor := true;
  3246. end. { initMenu }
  3247.  
  3248. SHAR_EOF
  3249. fi
  3250. if test -f 'goMgr.pas'
  3251. then
  3252.     echo shar: "will not over-write existing file 'goMgr.pas'"
  3253. else
  3254. cat << \SHAR_EOF > 'goMgr.pas'
  3255. {---------------------------------------------------------------}
  3256. { GoMgr.Pas                                                     }
  3257. {                                                               }
  3258. { Go Game Manager                                               }
  3259. { Copyright (c) 1982 by Three Rivers Computer Corp.             }
  3260. {                                                               }
  3261. { Written: June 3, 1982 by Stoney Ballard                       }
  3262. { Edit History:                                                 }
  3263. {    June  3, 1982  Started                                     }
  3264. {    June  4, 1982  Add dead group removal                      }
  3265. {    June 10, 1982  Use new go file manager                     }
  3266. {    Nov   9, 1982  Extracted from GO.PAS                       }
  3267. {---------------------------------------------------------------}
  3268.  
  3269. module goMgr;
  3270.  
  3271. exports
  3272.  
  3273. imports goCom from goCom;
  3274. imports goTree from goTree;
  3275.  
  3276. var
  3277.   curMove: pMRec;
  3278.   gameOver: boolean;
  3279.   passIsAlt: boolean;
  3280.  
  3281. procedure initGoMgr;
  3282. procedure backUp1;
  3283. procedure doMove(which: sType; ix, iy, pox, poy: integer);
  3284. procedure doPass(which: sType);
  3285. procedure doHCPlay(num: integer);
  3286. procedure forwardTo(m: pMRec);
  3287. procedure forwToBr;
  3288. procedure backToBr;
  3289. procedure showAlts;
  3290. procedure remAlts;
  3291. procedure selAlt(lx, ly: integer);
  3292. procedure selPass;
  3293. function atBranch(cm: pMRec): boolean;
  3294. function atLeaf(cm: pMRec): boolean;
  3295. procedure checkAtari(cm: pMRec);
  3296. procedure switchBranch(bm: pMRec);
  3297. procedure scoreGame(var ws, bs: integer);
  3298. procedure putEnd;
  3299. procedure delGroup(bx, by: integer);
  3300. procedure restoreDead;
  3301. procedure dotLast;
  3302. function lastPlayAt(bx, by: integer): boolean;
  3303. procedure doStepTag;
  3304. function stepTagPossible: boolean;
  3305. procedure wipeTreeMarks;
  3306.  
  3307. private
  3308.  
  3309. imports goBoard from goBoard;
  3310. imports goMenu from goMenu;
  3311. imports screen from screen;
  3312.  
  3313. type
  3314.   deadRec = record
  3315.               dx, dy, dox, doy, mn: integer;
  3316.               whoDead: sType;
  3317.             end;
  3318.  
  3319. var
  3320.   killX, killY: integer;
  3321.   endDead: array[1..361] of deadRec;
  3322.   numEndDead: integer;
  3323.  
  3324. procedure wipeMarks;
  3325. var
  3326.   i, j: integer;
  3327. begin { wipeMarks }
  3328.   for i := 0 to maxPoint do
  3329.     for j := 0 to maxPoint do
  3330.       board[i, j].marked := false;
  3331. end { wipeMarks };
  3332.  
  3333. procedure wipeTreeMarks;
  3334.  
  3335.   procedure recWipe(m: pMRec);
  3336.   begin { recWipe }
  3337.     while m <> nil do
  3338.       begin
  3339.         recWipe(m^.slink);
  3340.         m^.mark := false;
  3341.         m := m^.flink;
  3342.       end;
  3343.   end { recWipe };
  3344.  
  3345. begin { wipeTreeMarks }
  3346.   treeRoot^.mark := false;
  3347.   if treeRoot^.flink <> nil then
  3348.     recWipe(treeRoot^.flink);
  3349. end { wipeTreeMarks };
  3350.  
  3351. procedure spanGroup(s: sType; xi, yi: integer; var libs, size: integer);
  3352. begin { spanGroup }
  3353.   if (xi >= 0) and (xi <= maxPoint) and
  3354.      (yi >= 0) and (yi <= maxPoint) then
  3355.     with board[xi, yi] do
  3356.       if not marked then
  3357.         if val = empty then
  3358.           begin
  3359.             libs := libs + 1;
  3360.             marked := true;
  3361.           end
  3362.         else if val = s then
  3363.           begin
  3364.             marked := true;
  3365.             size := size + 1;
  3366.             spanGroup(s, xi - 1, yi, libs, size);
  3367.             spanGroup(s, xi + 1, yi, libs, size);
  3368.             spanGroup(s, xi, yi - 1, libs, size);
  3369.             spanGroup(s, xi, yi + 1, libs, size);
  3370.           end;
  3371. end { spanGroup };
  3372.  
  3373. function libertyCount(xi, yi: integer): integer;
  3374. var
  3375.   libs, size: integer;
  3376. begin { libertyCount }
  3377.   wipeMarks;
  3378.   libs := 0; 
  3379.   size := 0;
  3380.   spanGroup(board[xi, yi].val, xi, yi, libs, size);
  3381.   libertyCount := libs;
  3382. end { libertyCount };
  3383.  
  3384. function groupSize(xi, yi: integer): integer;
  3385. var
  3386.   gbg, size: integer;
  3387. begin { groupSize }
  3388.   wipeMarks;
  3389.   size := 0;
  3390.   gbg := 0;
  3391.   spanGroup(board[xi, yi].val, xi, yi, gbg, size); 
  3392.   groupSize := size;
  3393. end { groupSize };
  3394.  
  3395. procedure killGroup(s: sType; xi, yi: integer);
  3396. begin { killGroup }
  3397.   if (xi >= 0) and (xi <= maxPoint) and
  3398.      (yi >= 0) and (yi <= maxPoint) then
  3399.     with board[xi, yi] do
  3400.       if val = s then
  3401.         begin
  3402.           remStone(xi, yi);
  3403.           curMove := newMove(curMove);
  3404.           with curMove^ do
  3405.             begin
  3406.               mx := xi;
  3407.               my := yi;
  3408.               ox := board[xi, yi].xOfs;
  3409.               oy := board[xi, yi].yOfs;
  3410.               moveN := board[xi, yi].mNum;
  3411.               who := s;
  3412.               id := remove;
  3413.             end;
  3414.           curMove := mergeMove(curMove);
  3415.           killGroup(s, xi - 1, yi);
  3416.           killGroup(s, xi + 1, yi);
  3417.           killGroup(s, xi, yi - 1);
  3418.           killGroup(s, xi, yi + 1);
  3419.         end;
  3420. end { killGroup };
  3421.  
  3422. procedure remDead(xi, yi: integer; var numDead: integer);
  3423. var
  3424.   i, j, libs, size: integer;
  3425.   s, other: bVal;
  3426.  
  3427. begin { remDead }
  3428.   numDead := 0;
  3429.   s := board[xi, yi].val;
  3430.   if s = white then
  3431.     other := black
  3432.   else
  3433.     other := white;
  3434.   if xi > 0 then
  3435.     if (board[xi - 1, yi].val = other) then
  3436.       begin
  3437.         wipeMarks;
  3438.         libs := 0;
  3439.         size := 0;
  3440.         spanGroup(other, xi - 1, yi, libs, size);
  3441.         if libs = 0 then
  3442.           begin
  3443.             killGroup(other, xi - 1, yi);
  3444.             numDead := numDead + size;
  3445.             killX := xi - 1;
  3446.             killY := yi;
  3447.           end;
  3448.       end;
  3449.   if xi < maxPoint then
  3450.     if (board[xi + 1, yi].val = other) then
  3451.       begin
  3452.         wipeMarks;
  3453.         libs := 0;
  3454.         size := 0;
  3455.         spanGroup(other, xi + 1, yi, libs, size);
  3456.         if libs = 0 then
  3457.           begin
  3458.             killGroup(other, xi + 1, yi);
  3459.             numDead := numDead + size;
  3460.             killX := xi + 1;
  3461.             killY := yi;
  3462.           end;
  3463.       end;
  3464.   if yi > 0 then 
  3465.     if (board[xi, yi - 1].val = other) then
  3466.       begin
  3467.         wipeMarks;
  3468.         libs := 0;
  3469.         size := 0;
  3470.         spanGroup(other, xi, yi - 1, libs, size);
  3471.         if libs = 0 then
  3472.           begin
  3473.             killGroup(other, xi, yi - 1);
  3474.             numDead := numDead + size;
  3475.             killX := xi;
  3476.             killY := yi - 1;
  3477.           end;
  3478.       end;
  3479.   if yi < maxPoint then
  3480.     if (board[xi, yi + 1].val = other) then
  3481.       begin
  3482.         wipeMarks;
  3483.         libs := 0;
  3484.         size := 0;
  3485.         spanGroup(other, xi, yi + 1, libs, size);
  3486.         if libs = 0 then
  3487.           begin
  3488.             killGroup(other, xi, yi + 1);
  3489.             numDead := numDead + size;
  3490.             killX := xi;
  3491.             killY := yi + 1;
  3492.           end;
  3493.       end;
  3494.   if numDead > 0 then
  3495.     beep(die);
  3496. end { remDead };
  3497.  
  3498. function lastPlayAt(bx, by: integer): boolean;
  3499. var
  3500.   tm: pMRec;
  3501. begin { lastPlayAt }
  3502.   lastPlayAt := false;
  3503.   tm := curMove;
  3504.   while tm <> treeRoot do
  3505.     with tm^ do
  3506.       if id = move then
  3507.         begin
  3508.           lastPlayAt := (mx = bx) and (my = by);
  3509.           exit(lastPlayAt);
  3510.         end
  3511.       else if id = pass then
  3512.         exit(lastPlayAt)
  3513.       else if id = hcPlay then
  3514.         exit(lastPlayAt)
  3515.       else
  3516.         tm := tm^.blink;
  3517. end { lastPlayAt };
  3518.  
  3519. procedure findAtari(xi, yi: integer);
  3520. var
  3521.   i, j, libs, num, size: integer;
  3522.   s, other: bVal;
  3523. begin { findAtari }
  3524.   size := 0;
  3525.   s := board[xi, yi].val;
  3526.   if s = white then
  3527.     other := black
  3528.   else
  3529.     other := white;
  3530.   wipeMarks;
  3531.   libs := 0;
  3532.   spanGroup(s, xi, yi, libs, size);
  3533.   if libs = 1 then
  3534.     begin
  3535.       beep(atari);
  3536.       exit(findAtari);
  3537.     end;
  3538.   if xi > 0 then
  3539.     if (board[xi - 1, yi].val = other) and
  3540.        (not board[xi - 1, yi].marked) then
  3541.       begin
  3542.         wipeMarks;
  3543.         libs := 0;
  3544.         spanGroup(other, xi - 1, yi, libs, size);
  3545.         if libs = 1 then
  3546.           begin
  3547.             beep(atari);
  3548.             exit(findAtari);
  3549.           end;
  3550.       end;
  3551.   if xi < maxPoint then
  3552.     if (board[xi + 1, yi].val = other) and
  3553.        (not board[xi + 1, yi].marked) then
  3554.       begin
  3555.         wipeMarks;
  3556.         libs := 0;
  3557.         spanGroup(other, xi + 1, yi, libs, size);
  3558.         if libs = 1 then
  3559.           begin
  3560.             beep(atari);
  3561.             exit(findAtari);
  3562.           end;
  3563.       end;
  3564.   if yi > 0 then 
  3565.     if (board[xi, yi - 1].val = other) and
  3566.        (not board[xi, yi - 1].marked) then
  3567.       begin
  3568.         wipeMarks;
  3569.         libs := 0;
  3570.         spanGroup(other, xi, yi - 1, libs, size);
  3571.         if libs = 1 then
  3572.           begin
  3573.             beep(atari);
  3574.             exit(findAtari);
  3575.           end;
  3576.       end;
  3577.   if yi < maxPoint then
  3578.     if (board[xi, yi + 1].val = other) and
  3579.        (not board[xi, yi + 1].marked) then
  3580.       begin
  3581.         wipeMarks;
  3582.         libs := 0;
  3583.         spanGroup(other, xi, yi + 1, libs, size);
  3584.         if libs = 1 then
  3585.           beep(atari);
  3586.       end;
  3587. end { findAtari };
  3588.  
  3589. procedure checkAtari(cm: pMRec);
  3590. begin { checkAtari }
  3591.   if cm <> treeRoot then
  3592.     if cm^.id <> hcPlay then
  3593.       if cm^.id <> pass then
  3594.         begin
  3595.           while cm^.id = remove do
  3596.             cm := cm^.blink;
  3597.           with cm^ do
  3598.             findAtari(mx, my);
  3599.       end;
  3600. end { checkAtari };
  3601.  
  3602. procedure restoreDead;
  3603. var
  3604.   i: integer;
  3605.   other: sType;
  3606. begin { restoreDead }
  3607.   for i := 1 to numEndDead do
  3608.     with endDead[i] do
  3609.       begin
  3610.         placeStone(whoDead, dx, dy, dox, doy, mn);
  3611.         if whoDead = white then
  3612.           other := black
  3613.         else
  3614.           other := white;
  3615.         captures[other] := captures[other] - 1;
  3616.       end;
  3617.   numEndDead := 0;
  3618.   gameOver := false;
  3619. end { restoreDead };
  3620.  
  3621. procedure backUp1;
  3622. var
  3623.   moveT: mType;
  3624.   prevMove, tm: pMRec;
  3625. begin { backUp1 }
  3626.   if dotSX >= 0 then
  3627.     begin
  3628.       dotStone(dotSX, dotSY);
  3629.       dotSX := -1;
  3630.     end;
  3631.   if gameOver then
  3632.     restoreDead;
  3633.   if curMove <> treeRoot then
  3634.     repeat
  3635.       with curMove^ do
  3636.         begin
  3637.           prevMove := blink;
  3638.           moveT := id;
  3639.           if id = move then
  3640.             remStone(mx, my)
  3641.           else if id = remove then
  3642.             begin 
  3643.               placeStone(who, mx, my, ox, oy, moveN);
  3644.               if who = black then
  3645.                 captures[white] := captures[white] - 1
  3646.               else
  3647.                 captures[black] := captures[black] - 1;
  3648.             end
  3649.           else if id = pass then
  3650.             remPass
  3651.           else { hcPlay }
  3652.             clearBoard;
  3653.         end;
  3654.       curMove := prevMove;
  3655.    until (curMove = treeRoot) or (moveT = move) or (moveT = pass); 
  3656.    if curMove = treeRoot then
  3657.      begin
  3658.        koX := -1;
  3659.        koY := -1;
  3660.        moveNum := 0;
  3661.      end
  3662.    else if curMove^.id = move then
  3663.      with curMove^ do
  3664.        begin
  3665.          koX := kx;
  3666.          koY := ky;
  3667.          moveNum := moveN;
  3668.        end
  3669.    else if curMove^.id = pass then
  3670.      with curMove^ do
  3671.        begin
  3672.          koX := -1;
  3673.          koY := -1;
  3674.          moveNum := moveN;
  3675.          showPass(who);
  3676.        end
  3677.    else if curMove^.id = hcPlay then
  3678.      begin
  3679.        koX := -1;
  3680.        koY := -1;
  3681.        moveNum := 1;
  3682.      end
  3683.    else
  3684.      begin
  3685.        tm := curMove^.blink;
  3686.        while tm^.id <> move do
  3687.          tm := tm^.blink;
  3688.        with tm^ do
  3689.          begin
  3690.            koX := kx;
  3691.            koY := ky;
  3692.            moveNum := moveN;
  3693.          end;
  3694.      end;
  3695. end { backUp1 };
  3696.  
  3697. procedure doMove(which: sType; ix, iy, pox, poy: integer);
  3698. var
  3699.   numDead: integer;
  3700.   cm: pMRec;
  3701. begin { doMove }
  3702.   if dotSX >= 0 then
  3703.     begin
  3704.       dotStone(dotSX, dotSY);
  3705.       dotSX := -1;
  3706.     end;
  3707.   if gameOver then
  3708.     restoreDead;
  3709.   curMove := newMove(curMove);
  3710.   moveNum := moveNum + 1;
  3711.   with curMove^ do
  3712.     begin
  3713.       mx := ix;
  3714.       my := iy;
  3715.       ox := pox;
  3716.       oy := poy;
  3717.       kx := koX;
  3718.       ky := koY;
  3719.       who := which;
  3720.       id := move;
  3721.       moveN := moveNum;
  3722.     end;
  3723.   curMove := mergeMove(curMove);
  3724.   cm := curMove;
  3725.   placeStone(which, ix, iy, pox, poy, moveNum);
  3726.   remDead(ix, iy, numDead);
  3727.   if libertyCount(ix, iy) < 1 then
  3728.     begin
  3729.       curMove := delBranch(curMove);
  3730.       moveNum := moveNum + 1;
  3731.       remStone(ix, iy);
  3732.       beep(error);
  3733.     end
  3734.   else
  3735.     begin
  3736.       captures[which] := captures[which] + numDead;
  3737.       if (numDead = 1) and (groupSize(ix, iy) = 1) then
  3738.         begin
  3739.           koX := killX;
  3740.           koY := killY;
  3741.         end
  3742.       else
  3743.         begin
  3744.           koX := -1;
  3745.           koY := -1;
  3746.         end;  
  3747.       with cm^ do
  3748.         begin
  3749.           kx := koX;
  3750.           ky := koY;
  3751.         end;
  3752.     end;
  3753. end { doMove };
  3754.  
  3755. procedure doPass(which: sType);
  3756. begin { doPass }
  3757.   if dotSX >= 0 then
  3758.     begin
  3759.       dotStone(dotSX, dotSY);
  3760.       dotSX := -1;
  3761.     end;
  3762.   if gameOver then
  3763.     restoreDead;
  3764.   curMove := newMove(curMove);
  3765.   moveNum := moveNum + 1;
  3766.   with curMove^ do
  3767.     begin
  3768.       who := which;
  3769.       id := pass;
  3770.       moveN := moveNum;
  3771.     end;
  3772.   curMove := mergeMove(curMove);
  3773.   showPass(which);
  3774. end { doPass };
  3775.  
  3776. procedure doHCPlay(num: integer);
  3777. begin { doHCPlay }
  3778.   moveNum := 1;
  3779.   curMove := newMove(treeRoot);
  3780.   with curMove^ do
  3781.     begin
  3782.       who := black;
  3783.       id := hcPlay;
  3784.       hcNum := num;
  3785.     end;
  3786.   addHCStones(num);
  3787. end { doHCPlay };
  3788.  
  3789. procedure forwardTo(m: pMRec);
  3790. begin { forwardTo }
  3791.   if dotSX >= 0 then
  3792.     begin
  3793.       dotStone(dotSX, dotSY);
  3794.       dotSX := -1;
  3795.     end;
  3796.   curMove := m;
  3797.   if passShowing then
  3798.     remPass;
  3799.   with curMove^ do
  3800.     if id = hcPlay then
  3801.       begin
  3802.         addHCStones(hcNum);
  3803.         moveNum := 1;
  3804.       end
  3805.     else if id = pass then
  3806.       begin
  3807.         moveNum := moveN;
  3808.         koX := -1;
  3809.         koY := -1;
  3810.         showPass(who);
  3811.       end
  3812.     else
  3813.       begin
  3814.         moveNum := moveN;
  3815.         placeStone(who, mx, my, ox, oy, moveNum);
  3816.         koX := kx;
  3817.         koY := ky;
  3818.         while curMove^.flink <> nil do
  3819.           if curMove^.flink^.id = remove then
  3820.             begin
  3821.               curMove := curMove^.flink;
  3822.               with curMove^ do
  3823.                 remStone(mx, my);
  3824.               if curMove^.who = white then
  3825.                 captures[black] := captures[black] + 1
  3826.               else
  3827.                 captures[white] := captures[white] + 1
  3828.             end
  3829.           else
  3830.             exit(forwardTo);
  3831.       end;
  3832. end { forwardTo };
  3833.  
  3834. procedure forwToBr;
  3835. var
  3836.   atBr: boolean;
  3837. begin { forwToBr }
  3838.   if dotSX >= 0 then
  3839.     begin
  3840.       dotStone(dotSX, dotSY);
  3841.       dotSX := -1;
  3842.     end;
  3843.   atBr := false;
  3844.   repeat
  3845.     if curMove^.flink = nil then
  3846.       atBr := true
  3847.     else if curMove^.flink^.slink <> nil then
  3848.       atBr := true
  3849.     else
  3850.       forwardTo(curMove^.flink);
  3851.   until atBr;
  3852. end { forwToBr };
  3853.  
  3854. procedure backToBr;
  3855. var
  3856.   na: integer;
  3857.   tm: pMRec;
  3858.   endLoop: boolean;
  3859. begin { backToBr }
  3860.   if dotSX >= 0 then
  3861.     begin
  3862.       dotStone(dotSX, dotSY);
  3863.       dotSX := -1;
  3864.     end;
  3865.   if curMove <> treeRoot then
  3866.     begin
  3867.       if not hasAlts(curMove) then
  3868.         repeat
  3869.           backUp1;
  3870.           if curMove = treeRoot then
  3871.             endLoop := true
  3872.           else
  3873.             endLoop := hasAlts(curMove);
  3874.         until endLoop;
  3875.       if curMove <> treeRoot then
  3876.         backUp1;
  3877.     end
  3878.   else
  3879.     beep(error);
  3880. end { backToBr };
  3881.  
  3882. function atBranch(cm: pMRec): boolean;
  3883. begin { atBranch }
  3884.   if cm^.flink <> nil then
  3885.     atBranch := cm^.flink^.slink <> nil
  3886.   else
  3887.     atBranch := false;
  3888. end { atBranch };
  3889.  
  3890. function atLeaf(cm: pMRec): boolean;
  3891. begin { atLeaf }
  3892.   atLeaf := cm^.flink = nil;
  3893. end { atLeaf };
  3894.  
  3895. procedure showAlts;
  3896. var
  3897.   tm: pMRec;
  3898. begin { showAlts }
  3899.   setMenuCursor;
  3900.   tm := curMove^.flink;
  3901.   passIsAlt := false;
  3902.   while tm <> nil do
  3903.     begin
  3904.       with tm^ do
  3905.         begin
  3906.           if id = move then
  3907.             placeAlt(who, mx, my, ox, oy)
  3908.           else if id = pass then
  3909.             begin
  3910.               SChrFunc(ord(rNot));
  3911.               showPass(who);
  3912.               SChrFunc(ord(rRpl));
  3913.               passIsAlt := true;
  3914.             end;
  3915.           tm := tm^.slink;
  3916.         end;
  3917.     end;
  3918. end { showAlts };
  3919.  
  3920. procedure remAlts;
  3921. var
  3922.   tm: pMRec;
  3923. begin { remAlts }
  3924.   tm := curMove^.flink;
  3925.   while tm <> nil do
  3926.     begin
  3927.       with tm^ do
  3928.         begin
  3929.           if id = move then
  3930.             remStone(mx, my)
  3931.           else if id = pass then
  3932.             remPass;
  3933.           tm := tm^.slink;
  3934.         end;
  3935.     end;
  3936. end { remAlts };
  3937.  
  3938. procedure selAlt(lx, ly: integer);
  3939. begin { selAlt }
  3940.   remAlts;
  3941.   curMove := curMove^.flink;
  3942.   repeat
  3943.     while curMove^.id <> move do
  3944.       curMove := curMove^.slink;
  3945.     if (curMove^.mx = lx) and (curMove^.my = ly) then
  3946.       begin
  3947.         forwardTo(curMove);
  3948.         exit(selAlt);
  3949.       end
  3950.     else
  3951.       curMove := curMove^.slink;
  3952.   until false;
  3953. end { selAlt };
  3954.  
  3955. procedure selPass;
  3956. begin { selPass }
  3957.   remAlts;
  3958.   curMove := curMove^.flink;
  3959.   while curMove^.id <> pass do
  3960.     curMove := curMove^.slink;
  3961.   forwardTo(curMove);
  3962. end { selPass };
  3963.  
  3964. procedure switchBranch(bm: pMRec);
  3965. var
  3966.   tm: pMRec;
  3967. begin { switchBranch }
  3968.   if dotSX >= 0 then
  3969.     begin
  3970.       dotStone(dotSX, dotSY);
  3971.       dotSX := -1;
  3972.     end;
  3973.   if gameOver then
  3974.     restoreDead;
  3975.   wipeTreeMarks;
  3976.   tm := bm;
  3977.   while tm <> treeRoot do
  3978.     begin
  3979.       tm^.mark := true;
  3980.       tm := tm^.blink;
  3981.     end;
  3982.   treeRoot^.mark := true;
  3983.   while not curMove^.mark do
  3984.     backup1;
  3985.   while curMove <> bm do
  3986.     begin
  3987.       tm := curMove^.flink;
  3988.       while not tm^.mark do
  3989.         tm := tm^.slink;
  3990.       forwardTo(tm);
  3991.     end;
  3992. end { switchBranch };
  3993.  
  3994. function stepTagPossible: boolean;
  3995. begin { stepTagPossible }
  3996.   if treeRoot^.lastTag = nil then
  3997.     stepTagPossible := false
  3998.   else if stepTag = nil then
  3999.     stepTagPossible := true
  4000.   else if curMove = treeRoot then
  4001.     stepTagPossible := true
  4002.   else if curMove^.tag = stepTag then
  4003.     stepTagPossible := false
  4004.   else
  4005.     stepTagPossible := true;
  4006. end { stepTagPossible };
  4007.  
  4008. procedure doStepTag;
  4009. var
  4010.   tm: pMRec;
  4011. begin { doStepTag }
  4012.   if stepTag = nil then
  4013.     exit(doStepTag);
  4014.   if dotSX >= 0 then
  4015.     begin
  4016.       dotStone(dotSX, dotSY);
  4017.       dotSX := -1;
  4018.     end;
  4019.   if gameOver then
  4020.     restoreDead;
  4021.   tm := stepTag^.mPtr;
  4022.   if curMove = tm then
  4023.     exit(doStepTag);
  4024.   wipeTreeMarks;
  4025.   while tm <> treeRoot do
  4026.     begin
  4027.       tm^.mark := true;
  4028.       tm := tm^.blink;
  4029.     end;
  4030.   treeRoot^.mark := true;
  4031.   if not curMove^.mark then
  4032.     begin
  4033.       prompt('Backed up to proper branch');
  4034.       repeat
  4035.         backup1;
  4036.       until curMove^.mark;
  4037.     end
  4038.   else 
  4039.     begin
  4040.       tm := curMove^.flink;
  4041.       while not tm^.mark do
  4042.         tm := tm^.slink;
  4043.       forwardTo(tm);
  4044.     end;
  4045. end { doStepTag };
  4046.  
  4047. procedure scoreGame(var ws, bs: integer);
  4048. var
  4049.   i, j, size: integer;
  4050.   bSeen, wSeen: boolean;
  4051.  
  4052.   procedure spanEmpties(bx, by: integer);
  4053.   begin { spanEmpties }
  4054.     if (bx >= 0) and (bx <= maxPoint) and
  4055.        (by >= 0) and (by <= maxPoint) then
  4056.       begin
  4057.         if board[bx, by].val = white then
  4058.           wSeen := true
  4059.         else if board[bx, by].val = black then
  4060.           bSeen := true
  4061.         else if not board[bx, by].marked then
  4062.           begin
  4063.             board[bx, by].marked := true;
  4064.             size := size + 1;
  4065.             spanEmpties(bx - 1, by);
  4066.             spanEmpties(bx + 1, by);
  4067.             spanEmpties(bx, by - 1);
  4068.             spanEmpties(bx, by + 1);
  4069.           end;
  4070.       end;
  4071.   end { spanEmpties };
  4072.  
  4073. begin { scoreGame }
  4074.   ws := 0;
  4075.   bs := 0;
  4076.   wipeMarks;
  4077.   for j := 0 to maxPoint do
  4078.     for i := 0 to maxPoint do
  4079.       if (not board[i, j].marked) and
  4080.          (board[i, j].val = empty) then
  4081.         begin
  4082.           bSeen := false;
  4083.           wSeen := false;
  4084.           size := 0;
  4085.           spanEmpties(i, j);
  4086.           if bSeen and not wSeen then
  4087.             bs := bs + size
  4088.           else if wSeen and not bSeen then
  4089.             ws := ws + size;
  4090.         end;
  4091. end { scoreGame };
  4092.  
  4093. procedure putEnd;
  4094. begin { putEnd }
  4095.   if not gameOver then
  4096.     begin
  4097.       gameOver := true;
  4098.       numEndDead := 0;
  4099.     end;
  4100. end { putEnd };
  4101.  
  4102. procedure delGroup(bx, by: integer);
  4103. var
  4104.   sto, other: sType;
  4105.   size: integer;
  4106.  
  4107.   procedure dumpDead(bx, by: integer);
  4108.   begin { dumpDead }
  4109.     if (bx >= 0) and (bx <= maxPoint) and
  4110.        (by >= 0) and (by <= maxPoint) then
  4111.       if board[bx, by].val = sto then
  4112.         begin
  4113.           remStone(bx, by);
  4114.           numEndDead := numEndDead + 1;
  4115.           with endDead[numEndDead] do
  4116.             begin
  4117.               dx := bx;
  4118.               dy := by;
  4119.               with board[bx, by] do
  4120.                 begin
  4121.                   dox := xOfs;
  4122.                   doy := yOfs;
  4123.                   mn := mNum;
  4124.                 end;
  4125.               whoDead := sto;
  4126.             end;
  4127.           size := size + 1;
  4128.           dumpDead(bx - 1, by);
  4129.           dumpDead(bx + 1, by);
  4130.           dumpDead(bx, by - 1);
  4131.           dumpDead(bx, by + 1);
  4132.         end;
  4133.   end { dumpDead };
  4134.  
  4135. begin { delGroup }
  4136.   sto := board[bx, by].val;
  4137.   size := 0;
  4138.   dumpDead(bx, by);
  4139.   if sto = white then
  4140.     other := black
  4141.   else
  4142.     other := white;
  4143.   captures[other] := captures[other] + size;
  4144. end { delGroup };
  4145.  
  4146. procedure dotLast;
  4147. var
  4148.   tm: pMRec;
  4149. begin { dotLast }
  4150.   if numbEnabled then
  4151.     exit(dotLast);
  4152.   if dotSX >= 0 then
  4153.     dotStone(dotSX, dotSY);
  4154.   dotSX := -1;
  4155.   tm := curMove;
  4156.   while tm <> treeRoot do
  4157.     if tm^.id = pass then
  4158.       exit(dotLast)
  4159.     else if tm^.id = move then
  4160.       with tm^ do
  4161.         begin
  4162.           dotSX := mx;
  4163.           dotSY := my;
  4164.           dotStone(mx, my);
  4165.           exit(dotLast);
  4166.         end
  4167.     else
  4168.       tm := tm^.blink;
  4169. end { dotLast };
  4170.  
  4171. procedure initGoMgr;
  4172. begin { initGoMgr }
  4173.   moveNum := 0;
  4174.   curMove := treeRoot;
  4175.   gameOver := false;
  4176.   numEndDead := 0;
  4177.   dotSX := -1;
  4178.   dotSY := -1;
  4179.   passShowing := false;
  4180. end. { initGoMgr }
  4181. SHAR_EOF
  4182. fi
  4183. if test -f 'goPlayUtils.pas'
  4184. then
  4185.     echo shar: "will not over-write existing file 'goPlayUtils.pas'"
  4186. else
  4187. cat << \SHAR_EOF > 'goPlayUtils.pas'
  4188. module goPlayUtils;
  4189.  
  4190. exports
  4191.  
  4192. imports goCom from goCom;
  4193.  
  4194. const
  4195.   iNil = 32767; { a distinguished value like nil }
  4196.   maxGroup = 512;
  4197.   maxSPoint = 16;
  4198.  
  4199. type
  4200.   intBoard = array[-2..maxPoint + 2] of array[-2..maxPoint + 2] of integer;
  4201.  
  4202.   boolBoard = array[-2..maxPoint + 2] of array[-2..maxPoint + 2] of boolean;
  4203.  
  4204.   point = record
  4205.             px, py: integer;
  4206.           end;
  4207.  
  4208.   pointList = record
  4209.                 p: array[1..400] of point;
  4210.                 indx: integer;
  4211.               end;
  4212.  
  4213.   sPointList = record
  4214.                  p: array[1..maxSPoint] of point;
  4215.                  indx: integer;
  4216.                end;
  4217.  
  4218.   intList = record
  4219.               indx: integer;
  4220.               v: array[1..400] of integer;
  4221.             end;
  4222.  
  4223.   sgRec = record
  4224.             w, s, sm: integer;
  4225.           end;
  4226.  
  4227.   groupRec = record
  4228.                groupMark: integer;
  4229.                atLevel: integer;
  4230.                isLive: boolean;
  4231.                isDead: boolean;
  4232.                libC: integer;
  4233.                numEyes: integer;
  4234.                size: integer;
  4235.                lx, ly: integer;
  4236.              end;
  4237.  
  4238. var
  4239.   kleim, ekstre, bord, ndbord, sGroups, threatBord: intBoard;
  4240.   groupIDs, connectMap, protPoints: intBoard;
  4241.   groupSeen, legal: boolBoard;
  4242.   maxGroupID: integer;
  4243.   pList, pList1, plist2, plist3, pPlist: pointList;
  4244.   nlcGroup, aList: intList;
  4245.   sList: array[1..400] of sgRec;
  4246.   gList: array[0..maxGroup] of groupRec;
  4247.   killFlag: boolean;
  4248.   numCapt: integer;
  4249.   utilPlayLevel: integer;
  4250.   treeLibLim: integer;
  4251.   mySType: sType;
  4252.   showTrees: boolean;
  4253.   sGlist: array[1..maxGroup] of integer;
  4254.   depthLimit: integer;
  4255.   markBoard: intBoard;
  4256.   marker: integer;
  4257.  
  4258. function saveable(gx, gy: integer; var savex, savey: integer): boolean;
  4259. function killable(gx, gy: integer; var killx, killy: integer): boolean;
  4260. procedure initBoolBoard(var bb: boolBoard);
  4261. procedure spanGroup(x, y: integer; var libs: pointList);
  4262. function abs(i: integer): integer;
  4263. procedure intersectPlist(var p1, p2, pr: pointList);
  4264. procedure initArray(var ary: intBoard);
  4265. procedure initState;
  4266. procedure copyArray(var dAry, sAry: intBoard);
  4267. procedure steik;
  4268. procedure spread;
  4269. procedure respreicen;
  4270. procedure plei(x, y, z: integer);
  4271. procedure genState;
  4272. procedure saveState;
  4273. procedure restoreState;
  4274. function tencen(x, y: integer): integer;
  4275. procedure genConnects;
  4276. procedure initGPUtils;
  4277. procedure sortLibs;
  4278.  
  4279. private
  4280.  
  4281. imports screen from screen;
  4282. imports raster from raster;
  4283. imports goBoard from goBoard;
  4284. imports io_others from io_others;
  4285.  
  4286. type
  4287.   playType = (rem, add, chLib, reMap);
  4288.  
  4289.   playRec = record
  4290.               gID: integer;
  4291.               case kind: playType of
  4292.                 rem, add:
  4293.                   (who, xl, yl, nextGID, sNumber: integer);
  4294.                 chLib:
  4295.                   (oldLC, oldLevel: integer);
  4296.                 reMap:
  4297.                   (oldGID: integer)
  4298.             end;
  4299.  
  4300. var
  4301.   adjInAtari, adj2Libs: boolean;
  4302.   intersectNum, spanNum, libMark: integer;
  4303.   playStack: array[1..1024] of playRec;
  4304.   playMark: integer;
  4305.   newGID: integer;
  4306.   tryLevel: integer;
  4307.   grpMark: integer;
  4308.   gMap: array[0..maxGroup] of integer;
  4309.   dbStop, inGenState: boolean;
  4310.  
  4311. exception screwup;
  4312.  
  4313. procedure pause;
  4314. begin { pause }
  4315. {  if dbStop and not inGenState then
  4316.     begin
  4317.       while not tabswitch do;
  4318.       repeat
  4319.         if tabYellow then
  4320.           dbStop := false;
  4321.       until not tabswitch;
  4322.     end;     }
  4323. end { pause };
  4324.  
  4325. procedure sstone(w, x, y, numb: integer);
  4326. var
  4327.   cx, cy: integer;
  4328. begin { sstone }
  4329.   sReadCursor(cx, cy);
  4330.   if w = 1 then
  4331.     placeStone(mySType, x, y, 0, 0, numb)
  4332.   else if mySType = white then
  4333.     placeStone(black, x, y, 0, 0, numb)
  4334.   else
  4335.     placeStone(white, x, y, 0, 0, numb);
  4336.   sSetCursor(cx, cy);
  4337. end { sstone };
  4338.  
  4339. procedure rstone(x, y: integer);
  4340. var
  4341.   cx, cy: integer;
  4342. begin { rstone }
  4343.   sReadCursor(cx, cy);
  4344.   remStone(x, y);
  4345.   sSetCursor(cx, cy);
  4346. end { rstone };
  4347.  
  4348. procedure initBoolBoard(var bb: boolBoard);
  4349. var
  4350.   i, j: integer;
  4351. begin { initBoolBoard }
  4352.   for i := 0 to maxPoint do
  4353.     for j := 0 to maxPoint do
  4354.       bb[i, j] := false;
  4355. end { initBoolBoard };
  4356.  
  4357. function abs(i: integer): integer;
  4358. begin { abs }
  4359.   if i < 0 then
  4360.     abs := -i
  4361.   else
  4362.     abs := i;  
  4363. end { abs };
  4364.  
  4365. procedure sortLibs;
  4366. var
  4367.   i, j, t: integer;
  4368. begin { sortLibs }
  4369.   for i := 1 to maxGroupID do
  4370.     sGList[i] := i;
  4371.   for i := 1 to maxGroupID - 1 do
  4372.     for j := i + 1 to maxGroupID do
  4373.       if gList[sGlist[i]].libC > gList[sGlist[j]].libC then
  4374.         begin
  4375.           t := sGList[i];
  4376.           sGlist[i] := sGlist[j];
  4377.           sGlist[j] := t;
  4378.         end;
  4379. end { sortLibs };
  4380.  
  4381. procedure spanGroup(x, y: integer; var libs: pointList);
  4382. var
  4383.   lookFor: integer;
  4384.  
  4385.   procedure span(x, y: integer);
  4386.   begin { span }
  4387.     markBoard[x, y] := marker;
  4388.     if bord[x, y] = 0 then
  4389.       begin
  4390.         libs.indx := libs.indx + 1;
  4391.         libs.p[libs.indx].px := x;
  4392.         libs.p[libs.indx].py := y;
  4393.       end
  4394.     else if bord[x, y] = lookFor then
  4395.       begin
  4396.         groupSeen[x, y] := true;
  4397.         if (x > 0) and (markBoard[x - 1, y] <> marker) then
  4398.           span(x - 1, y);
  4399.         if (y > 0) and (markBoard[x, y - 1] <> marker) then
  4400.           span(x, y - 1);
  4401.         if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
  4402.           span(x + 1, y);
  4403.         if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
  4404.           span(x, y + 1);
  4405.       end
  4406.     else if gList[gMap[groupIDs[x, y]]].libC = 1 then 
  4407.       adjInAtari := true 
  4408.     else if (gList[gMap[groupIDs[x, y]]].libC = 2) and
  4409.             (not gList[gMap[groupIDs[x, y]]].isLive) then 
  4410.       adj2Libs := true; 
  4411.   end { span };
  4412.  
  4413. begin { spanGroup }
  4414.   marker := marker + 1;
  4415.   if marker = 0 then
  4416.     begin
  4417.       initArray(markBoard);
  4418.       marker := 1;
  4419.     end;
  4420.   adjInAtari := false;
  4421.   adj2Libs := false;
  4422.   lookFor := bord[x, y];
  4423.   libs.indx := 0;
  4424.   span(x, y);
  4425. end { spanGroup };
  4426.  
  4427. procedure sSpanGroup(x, y: integer; var libs: sPointList);
  4428. var
  4429.   lookFor: integer;
  4430.  
  4431.   procedure span(x, y: integer);
  4432.   begin { span }
  4433.     markBoard[x, y] := marker;
  4434.     if bord[x, y] = 0 then
  4435.       begin
  4436.         libs.indx := libs.indx + 1;
  4437.         if libs.indx <= maxSPoint then
  4438.           begin
  4439.             libs.p[libs.indx].px := x;
  4440.             libs.p[libs.indx].py := y;
  4441.           end;
  4442.       end
  4443.     else if bord[x, y] = lookFor then
  4444.       begin
  4445.         groupSeen[x, y] := true;
  4446.         if (x > 0) and (markBoard[x - 1, y] <> marker) then
  4447.           span(x - 1, y);
  4448.         if (y > 0) and (markBoard[x, y - 1] <> marker) then
  4449.           span(x, y - 1);
  4450.         if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
  4451.           span(x + 1, y);
  4452.         if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
  4453.           span(x, y + 1);
  4454.       end
  4455.     else if gList[gMap[groupIDs[x, y]]].libC = 1 then 
  4456.       adjInAtari := true 
  4457.     else if (gList[gMap[groupIDs[x, y]]].libC = 2) and
  4458.             (not gList[gMap[groupIDs[x, y]]].isLive) then 
  4459.       adj2Libs := true; 
  4460.   end { span };
  4461.  
  4462. begin { sSpanGroup }
  4463.   marker := marker + 1;
  4464.   if marker = 0 then
  4465.     begin
  4466.       initArray(markBoard);
  4467.       marker := 1;
  4468.     end;
  4469.   adjInAtari := false;
  4470.   adj2Libs := false;
  4471.   lookFor := bord[x, y];
  4472.   libs.indx := 0;
  4473.   span(x, y);
  4474. end { sSpanGroup };
  4475.  
  4476. procedure listAdjacents(x, y: integer; var iL: intList);
  4477. var
  4478.   me, him: integer;
  4479.  
  4480.   procedure span(x, y: integer);
  4481.   begin { span }
  4482.     markBoard[x, y] := marker;
  4483.     if bord[x, y] = me then
  4484.       begin
  4485.         if (x > 0) and (markBoard[x - 1, y] <> marker) then
  4486.           span(x - 1, y);
  4487.         if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
  4488.           span(x + 1, y);
  4489.         if (y > 0) and (markBoard[x, y - 1] <> marker) then
  4490.           span(x, y - 1);
  4491.         if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
  4492.           span(x, y + 1);
  4493.       end
  4494.     else if bord[x, y] = him then
  4495.       if gList[gMap[groupIDs[x, y]]].groupMark <> grpMark then
  4496.         begin
  4497.           gList[gMap[groupIDs[x, y]]].groupMark := grpMark;
  4498.           iL.indx := iL.indx + 1;
  4499.           iL.v[iL.indx] := gMap[groupIDs[x, y]];
  4500.         end;
  4501.   end { span };
  4502.  
  4503. begin { listAdjacents }
  4504.   grpMark := grpMark + 1;
  4505.   marker := marker + 1;
  4506.   if marker = 0 then
  4507.     begin
  4508.       initArray(markBoard);
  4509.       marker := 1;
  4510.     end;
  4511.   iL.indx := 0;
  4512.   me := bord[x, y];
  4513.   him := -me;
  4514.   span(x, y);
  4515. end { listAdjacents };
  4516.  
  4517. procedure listDiags(x, y: integer; var diags: sPointList);
  4518. var
  4519.   me: integer;
  4520.  
  4521.   procedure span(x, y: integer);
  4522.   begin { span }
  4523.     markBoard[x, y] := marker;
  4524.     if (x > 0) and (y > 0) and
  4525.        (bord[x - 1, y - 1] = 0) and
  4526.        (bord[x, y - 1] <> me) and
  4527.        (bord[x - 1, y] <> me) and
  4528.        (markBoard[x - 1, y - 1] <> marker) then
  4529.       begin
  4530.         markBoard[x - 1, y - 1] := marker;
  4531.         diags.indx := diags.indx + 1;
  4532.         if diags.indx <= maxSPoint then
  4533.           with diags.p[diags.indx] do
  4534.             begin
  4535.               px := x - 1;
  4536.               py := y - 1;
  4537.             end;
  4538.       end;
  4539.     if (x < maxPoint) and (y > 0) and
  4540.        (bord[x + 1, y - 1] = 0) and
  4541.        (bord[x, y - 1] <> me) and
  4542.        (bord[x + 1, y] <> me) and
  4543.        (markBoard[x + 1, y - 1] <> marker) then
  4544.       begin
  4545.         markBoard[x + 1, y - 1] := marker;
  4546.         diags.indx := diags.indx + 1;
  4547.         if diags.indx <= maxSPoint then
  4548.           with diags.p[diags.indx] do
  4549.             begin
  4550.               px := x + 1;
  4551.               py := y - 1;
  4552.             end;
  4553.       end;
  4554.     if (x > 0) and (y < maxPoint) and
  4555.        (bord[x - 1, y + 1] = 0) and
  4556.        (bord[x, y + 1] <> me) and
  4557.        (bord[x - 1, y] <> me) and
  4558.        (markBoard[x - 1, y + 1] <> marker) then
  4559.       begin
  4560.         markBoard[x - 1, y + 1] := marker;
  4561.         diags.indx := diags.indx + 1;
  4562.         if diags.indx <= maxSPoint then
  4563.           with diags.p[diags.indx] do
  4564.             begin
  4565.               px := x - 1;
  4566.               py := y + 1;
  4567.             end;
  4568.       end;
  4569.     if (x < maxPoint) and (y < maxPoint) and
  4570.        (bord[x + 1, y + 1] = 0) and
  4571.        (bord[x, y + 1] <> me) and
  4572.        (bord[x + 1, y] <> me) and
  4573.        (markBoard[x + 1, y + 1] <> marker) then
  4574.       begin
  4575.         markBoard[x + 1, y + 1] := marker;
  4576.         diags.indx := diags.indx + 1;
  4577.         if diags.indx <= maxSPoint then
  4578.           with diags.p[diags.indx] do
  4579.             begin
  4580.               px := x + 1;
  4581.               py := y + 1;
  4582.             end;
  4583.       end;
  4584.     if (x > 0) and (bord[x - 1, y] = me) and
  4585.        (markBoard[x - 1, y] <> marker) then
  4586.       span(x - 1, y);
  4587.     if (x < maxPoint) and (bord[x + 1, y] = me) and
  4588.        (markBoard[x + 1, y] <> marker) then
  4589.       span(x + 1, y);
  4590.     if (y > 0) and (bord[x, y - 1] = me) and
  4591.        (markBoard[x, y - 1] <> marker) then
  4592.       span(x, y - 1);
  4593.     if (y < maxPoint) and (bord[x, y + 1] = me) and
  4594.        (markBoard[x, y + 1] <> marker) then
  4595.       span(x, y + 1);
  4596.   end { span };
  4597.  
  4598. begin { listDiags }
  4599.   me := bord[x, y];
  4600.   diags.indx := 0;
  4601.   marker := marker + 1;
  4602.   if marker = 0 then
  4603.     begin
  4604.       initArray(markBoard);
  4605.       marker := 1;
  4606.     end;
  4607.   span(x, y);
  4608. end { listDiags };
  4609.  
  4610. procedure intersectPlist(var p1, p2, pr: pointList);
  4611. var
  4612.   i, j, k: integer;
  4613. begin { intersectPlist }
  4614.   marker := marker + 1;
  4615.   if marker = 0 then
  4616.     begin
  4617.       initArray(markBoard);
  4618.       marker := 1;
  4619.     end;
  4620.   pr.indx := 0;
  4621.   for i := 1 to p1.indx do
  4622.     with p1.p[i] do
  4623.       markBoard[px, py] := marker;
  4624.   j := 0;
  4625.   for i := 1 to p2.indx do
  4626.     with p2.p[i] do
  4627.       if markBoard[px, py] = marker then
  4628.         begin
  4629.           j := j + 1;
  4630.           pr.p[j] := p2.p[i];
  4631.         end;
  4632.   pr.indx := j;
  4633. end { intersectPlist };
  4634.  
  4635. procedure initArray(var ary: intBoard);
  4636. var
  4637.   i, j: integer;
  4638. begin { initArray }
  4639.   for i := 0 to maxPoint do
  4640.     for j := 0 to maxPoint do
  4641.       ary[i, j] := 0;
  4642. end { initArray };
  4643.  
  4644. procedure initState;
  4645. var
  4646.   i, j: integer;
  4647. begin { initState }
  4648.   for i := -2 to maxPoint + 2 do
  4649.     for j := -2 to maxPoint + 2 do
  4650.       begin
  4651.         ekstre[i, j] := 0;
  4652.         kleim[i, j] := 0;
  4653.         groupIDs[i, j] := 0;
  4654.         connectMap[i, j] := 0;
  4655.         protPoints[i, j] := 0;
  4656.       end;
  4657. end { initState };
  4658.  
  4659. procedure copyArray(var dAry, sAry: intBoard);
  4660. var
  4661.   i, j: integer;
  4662. begin { copyArray }
  4663.   for i := 0 to maxPoint do
  4664.     for j := 0 to maxPoint do
  4665.       dAry[i, j] := sAry[i, j];
  4666. end { copyArray };
  4667.  
  4668. {
  4669.   generates a one-point spread in the force field array (kleim)
  4670.  
  4671.   the spread from a single point after four calls is:
  4672.  
  4673.               1
  4674.            2  2  2
  4675.         2  4  6  4  2
  4676.      2  4  8 10  8  4  2
  4677.   1  2  6 10 62 10  6  2  1  
  4678.      2  4  8 10  8  4  2
  4679.         2  4  6  4  2
  4680.            2  2  2
  4681.               1
  4682.  
  4683. }
  4684. procedure steik;
  4685. var
  4686.   i, j: integer;
  4687. begin { steik }
  4688.   initArray(ekstre);
  4689.   for i := 0 to maxPoint do
  4690.     for j := 0 to maxPoint do
  4691.       begin
  4692.         ekstre[i, j] := ekstre[i, j] + kleim[i, j];
  4693.         if kleim[i, j] > 0 then
  4694.           begin
  4695.             if i > 0 then
  4696.               ekstre[i - 1, j] := ekstre[i - 1, j] + 1;
  4697.             if j > 0 then
  4698.               ekstre[i, j - 1] := ekstre[i, j - 1] + 1;
  4699.             if i < maxPoint then
  4700.               ekstre[i + 1, j] := ekstre[i + 1, j] + 1;
  4701.             if j < maxPoint then
  4702.               ekstre[i, j + 1] := ekstre[i, j + 1] + 1;
  4703.           end
  4704.         else if kleim[i, j] < 0 then
  4705.           begin
  4706.             if i > 0 then
  4707.               ekstre[i - 1, j] := ekstre[i - 1, j] - 1;
  4708.             if j > 0 then
  4709.               ekstre[i, j - 1] := ekstre[i, j - 1] - 1;
  4710.             if i < maxPoint then
  4711.               ekstre[i + 1, j] := ekstre[i + 1, j] - 1;
  4712.             if j < maxPoint then
  4713.               ekstre[i, j + 1] := ekstre[i, j + 1] - 1;
  4714.           end;
  4715.       end;
  4716.   copyArray(kleim, ekstre);
  4717. end { steik };
  4718.  
  4719. {
  4720.   sets up kleim from the current board position
  4721. }
  4722. procedure spread;
  4723. var
  4724.   i, j: integer;
  4725. begin { spread }
  4726.   for i := 0 to maxPoint do
  4727.     for j := 0 to maxPoint do
  4728.       kleim[i, j] := ndbord[i, j] * 50;
  4729.   steik;
  4730.   steik;
  4731.   steik;
  4732.   steik;
  4733. end { spread };
  4734.  
  4735. {
  4736.   gList is initialized with the size, loc, and libCount of each group
  4737.   groupIDs contains the serial numbers of the groups.
  4738. }
  4739. procedure respreicen;
  4740. var
  4741.   i, j, gID, libCount, gSize, who: integer;
  4742.  
  4743.   procedure span(x, y: integer);
  4744.   begin { span }
  4745.     if (bord[x, y] = 0) and
  4746.        (markBoard[x, y] <> marker) then { a liberty }
  4747.       begin
  4748.         markBoard[x, y] := marker;
  4749.         libCount := libCount + 1;
  4750.       end 
  4751.     else if (bord[x, y] = who) and
  4752.             (groupIDs[x, y] = 0) then
  4753.       begin
  4754.         groupIDs[x, y] := gID;
  4755.         gSize := gSize + 1;
  4756.         if x > 0 then
  4757.           span(x - 1, y);
  4758.         if x < maxPoint then
  4759.           span(x + 1, y);
  4760.         if y > 0 then
  4761.           span(x, y - 1);
  4762.         if y < maxPoint then
  4763.           span(x, y + 1);
  4764.       end;
  4765.   end { span };
  4766.  
  4767. begin { respreicen }
  4768.   gID := 0;
  4769.   for i := 0 to maxPoint do
  4770.     for j := 0 to maxPoint do
  4771.       groupIDs[i, j] := 0;
  4772.   for i := 0 to maxPoint do
  4773.     for j := 0 to maxPoint do
  4774.       if (bord[i, j] <> 0) and   { a stone there }
  4775.          (groupIDs[i, j] = 0) then { not seen yet }
  4776.         begin
  4777.           marker := marker + 1;
  4778.           if marker = 0 then
  4779.             begin
  4780.               initArray(markBoard);
  4781.               marker := 1;
  4782.             end;
  4783.           gID := gID + 1;
  4784.           libCount := 0;
  4785.           gSize := 0;
  4786.           who := bord[i, j];
  4787.           span(i, j); { span the group, collecting info }
  4788.           with gList[gID] do
  4789.             begin
  4790.               groupMark := 0;
  4791.               atLevel := 0;
  4792.               isLive := false; { we don't know yet }
  4793.               isDead := false;
  4794.               numEyes := -1;
  4795.               size := gSize;
  4796.               libC := libCount;
  4797.               lx := i;
  4798.               ly := j;
  4799.             end;
  4800.           gMap[gID] := gID; { set up identity map }
  4801.         end;
  4802.   maxGroupID := gID;
  4803.   newGID := gID;
  4804.   grpMark := 0;
  4805. end { respreicen };
  4806.  
  4807. {
  4808.   play z at [x, y].
  4809.   killFlag is set true if anything is killed.
  4810. }
  4811. procedure plei(x, y, z: integer);
  4812. var
  4813.   i, me, him, myGID: integer;
  4814.   isNew: boolean;
  4815.  
  4816.   procedure killGroup(x, y: integer);
  4817.   begin { killGroup }
  4818.     playMark := playMark + 1;
  4819.     with playStack[playMark] do
  4820.       begin                        { record this kill }
  4821.         kind := rem;
  4822.         who := him;
  4823.         xl := x;
  4824.         yl := y;
  4825.         gID := groupIDs[x, y];
  4826.         sNumber := board[x, y].mNum;
  4827.         if showTrees then
  4828.           rstone(x, y);
  4829.       end;
  4830.     numCapt := numCapt + 1;
  4831.     bord[x, y] := 0;
  4832.     groupIDs[x, y] := 0;
  4833.     if x > 0 then
  4834.       begin
  4835.         if bord[x - 1, y] = me then
  4836.           begin
  4837.             nlcGroup.indx := nlcGroup.indx + 1;
  4838.             nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x - 1, y]];
  4839.           end
  4840.         else if bord[x - 1, y] = him then
  4841.           killGroup(x - 1, y);
  4842.       end;
  4843.     if x < maxPoint then
  4844.       begin
  4845.         if bord[x + 1, y] = me then
  4846.           begin
  4847.             nlcGroup.indx := nlcGroup.indx + 1;
  4848.             nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x + 1, y]];
  4849.           end
  4850.         else if bord[x + 1, y] = him then
  4851.           killGroup(x + 1, y);
  4852.       end;
  4853.     if y > 0 then
  4854.       begin
  4855.         if bord[x, y - 1] = me then
  4856.           begin
  4857.             nlcGroup.indx := nlcGroup.indx + 1;
  4858.             nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y - 1]];
  4859.           end
  4860.         else if bord[x, y - 1] = him then
  4861.           killGroup(x, y - 1);
  4862.       end;
  4863.     if y < maxPoint then
  4864.       begin
  4865.         if bord[x, y + 1] = me then
  4866.           begin
  4867.             nlcGroup.indx := nlcGroup.indx + 1;
  4868.             nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y + 1]];
  4869.           end
  4870.         else if bord[x, y + 1] = him then
  4871.           killGroup(x, y + 1);
  4872.       end;
  4873.   end { killGroup };
  4874.  
  4875.   procedure mergeGroup(sGID: integer);
  4876.   var
  4877.     i: integer;
  4878.   begin { mergeGroup }
  4879.     for i := 1 to newGID do
  4880.       if gMap[i] = sGID then
  4881.         begin
  4882.           playMark := playMark + 1;
  4883.           with playStack[playMark] do
  4884.             begin
  4885.               kind := reMap;
  4886.               gID := i;
  4887.               oldGID := sGID;
  4888.             end;
  4889.           gMap[i] := myGID;
  4890.         end;
  4891.   end { mergeGroup };
  4892.  
  4893. begin { plei }
  4894.   me := z;
  4895.   him := -me;
  4896.   killFlag := false;  { set true if something is killed }
  4897.   numCapt := 0;
  4898.   tryLevel := tryLevel + 1;
  4899.   isNew := false;
  4900.   bord[x, y] := z;  { play the stone }
  4901.   if (x > 0) and (bord[x - 1, y] = me) then   { connect to adjacent group }
  4902.     myGID := gMap[groupIDs[x - 1, y]]
  4903.   else if (x < maxPoint) and (bord[x + 1, y] = me) then
  4904.     myGID := gMap[groupIDs[x + 1, y]]
  4905.   else if (y > 0) and (bord[x, y - 1] = me) then
  4906.     myGID := gMap[groupIDs[x, y - 1]]
  4907.   else if (y < maxPoint) and (bord[x, y + 1] = me) then
  4908.     myGID := gMap[groupIDs[x, y + 1]]
  4909.   else  { nobody to connect to }
  4910.     begin
  4911.       newGID := newGID + 1;
  4912.       isNew := true;
  4913.       myGID := newGID;
  4914.       with gList[myGID] do
  4915.         begin
  4916.           groupMark := 0;
  4917.           atLevel := tryLevel;
  4918.           isLive := false;
  4919.           numEyes := -1;
  4920.           size := -1;
  4921.           lx := x;
  4922.           ly := y;
  4923.         end;
  4924.       gMap[myGID] := myGID;
  4925.     end;
  4926.   groupIDs[x, y] := myGID;
  4927.   playMark := playMark + 1;
  4928.   with playStack[playMark] do
  4929.     begin                        { record this move }
  4930.       kind := add;
  4931.       who := me;
  4932.       xl := x;
  4933.       yl := y;
  4934.       gID := myGID;
  4935.       sNumber := 0;
  4936.       if isNew then
  4937.         nextGID := newGID - 1
  4938.       else
  4939.         nextGID := newGID;
  4940.       if showTrees then
  4941.         sstone(me, x, y, 0);
  4942.     end;
  4943.   { merge adjacent groups }
  4944.   if (x > 0) and (bord[x - 1, y] = me) and
  4945.      (gMap[groupIDs[x - 1, y]] <> myGID) then
  4946.     mergeGroup(gMap[groupIDs[x - 1, y]]);
  4947.   if (x < maxPoint) and (bord[x + 1, y] = me) and
  4948.      (gMap[groupIDs[x + 1, y]] <> myGID) then
  4949.     mergeGroup(gMap[groupIDs[x + 1, y]]);
  4950.   if (y > 0) and (bord[x, y - 1] = me) and
  4951.      (gMap[groupIDs[x, y - 1]] <> myGID) then
  4952.     mergeGroup(gMap[groupIDs[x, y - 1]]);
  4953.   if (y < maxPoint) and (bord[x, y + 1] = me) and
  4954.      (gMap[groupIDs[x, y + 1]] <> myGID) then
  4955.     mergeGroup(gMap[groupIDs[x, y + 1]]);
  4956.   { kill opposing groups, listing affected groups }
  4957.   nlcGroup.indx := 1;
  4958.   nlcGroup.v[1] := myGID; { init list to include me }
  4959.   if (x > 0) and (bord[x - 1, y] = him) and
  4960.      (gList[gMap[groupIDs[x - 1, y]]].libC = 1) then
  4961.     begin
  4962.       killFlag := true;
  4963.       killGroup(x - 1, y);
  4964.     end;
  4965.   if (x < maxPoint) and (bord[x + 1, y] = him) and
  4966.      (gList[gMap[groupIDs[x + 1, y]]].libC = 1) then
  4967.     begin
  4968.       killFlag := true;
  4969.       killGroup(x + 1, y);
  4970.     end;
  4971.   if (y > 0) and (bord[x, y - 1] = him) and
  4972.      (gList[gMap[groupIDs[x, y - 1]]].libC = 1) then
  4973.     begin
  4974.       killFlag := true;
  4975.       killGroup(x, y - 1);
  4976.     end;
  4977.   if (y < maxPoint) and (bord[x, y + 1] = him) and
  4978.      (gList[gMap[groupIDs[x, y + 1]]].libC = 1) then
  4979.     begin
  4980.       killFlag := true;
  4981.       killGroup(x, y + 1);
  4982.     end;
  4983.   { list groups adjacent to me }
  4984.   if (x > 0) and (bord[x - 1, y] = him) then
  4985.     begin
  4986.       nlcGroup.indx := nlcGroup.indx + 1;
  4987.       nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x - 1, y]];
  4988.     end;
  4989.   if (x < maxPoint) and (bord[x + 1, y] = him) then
  4990.     begin
  4991.       nlcGroup.indx := nlcGroup.indx + 1;
  4992.       nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x + 1, y]];
  4993.     end;
  4994.   if (y > 0) and (bord[x, y - 1] = him) then
  4995.     begin
  4996.       nlcGroup.indx := nlcGroup.indx + 1;
  4997.       nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y - 1]];
  4998.     end;
  4999.   if (y < maxPoint) and (bord[x, y + 1] = him) then
  5000.     begin
  5001.       nlcGroup.indx := nlcGroup.indx + 1;
  5002.       nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y + 1]];
  5003.     end;
  5004.   { fix liberty count for affected groups }
  5005.   grpMark := grpMark + 1;
  5006.   for i := 1 to nlcGroup.indx do
  5007.     with gList[nlcGroup.v[i]] do
  5008.       if groupMark <> grpMark then
  5009.         begin
  5010.           if atLevel <> tryLevel then
  5011.             begin
  5012.               playMark := playMark + 1;
  5013.               with playStack[playMark] do
  5014.                 begin
  5015.                   kind := chLib;
  5016.                   gID := nlcGroup.v[i];
  5017.                   oldLevel := atLevel;
  5018.                   oldLC := libC;
  5019.                 end;
  5020.             end;
  5021.           groupMark := grpMark;
  5022.           atLevel := tryLevel;
  5023.           spanGroup(lx, ly, pPList);
  5024.           libC := pPList.indx;
  5025.         end;
  5026. end { plei };
  5027.  
  5028. procedure saveState;
  5029. begin { saveState };
  5030.   playMark := 0;
  5031.   tryLevel := 0;
  5032.   newGID := maxGroupID;
  5033. end { saveState };
  5034.  
  5035. {
  5036.   undoes a move sequence back to uMark
  5037. }
  5038. procedure undoTo(uMark: integer);
  5039. var
  5040.   i: integer;
  5041. begin { undoTo }
  5042.   for i := playMark downto uMark + 1 do
  5043.     with playStack[i] do
  5044.       if kind = rem then
  5045.         begin
  5046.           bord[xl, yl] := who;
  5047.           groupIDs[xl, yl] := gID;
  5048.           if showTrees then
  5049.             sstone(who, xl, yl, sNumber);
  5050.         end
  5051.       else if kind = add then
  5052.         begin
  5053.           bord[xl, yl] := 0;
  5054.           groupIDs[xl, yl] := 0;
  5055.           tryLevel := tryLevel - 1;
  5056.           newGID := nextGID;
  5057.           if showTrees then
  5058.             rstone(xl, yl);
  5059.         end
  5060.       else if kind = reMap then
  5061.         gMap[gID] := oldGID
  5062.       else { change libs of group - gID is pre-mapped }
  5063.         with gList[gID] do
  5064.           begin
  5065.             libC := oldLC;
  5066.             atLevel := oldLevel;
  5067.           end;
  5068.   playMark := uMark;
  5069. end { undoTo };
  5070.  
  5071. {
  5072.   restores the state of the world after trying a move sequence
  5073. }
  5074. procedure restoreState;
  5075. var
  5076.   i: integer;
  5077. begin { restoreState }
  5078.   if playMark > 0 then
  5079.     begin
  5080.       undoTo(0);
  5081.       playMark := 0;
  5082.       tryLevel := 0;
  5083.     end;
  5084. end { restoreState };
  5085.  
  5086. exception bpt;
  5087.  
  5088. {
  5089.   returns true if the group (at x, y) is killable.
  5090.   if so, returns the point to play at in killx, killy.
  5091. }
  5092. function killable(gx, gy: integer; var killx, killy: integer): boolean;
  5093. const
  5094.   tryLimit = 300;
  5095.  
  5096. var
  5097.   me, him, depth, i, j, tryCount, tl, topMark, tkMark, mark2: integer;
  5098.   sChar: char;
  5099.   lList, dList: sPointList;
  5100.   tp: point;
  5101.   libList: array[1..maxSPoint] of integer;
  5102.   esc: boolean;
  5103.  
  5104.   function mtNbrs(x, y: integer): integer;
  5105.   var
  5106.     n: integer;
  5107.   begin { mtNbrs }
  5108.     n := 0;
  5109.     if (x > 0) and (bord[x - 1, y] = 0) then
  5110.       n := n + 1;
  5111.     if (x < maxPoint) and (bord[x + 1, y] = 0) then
  5112.       n := n + 1;
  5113.     if (y > 0) and (bord[x, y - 1] = 0) then
  5114.       n := n + 1;
  5115.     if (y < maxPoint) and (bord[x, y + 1] = 0) then
  5116.       n := n + 1;
  5117.     mtNbrs := n;
  5118.   end { mtNbrs };
  5119.  
  5120.   function tKillTree(tx, ty: integer): boolean;
  5121.   var
  5122.     tkMark: integer;
  5123.     escape: boolean;
  5124.  
  5125.   function killTree(tx, ty: integer; var escape: boolean): boolean;
  5126.     label
  5127.       1, 2;
  5128.     var
  5129.       curMark, mark2, mark3, i, j, k, tl, dStart: integer;
  5130.       lList1, lList2: sPointList;
  5131.       libList: array[1..maxSPoint] of integer;
  5132.       tp: point;
  5133.       esc: boolean;
  5134.     begin { killTree }
  5135.       escape := false;
  5136.       tryCount := tryCount + 1;
  5137.       if tryCount > tryLimit then
  5138.         begin
  5139.           killable := false;
  5140.           undoTo(tkMark);
  5141.           for i := 1 to depth - 1 do
  5142.             begin
  5143.               sClearChar(sChar, rXor);
  5144.             end;
  5145.           depth := 1;
  5146.           exit(tKilltree);
  5147.         end;
  5148.       write(sChar);
  5149.       depth := depth + 1;
  5150.       curMark := playMark;
  5151.       plei(tx, ty, me); { try my move }
  5152.       pause;
  5153.       if gList[gMap[groupIDs[tx, ty]]].libC = 0 then { I'm dead }
  5154.         killTree := false
  5155.       else if killFlag then { I killed something of his }
  5156.         killTree := true
  5157.       else if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then { safe }
  5158.         killTree := false
  5159.       else
  5160.         begin
  5161.           sSpanGroup(gx, gy, lList1); { find his liberties }
  5162.           if gList[gMap[groupIDs[tx, ty]]].libC = 1 then { he can kill me }
  5163.             begin
  5164.               if lList1.indx < maxSPoint then { add that option to his list }
  5165.                 begin
  5166.                   lList1.indx := lList1.indx + 1;
  5167.                   spanGroup(tx, ty, pList2); { find my liberty }
  5168.                   with lList1.p[lList1.indx] do
  5169.                     begin
  5170.                       px := pList2.p[1].px;
  5171.                       py := pList2.p[1].py;
  5172.                     end;
  5173.                 end
  5174.               else
  5175.                 begin
  5176.                   killTree := false; { forget it }
  5177.                   goto 1;
  5178.                 end;
  5179.             end;
  5180.           for i := 1 to maxSPoint do    { init liblist so diags can be marked }
  5181.             libList[i] := -1;
  5182.           if (utilPlayLevel > 4) and
  5183.              (lList1.indx > 1) and
  5184.              (gList[gMap[groupIDs[gx, gy]]].libC > 1) then { try diags }
  5185.             begin
  5186.               listDiags(gx, gy, dList);
  5187.               j := 0;
  5188.               i := lList1.indx;
  5189.               while (j < dList.indx) and
  5190.                     (i < maxSPoint) do
  5191.                 begin
  5192.                   j := j + 1;
  5193.                   i := i + 1;
  5194.                   libList[i] := 0;     { mark this as a diag }
  5195.                   with dList.p[j] do
  5196.                     begin
  5197.                       lList1.p[i].px := px;
  5198.                       lList1.p[i].py := py;
  5199.                     end;
  5200.                 end;
  5201.               lList1.indx := i;
  5202.             end;
  5203.           if lList1.indx > 1 then { sort by decreasing lib count }
  5204.             begin
  5205.               for i := 1 to lList1.indx do
  5206.                 if libList[i] <> 0 then       { diags are tried last }
  5207.                   with lList1.p[i] do
  5208.                     begin
  5209.                       mark2 := playMark;
  5210.                       plei(px, py, him);
  5211.                       libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
  5212.                       if (libList[i] > treeLibLim) or
  5213.                          ((libList[i] > (depthLimit - depth)) and
  5214.                           (libList[i] > 2)) then
  5215.                         begin
  5216.                           escape := true;
  5217.                           killTree := false;
  5218.                           goto 1; { he can live }
  5219.                         end;
  5220.                       undoTo(mark2);
  5221.                     end;
  5222.               for i := 1 to lList1.indx - 1 do
  5223.                 for j := i + 1 to lList1.indx do
  5224.                   if libList[i] < libList[j] then
  5225.                     begin
  5226.                       tl := libList[i];
  5227.                       libList[i] := libList[j];
  5228.                       libList[j] := tl;
  5229.                       tp := lList1.p[i];
  5230.                       lList1.p[i] := lList1.p[j];
  5231.                       lList1.p[j] := tp;
  5232.                     end;
  5233.             end;
  5234.           for i := 1 to lList1.indx + 1 do { try his responses }
  5235.             begin
  5236.               mark2 := playMark;
  5237.               if i <= lList1.indx then { try his move }
  5238.                 with lList1.p[i] do
  5239.                   begin
  5240.                     plei(px, py, him); { play his response }
  5241.                     pause;
  5242.                     if gList[gMap[groupIDs[px, py]]].libC < 2 then
  5243.                       goto 2; { a bogus move }
  5244.                   end
  5245.               else if gList[gMap[groupIDs[gx, gy]]].libC <= 1 then
  5246.                 begin
  5247.                   killTree := true; { can't tenuki if in atari }
  5248.                   goto 1;
  5249.                 end;
  5250.               if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then
  5251.                 begin
  5252.                   escape := true;
  5253.                   killTree := false;
  5254.                   goto 1;
  5255.                 end;
  5256.               if gList[gMap[groupIDs[gx, gy]]].libC > 1 then
  5257.                 begin  { look at my responses }
  5258.                   sSpanGroup(gx, gy, lList2); { list his liberties }
  5259.                   dStart := lList2.indx + 1;
  5260.                   if adjInAtari then { he wins }
  5261.                      begin
  5262.                        killTree := false;
  5263.                        goto 1;
  5264.                      end;
  5265.                   if (lList2.Indx > 2) and adj2Libs then { he wins }
  5266.                      begin
  5267.                        killTree := false;
  5268.                        goto 1;
  5269.                      end;
  5270.                   for k := 1 to maxSPoint do
  5271.                     libList[k] := -1;
  5272.                   if utilPlayLevel > 4 then { account for diagonal moves }
  5273.                     begin
  5274.                       listDiags(gx, gy, dList);
  5275.                       j := 0;
  5276.                       k := lList2.indx;
  5277.                       while (j < dList.indx) and
  5278.                             (k < maxSPoint) do
  5279.                         begin
  5280.                           j := j + 1;
  5281.                           k := k + 1;
  5282.                           libList[k] := 100;
  5283.                           with dList.p[j] do
  5284.                             begin
  5285.                               lList2.p[k].px := px;
  5286.                               lList2.p[k].py := py;
  5287.                             end;
  5288.                         end;
  5289.                       lList2.indx := k;
  5290.                     end;
  5291.                   if lList2.indx > 1 then { sort by increasing lib count }
  5292.                     begin
  5293.                       for k := 1 to lList2.indx do
  5294.                         if libList[k] <> 100 then     { diags go last }
  5295.                           with lList2.p[k] do
  5296.                             begin
  5297.                               mark3 := playMark;
  5298.                               plei(px, py, me);
  5299.                               libList[k] := gList[gMap[groupIDs[gx, gy]]].libC;
  5300.                               undoTo(mark3);
  5301.                             end;
  5302.                       for k := 1 to lList2.indx - 1 do
  5303.                         for j := k + 1 to lList2.indx do
  5304.                           if libList[k] > libList[j] then
  5305.                             begin
  5306.                               tl := libList[k];
  5307.                               libList[k] := libList[j];
  5308.                               libList[j] := tl;
  5309.                               tp := lList2.p[k];
  5310.                               lList2.p[k] := lList2.p[j];
  5311.                               lList2.p[j] := tp;
  5312.                             end
  5313.                           else if (libList[k] = libList[j]) and
  5314.                                   (libList[k] = 1) then
  5315.                             if mtNbrs(lList2.p[k].px, lList2.p[k].py) <
  5316.                                mtNbrs(lList2.p[j].px, lList2.p[j].py) then
  5317.                               begin
  5318.                                 tl := libList[k];
  5319.                                 libList[k] := libList[j];
  5320.                                 libList[j] := tl;
  5321.                                 tp := lList2.p[k];
  5322.                                 lList2.p[k] := lList2.p[j];
  5323.                                 lList2.p[j] := tp;
  5324.                               end;
  5325.                     end;
  5326.                   for j := 1 to lList2.indx do
  5327.                     begin
  5328.                       if killTree(lList2.p[j].px, lList2.p[j].py, esc) then
  5329.                         goto 2; { this kills him }
  5330.                       if esc and (j >= dStart) then
  5331.                         begin
  5332.                           killTree := false;
  5333.                           goto 1; { don't bother with more diags if escapes }
  5334.                         end;
  5335.                     end;
  5336.                   killTree := false;  { none of my responses kills him }
  5337.                   goto 1;
  5338.                 end;
  5339.     2:
  5340.              undoTo(mark2);
  5341.            end;
  5342.           killTree := true; { none of his responses saves him }
  5343.         end;
  5344.     1:
  5345.       undoTo(curMark);
  5346.       sClearChar(sChar, rXor);
  5347.       depth := depth - 1;
  5348.     end { killTree };
  5349.  
  5350.   begin { tKillTree }
  5351.     tryCount := 0;
  5352.     tkMark := playMark;
  5353.     tKillTree := killTree(tx, ty, escape);
  5354.   end { tKillTree };
  5355.  
  5356. begin { killable }
  5357.   dbStop := true;
  5358.   him := bord[gx, gy]; { find out who I am }
  5359.   me := -him;
  5360.   if me = 1 then
  5361.     sChar := '>'
  5362.   else
  5363.     sChar := '|';
  5364.   write(sChar);
  5365.   depth := 1;
  5366.   topMark := playMark;
  5367.   sSpanGroup(gx, gy, lList); { find his liberties }
  5368.   if lList.indx = 1 then
  5369.     begin
  5370.       killable := true;
  5371.       killx := lList.p[1].px;
  5372.       killy := lList.p[1].py;
  5373.     end
  5374.   else if lList.indx > treeLibLim then
  5375.     killable := false
  5376.   else if adjInAtari then
  5377.     killable := false
  5378.   else if (lList.indx > 2) and adj2Libs then
  5379.     killable := false
  5380.   else
  5381.     begin
  5382.       for i := 1 to maxSPoint do
  5383.         libList[i] := -1;
  5384.       if utilPlayLevel > 4 then { account for diagonal moves }
  5385.         begin
  5386.           listDiags(gx, gy, dList);
  5387.           j := 0;
  5388.           i := lList.indx;
  5389.           while (j < dList.indx) and
  5390.                 (i < maxSPoint) do
  5391.             begin
  5392.               j := j + 1;
  5393.               i := i + 1;
  5394.               libList[i] := 100;
  5395.               with dList.p[j] do
  5396.                 begin
  5397.                   lList.p[i].px := px;
  5398.                   lList.p[i].py := py;
  5399.                 end;
  5400.             end;
  5401.           lList.indx := i;
  5402.         end;
  5403.       if lList.indx > 1 then { sort by increasing lib count }
  5404.         begin
  5405.           for i := 1 to lList.indx do
  5406.             if libList[i] <> 100 then  { diags go last }
  5407.               with lList.p[i] do
  5408.                 begin
  5409.                   mark2 := playMark;
  5410.                   plei(px, py, me);
  5411.                   libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
  5412.                   undoTo(mark2);
  5413.                 end;
  5414.           for i := 1 to lList.indx - 1 do
  5415.             for j := i + 1 to lList.indx do
  5416.               if libList[i] > libList[j] then
  5417.                 begin
  5418.                   tl := libList[i];
  5419.                   libList[i] := libList[j];
  5420.                   libList[j] := tl;
  5421.                   tp := lList.p[i];
  5422.                   lList.p[i] := lList.p[j];
  5423.                   lList.p[j] := tp;
  5424.                 end
  5425.               else if (libList[i] = libList[j]) and
  5426.                       (libList[i] = 1) then
  5427.                 if mtNbrs(lList.p[i].px, lList.p[i].py) <
  5428.                    mtNbrs(lList.p[j].px, lList.p[j].py) then
  5429.                   begin
  5430.                     tl := libList[i];
  5431.                     libList[i] := libList[j];
  5432.                     libList[j] := tl;
  5433.                     tp := lList.p[i];
  5434.                     lList.p[i] := lList.p[j];
  5435.                     lList.p[j] := tp;
  5436.                   end;
  5437.         end;
  5438.       for i := 1 to lList.indx do
  5439.         begin
  5440.           if legal[lList.p[i].px, lList.p[i].py] then
  5441.             begin
  5442.               killx := lList.p[i].px;
  5443.               killy := lList.p[i].py;
  5444.               if tKillTree(killx, killy) then
  5445.                 begin
  5446.                   killable := true;
  5447.                   sClearChar(sChar, rXor);
  5448.                   exit(killable);
  5449.                 end;
  5450.             end;
  5451.         end;
  5452.       killable := false;
  5453.     end;
  5454.   sClearChar(sChar, rXor);
  5455. end { killable };
  5456.  
  5457. {
  5458.   returns true if the group (at gx, gy) is saveable.
  5459.   if so, returns the point to play at in savex, savey
  5460. }
  5461. function saveable(gx, gy: integer; var savex, savey: integer): boolean;
  5462. label
  5463.   1;
  5464. var
  5465.   me, him, gx1, gx2, i, j, smark, mark2, tl: integer;
  5466.   sChar: char;
  5467.   dList: sPointList;
  5468.   tp: point;
  5469.   libList: array[1..maxSPoint] of integer;
  5470. begin { saveable }
  5471.   dbStop := true;
  5472.   me := bord[gx, gy];
  5473.   him := -me;
  5474.   if me = 1 then
  5475.     sChar := '|'
  5476.   else
  5477.     sChar := '>';
  5478.   write(sChar);
  5479.   spanGroup(gx, gy, pList3); { find my liberties }
  5480.   if adjInAtari then { one of my options is to kill }
  5481.     begin
  5482.       listAdjacents(gx, gy, aList);
  5483.       for i := 1 to aList.indx do
  5484.         if gList[aList.v[i]].libC = 1 then
  5485.           with gList[aList.v[i]] do
  5486.             begin
  5487.               spanGroup(lx, ly, pList1); { find it's liberty }
  5488.               pList3.indx := pList3.indx + 1;
  5489.               pList3.p[pList3.indx].px := pList1.p[1].px;
  5490.               pList3.p[pList3.indx].py := pList1.p[1].py;
  5491.             end;
  5492.     end;
  5493.   for i := 1 to maxSPoint do
  5494.     libList[i] := -1;
  5495.   if (utilPlayLevel > 4) and
  5496.      (gList[gMap[groupIDs[gx, gy]]].libC > 1) then { account for diags }
  5497.     begin
  5498.       listDiags(gx, gy, dList);
  5499.       j := 0;
  5500.       i := pList3.indx;
  5501.       while (j < dList.indx) and
  5502.             (i < maxSPoint) do
  5503.         begin
  5504.           j := j + 1;
  5505.           i := i + 1;
  5506.           libList[i] := 100;
  5507.           with dList.p[j] do
  5508.             begin
  5509.               pList3.p[i].px := px;
  5510.               pList3.p[i].py := py;
  5511.             end;
  5512.         end;
  5513.       pList3.indx := i;
  5514.     end;
  5515.   if pList3.indx > 1 then { sort by decreasing lib count }
  5516.     begin
  5517.       for i := 1 to pList3.indx do
  5518.         if libList[i] <> 100 then
  5519.           with pList3.p[i] do
  5520.             begin
  5521.               mark2 := playMark;
  5522.               plei(px, py, me);
  5523.               libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
  5524.               if libList[i] > treeLibLim then { i'm safe }
  5525.                 begin
  5526.                   savex := px;
  5527.                   savey := py;
  5528.                   saveable := true;
  5529.                   goto 1;
  5530.                 end;
  5531.               undoTo(mark2);
  5532.             end;
  5533.       for i := 1 to pList3.indx - 1 do
  5534.         for j := i + 1 to pList3.indx do
  5535.           if libList[i] < libList[j] then
  5536.             begin
  5537.               tl := libList[i];
  5538.               libList[i] := libList[j];
  5539.               libList[j] := tl;
  5540.               tp := pList3.p[i];
  5541.               pList3.p[i] := pList3.p[j];
  5542.               pList3.p[j] := tp;
  5543.             end;
  5544.     end;
  5545.   for i := 1 to pList3.indx do
  5546.     begin
  5547.       savex := pList3.p[i].px;
  5548.       savey := pList3.p[i].py;
  5549.       if legal[savex, savey] then
  5550.         begin
  5551.           smark := playMark;
  5552.           plei(savex, savey, me);
  5553.           pause;
  5554.           if gList[gMap[groupIDs[savex, savey]]].libC > 1 then
  5555.             if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then
  5556.               begin
  5557.                 saveable := true;
  5558.                 restoreState;
  5559.                 sClearChar(sChar, rXor);
  5560.                 exit(saveable);
  5561.               end
  5562.             else if gList[gMap[groupIDs[gx, gy]]].libC > 1 then
  5563.               if not killable(gx, gy, gx1, gx2) then
  5564.                 begin
  5565.                   saveable := true;
  5566.                   restoreState;
  5567.                   sClearChar(sChar, rXor);
  5568.                   exit(saveable);
  5569.                 end;
  5570.           undoTo(smark);
  5571.         end;
  5572.     end;
  5573.   saveable := false;
  5574. 1:
  5575.   restoreState;
  5576.   sClearChar(sChar, rXor);
  5577. end { saveable };
  5578.  
  5579. {
  5580.   marks unsavable groups as dead
  5581. }
  5582. procedure markDead;
  5583. var
  5584.   i, j, gx, gy: integer;
  5585. begin { markDead }
  5586.   for i := 1 to maxGroupID do
  5587.     with gList[i] do
  5588.       if killable(lx, ly, gx, gy) then
  5589.         isDead := not saveable(lx, ly, gx, gy)
  5590.       else
  5591.         isDead := false;
  5592.   for i := 0 to maxPoint do
  5593.     for j := 0 to maxPoint do
  5594.       if bord[i, j] = 0 then
  5595.         ndbord[i, j] := 0
  5596.       else if gList[groupIDs[i, j]].isDead then
  5597.         ndbord[i, j] := 0
  5598.       else
  5599.         ndbord[i, j] := bord[i, j];
  5600. end { markDead };
  5601.  
  5602. {
  5603.   marks groups with two eyes as live
  5604. }
  5605. procedure markLive;
  5606. var
  5607.   i, j, size, sMark: integer;
  5608.   saw1, sawm1: boolean;
  5609.  
  5610.   procedure span(x, y: integer);
  5611.   begin { span }
  5612.     if ndbord[x, y] = 1 then
  5613.       saw1 := true
  5614.     else if ndbord[x, y] = -1 then
  5615.       sawm1 := true
  5616.     else if sGroups[x, y] = 0 then
  5617.       begin
  5618.         sGroups[x, y] := sMark;
  5619.         size := size + 1;
  5620.         if x > 0 then
  5621.           span(x - 1, y);
  5622.         if x < maxPoint then
  5623.           span(x + 1, y);
  5624.         if y > 0 then
  5625.           span(x, y - 1);
  5626.         if y < maxPoint then
  5627.           span(x, y + 1);
  5628.       end;
  5629.   end { span };
  5630.  
  5631.   function checkLive(x, y: integer): boolean;
  5632.   var
  5633.     numEyes, who: integer;
  5634.  
  5635.     procedure span(x, y: integer);
  5636.     begin { span }
  5637.       markBoard[x, y] := marker;
  5638.       if ndbord[x, y] = 0 then
  5639.         with sList[sGroups[x, y]] do
  5640.           begin
  5641.             if (sm <> marker) and
  5642.                (w = who) then
  5643.               begin
  5644.                 sm := marker;
  5645.                 if s > 6 then
  5646.                   exit(checkLive);
  5647.                 numEyes := numEyes + 1;
  5648.                 if numEyes > 1 then
  5649.                   exit(checkLive);
  5650.               end;  
  5651.           end
  5652.       else if bord[x, y] = who then
  5653.         begin
  5654.           if (x > 0) and
  5655.              (markBoard[x - 1, y] <> marker) then
  5656.             span(x - 1, y);
  5657.           if (x < maxPoint) and
  5658.              (markBoard[x + 1, y] <> marker) then
  5659.             span(x + 1, y);
  5660.           if (y > 0) and
  5661.              (markBoard[x, y - 1] <> marker) then
  5662.             span(x, y - 1);
  5663.           if (y < maxPoint) and
  5664.              (markBoard[x, y + 1] <> marker) then
  5665.             span(x, y + 1);
  5666.         end;
  5667.     end { span };
  5668.  
  5669.   begin { checkLive }
  5670.     checkLive := true;
  5671.     numEyes := 0;
  5672.     who := bord[x, y];
  5673.     marker := marker + 1;
  5674.     span(x, y);
  5675.     checkLive := false;
  5676.   end { checkLive };
  5677.  
  5678. begin { markLive }
  5679.   sMark := 0;
  5680.   initArray(sGroups);
  5681.   for i := 0 to maxPoint do
  5682.     for j := 0 to maxPoint do
  5683.       if (sGroups[i, j] = 0) and
  5684.          (ndbord[i, j] = 0) then
  5685.         begin
  5686.           size := 0;
  5687.           sMark := sMark + 1;
  5688.           sawm1 := false;
  5689.           saw1 := false;
  5690.           span(i, j);
  5691.           sList[sMark].s := size;
  5692.           sList[sMark].sm := 0;
  5693.           if sawm1 then
  5694.             if saw1 then
  5695.               sList[sMark].w := 0
  5696.             else
  5697.               sList[sMark].w := -1
  5698.           else if saw1 then
  5699.             sList[sMark].w := 1
  5700.           else
  5701.             sList[sMark].w := 0;
  5702.         end;
  5703.   for i := 1 to maxGroupID do
  5704.     with gList[i] do
  5705.       if not isDead then
  5706.         isLive := checkLive(lx, ly);
  5707. end { markLive };
  5708.  
  5709. {
  5710.   generates the connection map and the protected point map.
  5711. }
  5712. procedure genConnects;
  5713. var
  5714.   x, y, numStones: integer;
  5715. begin { genConnects }
  5716.   for x := 0 to maxPoint do
  5717.     for y := 0 to maxPoint do
  5718.       begin
  5719.         connectMap[x, y] := 0;
  5720.         protPoints[x, y] := 0;
  5721.       end;
  5722.   for x := 0 to maxPoint do
  5723.     for y := 0 to maxPoint do
  5724.       if bord[x, y] = 1 then   { map connections to this stone }
  5725.         begin
  5726.           if x > 0 then        { direct connection }
  5727.             connectMap[x - 1, y] := connectMap[x - 1, y] + 1;
  5728.           if x < maxPoint then
  5729.             connectMap[x + 1, y] := connectMap[x + 1, y] + 1;
  5730.           if y > 0 then
  5731.             connectMap[x, y - 1] := connectMap[x, y - 1] + 1;
  5732.           if y < maxPoint then
  5733.             connectMap[x, y + 1] := connectMap[x, y + 1] + 1;
  5734.           if (x > 0) and (y > 0) and   { diagonal connection }
  5735.              (bord[x - 1, y] = 0) and (bord[x, y - 1] = 0) then
  5736.             connectMap[x - 1, y - 1] := connectMap[x - 1, y - 1] + 1;
  5737.           if (x < maxPoint) and (y > 0) and
  5738.              (bord[x + 1, y] = 0) and (bord[x, y - 1] = 0) then
  5739.             connectMap[x + 1, y - 1] := connectMap[x + 1, y - 1] + 1; 
  5740.           if (x < maxPoint) and (y < maxPoint) and
  5741.              (bord[x + 1, y] = 0) and (bord[x, y + 1] = 0) then
  5742.             connectMap[x + 1, y + 1] := connectMap[x + 1, y + 1] + 1; 
  5743.           if (x > 0) and (y < maxPoint) and
  5744.              (bord[x - 1, y] = 0) and (bord[x, y + 1] = 0) then
  5745.             connectMap[x - 1, y + 1] := connectMap[x - 1, y + 1] + 1; 
  5746.           if (x > 1) and (kleim[x - 1, y] > 3) then   { one point jump }
  5747.             connectMap[x - 2, y] := connectMap[x - 2, y] + 1; 
  5748.           if (x < (maxPoint - 1)) and (kleim[x + 1, y] > 3) then
  5749.             connectMap[x + 2, y] := connectMap[x + 2, y] + 1; 
  5750.           if (y > 1) and (kleim[x, y - 1] > 3) then
  5751.             connectMap[x, y - 2] := connectMap[x, y - 2] + 1; 
  5752.           if (y < (maxPoint - 1)) and (kleim[x, y + 1] > 3) then
  5753.             connectMap[x, y + 2] := connectMap[x, y + 2] + 1;
  5754.           if (x > 1) and (y > 0) and        { knight's move }
  5755.              (kleim[x - 1, y] > 3) and (kleim[x - 1, y - 1] > 3) then
  5756.             connectMap[x - 2, y - 1] := connectMap[x - 2, y - 1] + 1;
  5757.           if (x > 0) and (y > 1) and
  5758.              (kleim[x, y - 1] > 3) and (kleim[x - 1, y - 1] > 3) then
  5759.             connectMap[x - 1, y - 2] := connectMap[x - 1, y - 2] + 1;
  5760.           if (x < (maxPoint - 1)) and (y > 0) and
  5761.              (kleim[x + 1, y] > 3) and (kleim[x + 1, y - 1] > 3) then
  5762.             connectMap[x + 2, y - 1] := connectMap[x + 2, y - 1] + 1;
  5763.           if (x < maxPoint) and (y > 1) and
  5764.              (kleim[x, y - 1] > 3) and (kleim[x + 1, y - 1] > 3) then
  5765.             connectMap[x + 1, y - 2] := connectMap[x + 1, y - 2] + 1;
  5766.           if (x > 1) and (y < maxPoint) and
  5767.              (kleim[x - 1, y] > 3) and (kleim[x - 1, y + 1] > 3) then
  5768.             connectMap[x - 2, y + 1] := connectMap[x - 2, y + 1] + 1;
  5769.           if (x > 0) and (y < (maxPoint - 1)) and
  5770.              (kleim[x, y + 1] > 3) and (kleim[x - 1, y + 1] > 3) then
  5771.             connectMap[x - 1, y + 2] := connectMap[x - 1, y + 2] + 1;
  5772.           if (x < (maxPoint - 1)) and (y < maxPoint) and
  5773.              (kleim[x + 1, y] > 3) and (kleim[x + 1, y + 1] > 3) then
  5774.             connectMap[x + 2, y + 1] := connectMap[x + 2, y + 1] + 1;
  5775.           if (x < maxPoint) and (y < (maxPoint - 1)) and
  5776.              (kleim[x, y + 1] > 3) and (kleim[x + 1, y + 1] > 3) then
  5777.             connectMap[x + 1, y + 2] := connectMap[x + 1, y + 2] + 1;
  5778.         end
  5779.       else if bord[x, y] = 0 then { see if protected point }
  5780.         begin
  5781.           numStones := 0;
  5782.           if x = 0 then
  5783.             numStones := numStones + 1;
  5784.           if y = 0 then
  5785.             numStones := numStones + 1;
  5786.           if x = maxPoint then
  5787.             numStones := numStones + 1;
  5788.           if y = maxPoint then
  5789.             numStones := numStones + 1;
  5790.           if (x > 0) and (bord[x - 1, y] = 1) then
  5791.             numStones := numStones + 1;
  5792.           if (y > 0) and (bord[x, y - 1] = 1) then
  5793.             numStones := numStones + 1;
  5794.           if (x < maxPoint) and (bord[x + 1, y] = 1) then
  5795.             numStones := numStones + 1;
  5796.           if (y < maxPoint) and (bord[x, y + 1] = 1) then
  5797.             numStones := numStones + 1;
  5798.           if numStones = 4 then
  5799.             protPoints[x, y] := 1
  5800.           else if numStones = 3 then
  5801.             begin
  5802.               if (x > 0) and
  5803.                  ((bord[x - 1, y] = 0) or
  5804.                   ((bord[x - 1, y] = -1) and
  5805.                    (gList[groupIDs[x - 1, y]].libC = 1))) then
  5806.                  protPoints[x, y] := 1
  5807.               else if (x < maxPoint) and
  5808.                       ((bord[x + 1, y] = 0) or
  5809.                        ((bord[x + 1, y] = -1) and
  5810.                         (gList[groupIDs[x + 1, y]].libC = 1))) then
  5811.                  protPoints[x, y] := 1
  5812.               else if (y > 0) and
  5813.                       ((bord[x, y - 1] = 0) or
  5814.                        ((bord[x, y - 1] = -1) and
  5815.                         (gList[groupIDs[x, y - 1]].libC = 1))) then
  5816.                  protPoints[x, y] := 1
  5817.               else if (y < maxPoint) and
  5818.                       ((bord[x, y + 1] = 0) or
  5819.                        ((bord[x, y + 1] = -1) and
  5820.                         (gList[groupIDs[x, y + 1]].libC = 1))) then
  5821.                  protPoints[x, y] := 1
  5822.             end;
  5823.         end; 
  5824.   for x := 0 to maxPoint do
  5825.     for y := 0 to maxPoint do
  5826.       if bord[x, y] <> 0 then
  5827.         begin
  5828.           connectMap[x, y] := 0;
  5829.           protPoints[x, y] := 0;
  5830.         end;
  5831. end { genConnects };
  5832.  
  5833. {
  5834.   generates the whole state of the game.
  5835. }
  5836. procedure genState;
  5837. var
  5838.   i, j: integer;
  5839. begin { genState }
  5840.   inGenState := true;
  5841.   respreicen;
  5842.   markDead;
  5843.   markLive;
  5844.   spread;
  5845.   genConnects;
  5846.   inGenState := false;
  5847. end { genState };
  5848.  
  5849. {
  5850.   generates a value for the [x, y] location that appears to get larger
  5851.   for points that are saddle points in the influence graph (klein)
  5852. }
  5853. function tencen(x, y: integer): integer;
  5854. var
  5855.   a, b, c, d, w, z: integer;
  5856. begin { tencen }
  5857.   if kleim[x, y] > -1 then  { if he does not influence this area, return 50 }
  5858.     begin
  5859.       tencen := 50;
  5860.       exit(tencen);
  5861.     end;
  5862.   w := kleim[x, y]; { w <= -1 }
  5863.   a := iNil;
  5864.   if x > 0 then
  5865.     if kleim[x - 1, y] > -1 then  { if neighbor is not influenced by him }
  5866.       a := kleim[x - 1, y] - w;   { score is sum of his influence on central }
  5867.   b := iNil;                      {  point and my influence on this neighbor }
  5868.   if y > 0 then
  5869.     if kleim[x, y - 1] > -1 then
  5870.       b := kleim[x, y - 1] - w;
  5871.   c := iNil;
  5872.   if x < maxPoint then
  5873.     if kleim[x + 1, y] > -1 then
  5874.       c := kleim[x + 1, y] - w;
  5875.   d := iNil;
  5876.   if y < maxPoint then
  5877.     if kleim[x, y + 1] > -1 then
  5878.       d := kleim[x, y + 1] - w;
  5879.   z := a;             { z := max(a, b, c, d) }
  5880.   if z <> iNil then
  5881.     begin
  5882.       if (b <> iNil) and
  5883.          (b > z) then
  5884.         z := b;
  5885.     end
  5886.   else
  5887.     z := b; 
  5888.   if z <> iNil then
  5889.     begin
  5890.       if (c <> iNil) and
  5891.          (c > z) then
  5892.         z := c;
  5893.     end
  5894.   else
  5895.     z := c; 
  5896.   if z <> iNil then
  5897.     begin
  5898.       if (d <> iNil) and
  5899.          (d > z) then
  5900.         z := d;
  5901.     end
  5902.   else
  5903.     z := d; 
  5904.   if (z <> iNil) and
  5905.      ((x = 0) or
  5906.       (y = 0) or
  5907.       (x = maxPoint) or
  5908.       (y = maxPoint)) then
  5909.     z := z * 2;     { double z if on the edge of the board ?? }
  5910.   if z <> iNil then
  5911.     tencen := z
  5912.   else
  5913.     tencen := 50;
  5914. end { tencen };
  5915.  
  5916. procedure initGPUtils;
  5917. begin { initGPUtils }
  5918.   initArray(markBoard);
  5919.   initState;
  5920.   marker := 0;
  5921.   playMark := 0;
  5922.   with gList[0] do
  5923.     begin
  5924.       isLive := false;
  5925.       isDead := false;
  5926.       libC := 0;
  5927.       size := 0;
  5928.       numEyes := 0;
  5929.       lx := -1;
  5930.       ly := -1;
  5931.     end;
  5932.   gMap[0] := 0;
  5933.   dbStop := false;
  5934.   inGenState := false;
  5935. end. { initGPUtils }
  5936.  
  5937. SHAR_EOF
  5938. fi
  5939. if test -f 'goPlayer.pas'
  5940. then
  5941.     echo shar: "will not over-write existing file 'goPlayer.pas'"
  5942. else
  5943. cat << \SHAR_EOF > 'goPlayer.pas'
  5944. {---------------------------------------------------------------}
  5945. { GoPlayer.Pas                                                  }
  5946. {                                                               }
  5947. { Go Move Generator                                             }
  5948. { Copyright (c) 1983 by Three Rivers Computer Corp.             }
  5949. {                                                               }
  5950. { Written: January 17, 1983 by Stoney Ballard                   }
  5951. { Edit History:                                                 }
  5952. {---------------------------------------------------------------}
  5953.  
  5954. module goPlayer;
  5955.  
  5956. exports
  5957.  
  5958. imports goCom from goCom;
  5959.  
  5960. { returns true if a move was generated, false for a pass }
  5961. function playMove(who: sType; var xLoc, yLoc: integer): boolean;
  5962. procedure showPlayState(who: sType);
  5963. procedure initGoPlayer;
  5964.  
  5965. var
  5966.   playReason: string;
  5967.   playLevel: integer;
  5968.   maxPlayLevel: integer;
  5969.  
  5970. private
  5971.  
  5972. imports goPlayUtils from goPlayUtils;
  5973. imports popUp from popUp;
  5974. imports goBoard from goBoard;
  5975. imports perq_string from perq_string;
  5976. imports io_others from io_others;
  5977.  
  5978. var
  5979.   saveNLibs: boolean;
  5980.   stateMenu: pNameDesc;
  5981.  
  5982. exception broken;
  5983.  
  5984. procedure blek(var moveX, moveY: integer);
  5985. label
  5986.   1; { done }
  5987.  
  5988. var
  5989.   x, y: integer;
  5990.   dapList1, dapList2, dapList3: pointList;
  5991.  
  5992.   {
  5993.     Checks out a move.
  5994.     If my stone is not killable then true.
  5995.   }
  5996.   function safeMove(x, y: integer): boolean;
  5997.   var
  5998.     gbx, gby: integer;
  5999.   begin { safeMove }
  6000.     plei(x, y, 1);              { try playing at point }
  6001.     if killFlag then { I shouldn't kill if lookForKill didn't }
  6002.       safeMove := false
  6003.     else if gList[groupIDs[x, y]].libC < 2 then
  6004.       begin                   { if it is in atari or dead }
  6005.         safeMove := false;      { reject it }
  6006.       end
  6007.     else if gList[groupIDs[x, y]].libC <= treeLibLim then { see if killable }
  6008.       if playLevel > 0 then
  6009.         safeMove := not killable(x, y, gbx, gby)
  6010.       else
  6011.         safeMove := true
  6012.     else
  6013.       safeMove := true;
  6014.     restoreState;
  6015.   end { safeMove };
  6016.  
  6017.   function heCanCut(x, y: integer): boolean;
  6018.   var
  6019.     gx, gy: integer;
  6020.   begin { heCanCut }
  6021.     if playLevel > 3 then
  6022.       begin
  6023.         plei(x, y, -1);  { try his cut }
  6024.         heCanCut := not killable(x, y, gx, gy);
  6025.         restoreState;
  6026.       end
  6027.     else
  6028.       heCanCut := true;
  6029.   end { heCanCut };
  6030.  
  6031.   {
  6032.     Plays on a corner point if possible
  6033.     returns true if so
  6034.   }
  6035.   function takeCorner(var x, y: integer): boolean;
  6036.   var
  6037.     field, i: integer;
  6038.  
  6039.     {
  6040.       checks a point for no influence and no neighbors
  6041.       sets up return vars and exits takeCorner if ok
  6042.     }
  6043.     procedure checkPos(tx, ty, field: integer);
  6044.     var
  6045.       ok: boolean;
  6046.     begin { checkPos }
  6047.       ok := (((field = 0) and (kleim[tx, ty] = 0)) or  { if in field limits }
  6048.              ((field > 0) and
  6049.               (kleim[tx, ty] >= 0) and (kleim[tx, ty] <= field)) or
  6050.              ((field < 0) and
  6051.               (kleim[tx, ty] <= 0) and (kleim[tx, ty] >= field))) and
  6052.             (bord[tx - 1, ty] = 0) and { and no neighbors }
  6053.             (bord[tx + 1, ty] = 0) and
  6054.             (bord[tx, ty - 1] = 0) and  
  6055.             (bord[tx, ty + 1] = 0);
  6056.       if ok then
  6057.         begin
  6058.           x := tx;
  6059.           y := ty;
  6060.           takeCorner := true;
  6061.           exit(takeCorner);
  6062.         end;
  6063.     end { checkPos };
  6064.  
  6065.   begin { takeCorner }
  6066.     playReason := 'takeCorner';
  6067.     i := maxPoint - 3;
  6068.     field := -1;
  6069.     repeat
  6070.       if field = -1 then
  6071.         field := 0
  6072.       else if field = 0 then
  6073.         field := 4
  6074.       else
  6075.         field := -4;
  6076.       checkPos(2, 3, field);
  6077.       checkPos(3, 2, field);
  6078.       checkPos(2, i, field);
  6079.       checkPos(3, i + 1, field);
  6080.       checkPos(i, i + 1, field);
  6081.       checkPos(i + 1, i, field);
  6082.       checkPos(i, 2, field);
  6083.       checkPos(i + 1, 3, field);
  6084.       checkPos(2, 4, field);
  6085.       checkPos(4, 2, field);
  6086.       checkPos(2, i - 1, field);
  6087.       checkPos(4, i + 1, field);
  6088.       checkPos(i - 1, i + 1, field);
  6089.       checkPos(i + 1, i - 1, field);
  6090.       checkPos(i + 1, 4, field);
  6091.       checkPos(i - 1, 2, field);
  6092.     until field = -4;
  6093.     takeCorner := false;
  6094.   end { takeCorner }; 
  6095.  
  6096.   {
  6097.     first phase of 3-line extentions
  6098.   }
  6099.   function extend(var x, y: integer): boolean;
  6100.   var
  6101.     i: integer;
  6102.   begin { extend }
  6103.     playReason := 'extend';
  6104.     for i := 2 to maxPoint - 2 do   { look along a three line }
  6105.       if (kleim[2, i] = 0) and
  6106.          (bord[1, i] = 0) and
  6107.          (bord[3, i] = 0) and
  6108.          (bord[2, i - 1] = 0) and
  6109.          (bord[2, i + 1] = 0) then
  6110.         begin
  6111.           x := 2;        { return the first point that there's nothing around }
  6112.           y := i;
  6113.           extend := true;
  6114.           exit(extend);
  6115.         end;
  6116.     for i := 2 to maxPoint - 2 do         { another 3-line extention }
  6117.       if (kleim[i, maxPoint - 2] = 0) and
  6118.          (bord[i - 1, maxPoint - 2] = 0) and
  6119.          (bord[i + 1, maxPoint - 2] = 0) and
  6120.          (bord[i, maxPoint - 1] = 0) and
  6121.          (bord[i, maxPoint - 3] = 0) then
  6122.         begin
  6123.           x := i;
  6124.           y := maxPoint - 2;
  6125.           extend := true;
  6126.           exit(extend);
  6127.         end;
  6128.     for i := maxPoint - 2 downto 2 do     { another 3-line extention }
  6129.       if (kleim[maxPoint - 2, i] = 0) and
  6130.          (bord[maxPoint - 1, i] = 0) and
  6131.          (bord[maxPoint - 3, i] = 0) and
  6132.          (bord[maxPoint - 2, i - 1] = 0) and
  6133.          (bord[maxPoint - 2, i + 1] = 0) then
  6134.         begin
  6135.           x := maxPoint - 2;
  6136.           y := i;
  6137.           extend := true;
  6138.           exit(extend);
  6139.         end;
  6140.     for i := maxPoint - 2 downto 2 do    { another 3-line extention }
  6141.       if (kleim[i, 2] = 0) and
  6142.          (bord[i - 1, 2] = 0) and
  6143.          (bord[i + 1, 2] = 0) and
  6144.          (bord[i, 1] = 0) and
  6145.          (bord[i, 3] = 0) then
  6146.         begin
  6147.           x := i;
  6148.           y := 2;
  6149.           extend := true;
  6150.           exit(extend);
  6151.         end;
  6152.     extend := false;
  6153.   end { extend };
  6154.  
  6155.   {
  6156.     second phase of extentions - plays in my lowest influence spots on
  6157.     the 3-lines, so long as they are not touching anything
  6158.   }
  6159.   function extend2(var x, y: integer): boolean;
  6160.   var
  6161.     i, rekrd, veliu: integer;
  6162.   begin { extend2 }
  6163.     playReason := 'extend2';
  6164.     rekrd := iNil;
  6165.     x := iNil;
  6166.     y := iNil;
  6167.     for i := 3 to maxPoint - 3 do    { scan a 3-line }
  6168.       if legal[2, i] then         { if there is nobody there }
  6169.         begin
  6170.           veliu := kleim[2, i];     { get influence }
  6171.           if (veliu < 7) and        { a reasonable hole in my wall }
  6172.              (veliu > -5) and       { or a reasonable gap in his }
  6173.              (bord[2, i + 1] = 0) and { not in contact with any stones }
  6174.              (bord[2, i - 1] = 0) then 
  6175.             if (rekrd <> iNil) and
  6176.                (veliu < rekrd) then
  6177.               begin
  6178.                 rekrd := veliu;     { rekrd gets the smallest value }
  6179.                 x := 2;              { that was seen along all the 3-lines }
  6180.                 y := i;              { x and y save that location }
  6181.               end
  6182.             else if rekrd = iNil then
  6183.               begin
  6184.                 rekrd := veliu;
  6185.                 x := 2;
  6186.                 y := i;
  6187.               end;
  6188.         end;
  6189.     for i := 3 to maxPoint - 3 do
  6190.       if legal[i, 2] then
  6191.         begin
  6192.           veliu := kleim[i, 2];
  6193.           if (veliu < 7) and
  6194.              (veliu > -5) and 
  6195.              (bord[i + 1, 2] = 0) and
  6196.              (bord[i - 1, 2] = 0) then 
  6197.             if (rekrd <> iNil) and
  6198.                (veliu < rekrd) then
  6199.               begin
  6200.                 rekrd := veliu;
  6201.                 x := i;
  6202.                 y := 2;
  6203.               end
  6204.             else if rekrd = iNil then
  6205.               begin
  6206.                 rekrd := veliu;
  6207.                 x := i;
  6208.                 y := 2;
  6209.               end;
  6210.         end;
  6211.     for i := maxPoint - 3 downto 3 do
  6212.       if legal[maxPoint - 2, i] then
  6213.         begin
  6214.           veliu := kleim[maxPoint - 2, i];
  6215.           if (veliu < 7) and
  6216.              (veliu > -5) and 
  6217.              (bord[maxPoint - 2, i + 1] = 0) and
  6218.              (bord[maxPoint - 2, i - 1] = 0) then 
  6219.             if (rekrd <> iNil) and
  6220.                (veliu < rekrd) then
  6221.               begin
  6222.                 rekrd := veliu;
  6223.                 x := maxPoint - 2;
  6224.                 y := i;
  6225.               end
  6226.             else if rekrd = iNil then
  6227.               begin
  6228.                 rekrd := veliu;
  6229.                 x := maxPoint - 2;
  6230.                 y := i;
  6231.               end;
  6232.         end;
  6233.     for i := maxPoint - 3 downto 3 do
  6234.       if legal[i, maxPoint - 2] then
  6235.         begin
  6236.           veliu := kleim[i, maxPoint - 2];
  6237.           if (veliu < 7) and
  6238.              (veliu > -5) and 
  6239.              (bord[i + 1, maxPoint - 2] = 0) and
  6240.              (bord[i - 1, maxPoint - 2] = 0) then 
  6241.             if (rekrd <> iNil) and
  6242.                (veliu < rekrd) then
  6243.               begin
  6244.                 rekrd := veliu;
  6245.                 x := i;
  6246.                 y := maxPoint - 2;
  6247.               end
  6248.             else if rekrd = iNil then
  6249.               begin
  6250.                 rekrd := veliu;
  6251.                 x := i;
  6252.                 y := maxPoint - 2;
  6253.               end;
  6254.         end;
  6255.     extend2 := x <> iNil;
  6256.   end { extend2 };
  6257.  
  6258.   {
  6259.     connects against enemy cuts
  6260.   }
  6261.   function connectCut(var x, y: integer): boolean;
  6262.   var
  6263.     i, j, nap, gid, infl: integer;
  6264.  
  6265.   begin { connectCut }
  6266.     playreason := 'connectCut';
  6267.     connectCut := true;
  6268.     for i := 0 to maxPoint do
  6269.       for j := 0 to maxPoint do
  6270.         if legal[i, j] and
  6271.            (protPoints[i, j] = 0) then   { not a protected point }
  6272.           begin
  6273.             nap := 0;     { how many of my stones am I adjacent to? }
  6274.             if (i > 0) and (bord[i - 1, j] = 1) then
  6275.               begin
  6276.                 nap := nap + 1;
  6277.                 pList.p[nap].px := i - 1;
  6278.                 pList.p[nap].py := j;
  6279.               end;
  6280.             if (j > 0) and (bord[i, j - 1] = 1) then
  6281.               begin
  6282.                 nap := nap + 1;
  6283.                 pList.p[nap].px := i;
  6284.                 pList.p[nap].py := j - 1;
  6285.               end;
  6286.             if (i < maxPoint) and (bord[i + 1, j] = 1) then
  6287.               begin
  6288.                 nap := nap + 1;
  6289.                 pList.p[nap].px := i + 1;
  6290.                 pList.p[nap].py := j;
  6291.               end;
  6292.             if (j < maxPoint) and (bord[i, j + 1] = 1) then
  6293.               begin
  6294.                 nap := nap + 1;
  6295.                 pList.p[nap].px := i;
  6296.                 pList.p[nap].py := j + 1;
  6297.               end;
  6298.             if nap = 1 then { possible knight's or 2-point extention }
  6299.               with pList.p[1] do
  6300.                 begin
  6301.                   gid := groupIDs[px, py];
  6302.                   if (i > 0) and (i < maxPoint) and
  6303.                      (ndbord[i - 1, j] = 1) and
  6304.                      (ndbord[i + 1, j] = 0) then { contact on left }
  6305.                     begin
  6306.                       if ((j > 0) and (ndbord[i, j - 1] = -1) and
  6307.                           (ndbord[i + 1, j - 1] = 1) and
  6308.                           (gid <> groupIDs[i + 1, j - 1])) or
  6309.                          ((j < maxPoint) and (ndbord[i, j + 1] = -1) and
  6310.                           (ndbord[i + 1, j + 1] = 1) and
  6311.                           (gid <> groupIDs[i + 1, j + 1])) or
  6312.                          ((((j > 0) and (ndbord[i, j - 1] = -1)) or
  6313.                            ((j < maxPoint) and (ndbord[i, j + 1] = -1))) and
  6314.                           (i < (maxPoint - 1)) and
  6315.                           (ndbord[i + 2, j] = 1) and
  6316.                           (gid <> groupIDs[i + 2, j])) then
  6317.                         begin
  6318.                           x := i;
  6319.                           y := j;
  6320.                           if safeMove(x, y) then
  6321.                             exit(connectCut);
  6322.                         end;
  6323.                     end
  6324.                   else if (i < maxPoint) and (i > 0) and
  6325.                           (ndbord[i + 1, j] = 1) and
  6326.                           (ndbord[i - 1, j] = 0) then { r }
  6327.                     begin
  6328.                       if ((j > 0) and (ndbord[i, j - 1] = -1) and
  6329.                           (ndbord[i - 1, j - 1] = 1) and
  6330.                           (gid <> groupIDs[i - 1, j - 1])) or
  6331.                          ((j < maxPoint) and (ndbord[i, j + 1] = -1) and
  6332.                           (ndbord[i - 1, j + 1] = 1) and
  6333.                           (gid <> groupIDs[i - 1, j + 1])) or
  6334.                          ((((j > 0) and (ndbord[i, j - 1] = -1)) or
  6335.                            ((j < maxPoint) and (ndbord[i, j + 1] = -1))) and
  6336.                           (i > 1) and
  6337.                           (ndbord[i - 2, j] = 1) and
  6338.                           (gid <> groupIDs[i - 2, j])) then
  6339.                         begin
  6340.                           x := i;
  6341.                           y := j;
  6342.                           if safeMove(x, y) then
  6343.                             exit(connectCut);
  6344.                         end;
  6345.                     end
  6346.                   else if (j > 0) and (j < maxPoint) and
  6347.                           (ndbord[i, j - 1] = 1) and
  6348.                           (ndbord[i, j + 1] = 0) then { top }
  6349.                     begin
  6350.                       if ((i > 0) and (ndbord[i - 1, j] = -1) and
  6351.                           (ndbord[i - 1, j + 1] = 1) and
  6352.                           (gid <> groupIDs[i - 1, j + 1])) or
  6353.                          ((i < maxPoint) and (ndbord[i + 1, j] = -1) and
  6354.                           (ndbord[i + 1, j + 1] = 1) and
  6355.                           (gid <> groupIDs[i + 1, j + 1])) or
  6356.                          ((((i > 0) and (ndbord[i - 1, j] = -1)) or
  6357.                            ((i < maxPoint) and (ndbord[i + 1, j] = -1))) and
  6358.                           (j < (maxPoint - 1)) and
  6359.                           (ndbord[i, j + 2] = 1) and
  6360.                           (gid <> groupIDs[i, j + 2])) then
  6361.                         begin
  6362.                           x := i;
  6363.                           y := j;
  6364.                           if safeMove(x, y) then
  6365.                             exit(connectCut);
  6366.                         end;
  6367.                     end
  6368.                   else if (j > 0) and (j < maxPoint) and
  6369.                           (ndbord[i, j + 1] = 1) and
  6370.                           (ndbord[i, j - 1] = 0) then { bottom }
  6371.                     begin
  6372.                       if ((i > 0) and (ndbord[i - 1, j] = -1) and
  6373.                           (ndbord[i - 1, j - 1] = 1) and
  6374.                           (gid <> groupIDs[i - 1, j - 1])) or
  6375.                          ((i < maxPoint) and (ndbord[i + 1, j] = -1) and
  6376.                           (ndbord[i + 1, j - 1] = 1) and
  6377.                           (gid <> groupIDs[i + 1, j - 1])) or
  6378.                          ((((i > 0) and (ndbord[i - 1, j] = -1)) or
  6379.                            ((i < maxPoint) and (ndbord[i + 1, j] = -1))) and
  6380.                           (j > 1) and
  6381.                           (ndbord[i, j - 2] = 1) and
  6382.                           (gid <> groupIDs[i, j - 2])) then
  6383.                         begin
  6384.                           x := i;
  6385.                           y := j;
  6386.                           if safeMove(x, y) then
  6387.                             exit(connectCut);
  6388.                         end;
  6389.                     end;
  6390.                 end
  6391.             else if nap = 2 then { diagonal or 1-point extention }
  6392.               begin
  6393.                 if groupIDs[pList.p[1].px, pList.p[1].py] <>
  6394.                    groupIDs[pList.p[2].px, pList.p[2].py] then
  6395.                   begin
  6396.                     if (pList.p[1].px <> pList.p[2].px) and
  6397.                        (pList.p[1].py <> pList.p[2].py) then { diag }
  6398.                       begin
  6399.                         spanGroup(pList.p[1].px,
  6400.                                   pList.p[1].py, pList1);
  6401.                         spanGroup(pList.p[2].px,
  6402.                                   pList.p[2].py, pList2);
  6403.                         intersectPlist(pList1, pList2, pList3);
  6404.                         if pList3.indx = 1 then
  6405.                           if (i > 0) and (ndbord[i - 1, j] = -1) or
  6406.                              (i < maxPoint) and (ndbord[i + 1, j] = -1) or
  6407.                              (j > 0) and (ndbord[i, j - 1] = -1) or
  6408.                              (j < maxPoint) and (ndbord[i, j + 1] = -1) then
  6409.                             begin { must make direct connection }
  6410.                               x := i;
  6411.                               y := j;
  6412.                               if heCanCut(x, y) then
  6413.                                 if safeMove(x, y) then
  6414.                                   exit(connectCut);
  6415.                             end
  6416.                           else if heCanCut(i, j) then
  6417.                             begin     { protect point if possible }
  6418.                               infl := 1000;
  6419.                               if (i > 0) and legal[i - 1, j] and
  6420.                                  ((i = 1) or (ndbord[i - 2, j] = 0)) and
  6421.                                  ((j = 0) or (ndbord[i - 1, j - 1] = 0)) and
  6422.                                  ((j = maxPoint) or
  6423.                                   (ndbord[i - 1, j + 1] = 0)) then
  6424.                                 if safeMove(i - 1, j) then
  6425.                                   if kleim[i - 1, j] < infl then
  6426.                                     begin
  6427.                                       x := i - 1;
  6428.                                       y := j;
  6429.                                       infl := kleim[i - 1, j];
  6430.                                     end;
  6431.                               if (j > 0) and legal[i, j - 1] and
  6432.                                  ((j = 1) or (ndbord[i, j - 2] = 0)) and
  6433.                                  ((i = 0) or (ndbord[i - 1, j - 1] = 0)) and
  6434.                                  ((i = maxPoint) or
  6435.                                   (ndbord[i + 1, j - 1] = 0)) then
  6436.                                 if safeMove(i, j - 1) then
  6437.                                   if kleim[i, j - 1] < infl then
  6438.                                     begin
  6439.                                       x := i;
  6440.                                       y := j - 1;
  6441.                                       infl := kleim[i, j - 1];
  6442.                                     end;
  6443.                               if (i < maxPoint) and legal[i + 1, j] and
  6444.                                  ((i = (maxPoint - 1)) or
  6445.                                   (ndbord[i + 2, j] = 0)) and
  6446.                                  ((j = 0) or (ndbord[i + 1, j - 1] = 0)) and
  6447.                                  ((j = maxPoint) or
  6448.                                   (ndbord[i + 1, j + 1] = 0)) then
  6449.                                 if safeMove(i + 1, j) then
  6450.                                   if kleim[i + 1, j] < infl then
  6451.                                     begin
  6452.                                       x := i + 1;
  6453.                                       y := j;
  6454.                                       infl := kleim[i + 1, j];
  6455.                                     end;
  6456.                               if (j < maxPoint) and legal[i, j + 1] and
  6457.                                  ((j = (maxPoint - 1)) or
  6458.                                   (ndbord[i, j + 2] = 0)) and
  6459.                                  ((i = 0) or (ndbord[i - 1, j + 1] = 0)) and
  6460.                                  ((i = maxPoint) or
  6461.                                   (ndbord[i + 1, j + 1] = 0)) then
  6462.                                 if safeMove(i, j + 1) then
  6463.                                   if kleim[i, j + 1] < infl then
  6464.                                     begin
  6465.                                       x := i;
  6466.                                       y := j + 1;
  6467.                                       infl := kleim[i, j + 1];
  6468.                                     end;
  6469.                               if infl < 1000 then
  6470.                                 exit(connectCut);
  6471.                               x := i;      { direct connection }
  6472.                               y := j;
  6473.                               if safeMove(x, y) then
  6474.                                 exit(connectCut);
  6475.                             end;
  6476.                       end
  6477.                     else { 1-point extension, only protect if threatened }
  6478.                       begin
  6479.                         if (i > 0) and (ndbord[i - 1, j] = -1) or
  6480.                            (j > 0) and (ndbord[i, j - 1] = -1) or
  6481.                            (i < maxPoint) and (ndbord[i + 1, j] = -1) or
  6482.                            (j < maxPoint) and (ndbord[i, j + 1] = -1) then
  6483.                           begin
  6484.                             x := i;
  6485.                             y := j;
  6486.                             if heCanCut(x, y) then
  6487.                               if safeMove(x, y) then
  6488.                                 exit(connectCut);
  6489.                           end;
  6490.                       end;
  6491.                   end;
  6492.               end
  6493.             else if nap = 3 then { unprotected, but me on 3 sides }
  6494.               begin
  6495.                 if (groupIDs[pList.p[1].px, pList.p[1].py] <>
  6496.                     groupIDs[pList.p[2].px, pList.p[2].py]) or
  6497.                    (groupIDs[pList.p[1].px, pList.p[1].py] <>
  6498.                     groupIDs[pList.p[3].px, pList.p[3].py]) or
  6499.                    (groupIDs[pList.p[3].px, pList.p[3].py] <>
  6500.                     groupIDs[pList.p[2].px, pList.p[2].py]) then
  6501.                   begin
  6502.                     spanGroup(pList.p[1].px, pList.p[1].py, pList1);
  6503.                     spanGroup(pList.p[2].px, pList.p[2].py, pList2);
  6504.                     intersectPlist(pList1, pList2, pList3);
  6505.                     spanGroup(pList.p[3].px, pList.p[3].py, pList2);
  6506.                     intersectPlist(pList2, pList3, pList1);
  6507.                     if pList1.indx = 1 then { a common connect point }
  6508.                       if heCanCut(i, j) then
  6509.                         if safeMove(i, j) then
  6510.                           begin
  6511.                             x := i;
  6512.                             y := j;
  6513.                             exit(connectCut);
  6514.                           end;
  6515.                   end;
  6516.               end;
  6517.           end;
  6518.     connectCut := false;
  6519.   end { connectCut };
  6520.  
  6521.   {
  6522.     cuts the enemy
  6523.   }
  6524.   function cutHim(var x, y: integer): boolean;
  6525.   var
  6526.     i, j, nap, gid: integer;
  6527.   begin { cutHim }
  6528.     playreason := 'cutHim';
  6529.     cutHim := true;
  6530.     for i := 0 to maxPoint do
  6531.       for j := 0 to maxPoint do
  6532.         if legal[i, j] then
  6533.           begin
  6534.             nap := 0;     { how many of his stones am I adjacent to? }
  6535.             if (i > 0) and (ndbord[i - 1, j] = -1) then
  6536.               begin
  6537.                 nap := nap + 1;
  6538.                 pList.p[nap].px := i - 1;
  6539.                 pList.p[nap].py := j;
  6540.               end;
  6541.             if (j > 0) and (ndbord[i, j - 1] = -1) then
  6542.               begin
  6543.                 nap := nap + 1;
  6544.                 pList.p[nap].px := i;
  6545.                 pList.p[nap].py := j - 1;
  6546.               end;
  6547.             if (i < maxPoint) and (ndbord[i + 1, j] = -1) then
  6548.               begin
  6549.                 nap := nap + 1;
  6550.                 pList.p[nap].px := i + 1;
  6551.                 pList.p[nap].py := j;
  6552.               end;
  6553.             if (j < maxPoint) and (ndbord[i, j + 1] = -1) then
  6554.               begin
  6555.                 nap := nap + 1;
  6556.                 pList.p[nap].px := i;
  6557.                 pList.p[nap].py := j + 1;
  6558.               end;
  6559.             if nap = 1 then { possible knight's or 2-point extention }
  6560.               with pList.p[1] do
  6561.                 begin
  6562.                   gid := groupIDs[px, py];
  6563.                   if (i > 0) and (i < maxPoint) and
  6564.                      (ndbord[i - 1, j] = -1) and
  6565.                      (connectMap[i, j] > 0) then { contact on left }
  6566.                     begin
  6567.                       if ((j > 0) and
  6568.                           (ndbord[i + 1, j - 1] = -1) and
  6569.                           (gid <> groupIDs[i + 1, j - 1])) or
  6570.                          ((j < maxPoint) and
  6571.                           (ndbord[i + 1, j + 1] = -1) and
  6572.                           (gid <> groupIDs[i + 1, j + 1])) or
  6573.                          ((i < (maxPoint - 1)) and
  6574.                           (ndbord[i + 1, j] = 0) and
  6575.                           (ndbord[i + 2, j] = -1) and
  6576.                           (gid <> groupIDs[i + 2, j])) then
  6577.                         begin
  6578.                           x := i;
  6579.                           y := j;
  6580.                           if safeMove(x, y) then
  6581.                             exit(cutHim);
  6582.                         end;
  6583.                     end
  6584.                   else if (i < maxPoint) and (i > 0) and
  6585.                           (ndbord[i + 1, j] = -1) and
  6586.                           (connectMap[i, j] > 0) then { r }
  6587.                     begin
  6588.                       if ((j > 0) and
  6589.                           (ndbord[i - 1, j - 1] = -1) and
  6590.                           (gid <> groupIDs[i - 1, j - 1])) or
  6591.                          ((j < maxPoint) and
  6592.                           (ndbord[i - 1, j + 1] = -1) and
  6593.                           (gid <> groupIDs[i - 1, j + 1])) or
  6594.                          ((i > 1) and
  6595.                           (ndbord[i - 1, j] = 0) and
  6596.                           (ndbord[i - 2, j] = -1) and
  6597.                           (gid <> groupIDs[i - 2, j])) then
  6598.                         begin
  6599.                           x := i;
  6600.                           y := j;
  6601.                           if safeMove(x, y) then
  6602.                             exit(cutHim);
  6603.                         end;
  6604.                     end
  6605.                   else if (j > 0) and (j < maxPoint) and
  6606.                           (ndbord[i, j - 1] = -1) and
  6607.                           (connectMap[i, j] > 0) then { top }
  6608.                     begin
  6609.                       if ((i > 0) and
  6610.                           (ndbord[i - 1, j + 1] = -1) and
  6611.                           (gid <> groupIDs[i - 1, j + 1])) or
  6612.                          ((i < maxPoint) and
  6613.                           (ndbord[i + 1, j + 1] = -1) and
  6614.                           (gid <> groupIDs[i + 1, j + 1])) or
  6615.                          ((j < (maxPoint - 1)) and
  6616.                           (ndbord[i, j + 1] = 0) and
  6617.                           (ndbord[i, j + 2] = -1) and
  6618.                           (gid <> groupIDs[i, j + 2])) then
  6619.                         begin
  6620.                           x := i;
  6621.                           y := j;
  6622.                           if safeMove(x, y) then
  6623.                             exit(cutHim);
  6624.                         end;
  6625.                     end
  6626.                   else if (j > 0) and (j < maxPoint) and
  6627.                           (ndbord[i, j + 1] = -1) and
  6628.                           (connectMap[i, j] > 0) then { bottom }
  6629.                     begin
  6630.                       if ((i > 0) and
  6631.                           (ndbord[i - 1, j - 1] = -1) and
  6632.                           (gid <> groupIDs[i - 1, j - 1])) or
  6633.                          ((i < maxPoint) and
  6634.                           (ndbord[i + 1, j - 1] = -1) and
  6635.                           (gid <> groupIDs[i + 1, j - 1])) or
  6636.                          ((j > 1) and
  6637.                           (ndbord[i, j - 1] = 0) and
  6638.                           (ndbord[i, j - 2] = -1) and
  6639.                           (gid <> groupIDs[i, j - 2])) then
  6640.                         begin
  6641.                           x := i;
  6642.                           y := j;
  6643.                           if safeMove(x, y) then
  6644.                             exit(cutHim);
  6645.                         end;
  6646.                     end;
  6647.                 end
  6648.             else if nap = 2 then { diagonal or 1-point extention }
  6649.               begin
  6650.                 if groupIDs[pList.p[1].px, pList.p[1].py] <>
  6651.                    groupIDs[pList.p[2].px, pList.p[2].py] then
  6652.                   begin
  6653.                     if (pList.p[1].px <> pList.p[2].px) and
  6654.                        (pList.p[1].py <> pList.p[2].py) then { diag }
  6655.                       begin
  6656.                         spanGroup(pList.p[1].px,
  6657.                                   pList.p[1].py, pList1);
  6658.                         spanGroup(pList.p[2].px,
  6659.                                   pList.p[2].py, pList2);
  6660.                         intersectPlist(pList1, pList2, pList3);
  6661.                         if pList3.indx = 1 then
  6662.                           begin
  6663.                             x := i;
  6664.                             y := j;
  6665.                             if safeMove(x, y) then
  6666.                               exit(cutHim);
  6667.                           end;
  6668.                       end
  6669.                     else { 1-point extension, only cut if connected }
  6670.                       begin
  6671.                         if connectMap[i, j] > 0 then
  6672.                           begin
  6673.                             x := i;
  6674.                             y := j;
  6675.                             if safeMove(x, y) then
  6676.                               exit(cutHim);
  6677.                           end;
  6678.                       end;
  6679.                   end;
  6680.               end
  6681.             else if nap = 3 then { unprotected, but him on 3 sides }
  6682.               begin
  6683.                 if (groupIDs[pList.p[1].px, pList.p[1].py] <>
  6684.                     groupIDs[pList.p[2].px, pList.p[2].py]) or
  6685.                    (groupIDs[pList.p[1].px, pList.p[1].py] <>
  6686.                     groupIDs[pList.p[3].px, pList.p[3].py]) or
  6687.                    (groupIDs[pList.p[3].px, pList.p[3].py] <>
  6688.                     groupIDs[pList.p[2].px, pList.p[2].py]) then
  6689.                   begin
  6690.                     spanGroup(pList.p[1].px, pList.p[1].py, pList1);
  6691.                     spanGroup(pList.p[2].px, pList.p[2].py, pList2);
  6692.                     intersectPlist(pList1, pList2, pList3);
  6693.                     spanGroup(pList.p[3].px, pList.p[3].py, pList2);
  6694.                     intersectPlist(pList2, pList3, pList1);
  6695.                     if pList1.indx = 1 then { a common connect point }
  6696.                       if safeMove(i, j) then
  6697.                         begin
  6698.                           x := i;
  6699.                           y := j;
  6700.                           exit(cutHim);
  6701.                         end;
  6702.                   end;
  6703.               end;
  6704.           end;
  6705.     cutHim := false;
  6706.   end { cutHim };
  6707.  
  6708.   {
  6709.     blocks enemy cuts thru 1-point extensions
  6710.   }
  6711.   function blockCut(var x, y: integer): boolean;
  6712.   var
  6713.     i, j: integer;
  6714.   begin { blockCut }
  6715.     playReason := 'blockCut';
  6716.     blockCut := true;
  6717.     for i := 0 to maxPoint do
  6718.       for j := 0 to maxPoint do
  6719.         if legal[i, j] then
  6720.           begin
  6721.             if (i > 0) and (j > 0) and (j < maxPoint) then
  6722.               begin
  6723.                 if (ndbord[i - 1, j] = -1) and
  6724.                    (ndbord[i - 1, j - 1] = 1) and
  6725.                    (ndbord[i - 1, j + 1] = 1) and
  6726.                    (groupIDs[i - 1, j - 1] <> groupIDs[i - 1, j + 1]) then
  6727.                   begin
  6728.                     x := i;
  6729.                     y := j;
  6730.                     if heCanCut(x, y) then
  6731.                       if safeMove(x, y) then
  6732.                         exit(blockCut);
  6733.                   end;
  6734.               end;
  6735.             if (i < maxPoint) and (j > 0) and (j < maxPoint) then
  6736.               begin
  6737.                 if (ndbord[i + 1, j] = -1) and
  6738.                    (ndbord[i + 1, j - 1] = 1) and
  6739.                    (ndbord[i + 1, j + 1] = 1) and
  6740.                    (groupIDs[i + 1, j - 1] <> groupIDs[i + 1, j + 1]) then
  6741.                   begin
  6742.                     x := i;
  6743.                     y := j;
  6744.                     if heCanCut(x, y) then
  6745.                       if safeMove(x, y) then
  6746.                         exit(blockCut);
  6747.                   end;
  6748.               end;
  6749.             if (j > 0) and (i > 0) and (i < maxPoint) then
  6750.               begin
  6751.                 if (ndbord[i, j - 1] = -1) and
  6752.                    (ndbord[i - 1, j - 1] = 1) and
  6753.                    (ndbord[i + 1, j - 1] = 1) and
  6754.                    (groupIDs[i - 1, j - 1] <> groupIDs[i + 1, j - 1]) then
  6755.                   begin
  6756.                     x := i;
  6757.                     y := j;
  6758.                     if heCanCut(x, y) then
  6759.                       if safeMove(x, y) then
  6760.                         exit(blockCut);
  6761.                   end;
  6762.               end;
  6763.             if (j < maxPoint) and (i > 0) and (i < maxPoint) then
  6764.               begin
  6765.                 if (ndbord[i, j + 1] = -1) and
  6766.                    (ndbord[i - 1, j + 1] = 1) and
  6767.                    (ndbord[i + 1, j + 1] = 1) and
  6768.                    (groupIDs[i - 1, j + 1] <> groupIDs[i + 1, j + 1]) then
  6769.                   begin
  6770.                     x := i;
  6771.                     y := j;
  6772.                     if heCanCut(x, y) then
  6773.                       if safeMove(x, y) then
  6774.                         exit(blockCut);
  6775.                   end;
  6776.               end;
  6777.           end;
  6778.     blockCut := false;
  6779.   end { blockCut };
  6780.  
  6781.   {
  6782.     drops to the edge of the board if threatened
  6783.   }
  6784.   function dropToEdge(var x, y: integer): boolean;
  6785.   var
  6786.     i: integer;
  6787.   begin { dropToEdge }
  6788.     dropToEdge := true;
  6789.     playReason := 'dropToEdge';
  6790.     for i := 1 to maxPoint - 1 do
  6791.       begin
  6792.         if legal[1, i] then
  6793.           if (ndbord[2, i] = 1) and
  6794.              (ndbord[0, i] = 0) and
  6795.              (ndbord[1, i - 1] < 1) and
  6796.              (ndbord[1, i + 1] < 1) and
  6797.              ((ndbord[2, i - 1] = -1) or
  6798.               (ndbord[2, i + 1] = -1) or
  6799.               (ndbord[1, i - 1] = -1) or
  6800.               (ndbord[1, i + 1] = -1)) then
  6801.             begin
  6802.               x := 1;
  6803.               y := i;
  6804.               if safeMove(x, y) then
  6805.                 exit(dropToEdge);
  6806.             end;
  6807.         if legal[maxPoint - 1, i] then
  6808.           if (ndbord[maxPoint - 2, i] = 1) and
  6809.              (ndbord[maxPoint, i] = 0) and
  6810.              (ndbord[maxPoint - 1, i - 1] < 1) and
  6811.              (ndbord[maxPoint - 1, i + 1] < 1) and
  6812.              ((ndbord[maxPoint - 2, i - 1] = -1) or
  6813.               (ndbord[maxPoint - 2, i + 1] = -1) or
  6814.               (ndbord[maxPoint - 1, i - 1] = -1) or
  6815.               (ndbord[maxPoint - 1, i + 1] = -1)) then
  6816.             begin
  6817.               x := maxPoint - 1;
  6818.               y := i;
  6819.               if safeMove(x, y) then
  6820.                 exit(dropToEdge);
  6821.             end;
  6822.         if legal[i, 1] then
  6823.           if (ndbord[i, 2] = 1) and
  6824.              (ndbord[i, 0] = 0) and
  6825.              (ndbord[i - 1, 1] < 1) and
  6826.              (ndbord[i + 1, 1] < 1) and
  6827.              ((ndbord[i - 1, 2] = -1) or
  6828.               (ndbord[i + 1, 2] = -1) or
  6829.               (ndbord[i - 1, 1] = -1) or
  6830.               (ndbord[i + 1, 1] = -1)) then
  6831.             begin
  6832.               x := i;
  6833.               y := 1;
  6834.               if safeMove(x, y) then
  6835.                 exit(dropToEdge);
  6836.             end;
  6837.         if legal[i, maxPoint - 1] then
  6838.           if (ndbord[i, maxPoint - 2] = 1) and
  6839.              (ndbord[i, maxPoint] = 0) and
  6840.              (ndbord[i - 1, maxPoint - 1] < 1) and
  6841.              (ndbord[i + 1, maxPoint - 1] < 1) and
  6842.              ((ndbord[i - 1, maxPoint - 2] = -1) or
  6843.               (ndbord[i + 1, maxPoint - 2] = -1) or
  6844.               (ndbord[i - 1, maxPoint - 1] = -1) or
  6845.               (ndbord[i + 1, maxPoint - 1] = -1)) then
  6846.             begin
  6847.               x := i;
  6848.               y := maxPoint - 1;
  6849.               if safeMove(x, y) then
  6850.                 exit(dropToEdge);
  6851.             end;
  6852.         if legal[0, i] then
  6853.           if (ndbord[1, i] = 1) and
  6854.              (ndbord[0, i - 1] < 1) and
  6855.              (ndbord[0, i + 1] < 1) and
  6856.              (((ndbord[1, i - 1] = -1) and
  6857.                (ndbord[1, i + 1] = -1)) or
  6858.               (ndbord[0, i - 1] = -1) or
  6859.               (ndbord[0, i + 1] = -1)) then
  6860.             begin
  6861.               x := 0;
  6862.               y := i;
  6863.               if safeMove(x, y) then
  6864.                 exit(dropToEdge);
  6865.             end;
  6866.         if legal[maxPoint, i] then
  6867.           if (ndbord[maxPoint - 1, i] = 1) and
  6868.              (ndbord[maxPoint, i - 1] < 1) and
  6869.              (ndbord[maxPoint, i + 1] < 1) and
  6870.              (((ndbord[maxPoint - 1, i - 1] = -1) and
  6871.                (ndbord[maxPoint - 1, i + 1] = -1)) or
  6872.               (ndbord[maxPoint, i - 1] = -1) or
  6873.               (ndbord[maxPoint, i + 1] = -1)) then
  6874.             begin
  6875.               x := maxPoint;
  6876.               y := i;
  6877.               if safeMove(x, y) then
  6878.                 exit(dropToEdge);
  6879.             end;
  6880.         if legal[i, 0] then
  6881.           if (ndbord[i, 1] = 1) and
  6882.              (ndbord[i - 1, 0] < 1) and
  6883.              (ndbord[i + 1, 0] < 1) and
  6884.              (((ndbord[i - 1, 1] = -1) and
  6885.                (ndbord[i + 1, 1] = -1)) or
  6886.               (ndbord[i - 1, 0] = -1) or
  6887.               (ndbord[i + 1, 0] = -1)) then
  6888.             begin
  6889.               x := i;
  6890.               y := 0;
  6891.               if safeMove(x, y) then
  6892.                 exit(dropToEdge);
  6893.             end;
  6894.         if legal[i, maxPoint] then
  6895.           if (ndbord[i, maxPoint - 1] = 1) and
  6896.              (ndbord[i - 1, maxPoint] < 1) and
  6897.              (ndbord[i + 1, maxPoint] < 1) and
  6898.              (((ndbord[i - 1, maxPoint - 1] = -1) and
  6899.                (ndbord[i + 1, maxPoint - 1] = -1)) or
  6900.               (ndbord[i - 1, maxPoint] = -1) or
  6901.               (ndbord[i + 1, maxPoint] = -1)) then
  6902.             begin
  6903.               x := i;
  6904.               y := maxPoint;
  6905.               if safeMove(x, y) then
  6906.                 exit(dropToEdge);
  6907.             end;
  6908.       end;
  6909.     dropToEdge := false;
  6910.   end { dropToEdge };
  6911.  
  6912.   {
  6913.     Plays a move that requires a response on the opponent's part
  6914.   }
  6915.   function threaten(var x, y: integer): boolean;
  6916.   var
  6917.     i, j, gx, gy, tNum: integer;
  6918.   begin { threaten }
  6919.     playReason := 'threaten';
  6920.     initArray(threatBord);
  6921.     for i := 1 to maxGroupID do
  6922.       with gList[i] do
  6923.         if (not isLive) and
  6924.            (ndBord[lx, ly] = -1) then
  6925.           begin
  6926.             spanGroup(lx, ly, pList);
  6927.             for j := 1 to pList.indx do
  6928.               with pList.p[j] do
  6929.                 if legal[px, py] then
  6930.                   begin
  6931.                     plei(px, py, 1);
  6932.                     if gList[groupIDs[px, py]].libC > 1 then
  6933.                       if killable(lx, ly, gx, gy) then
  6934.                         threatBord[px, py] := threatBord[px, py] + 1;
  6935.                     restoreState;
  6936.                   end;
  6937.           end;
  6938.     tNum := 0;
  6939.     for i := 0 to maxPoint do
  6940.       for j := 0 to maxPoint do
  6941.         if (threatBord[i, j] > tNum) and
  6942.            ((threatBord[i, j] > 1) or
  6943.             (connectMap[i, j] > 0)) then
  6944.           begin
  6945.             tNum := threatBord[i, j];
  6946.             x := i;
  6947.             y := j;
  6948.           end;
  6949.     threaten := tNum > 0;
  6950.   end { threaten };
  6951.  
  6952.   {
  6953.     Extends walls in a connected fashion.
  6954.     Finds the lowest influence (mine) point that is connected to one
  6955.     of my groups.
  6956.     Only looks in the center of the board.
  6957.   }
  6958.   function extendWall(var x, y: integer): boolean;
  6959.   var
  6960.     infl, i, j: integer;
  6961.   begin { extendWall }
  6962.     playReason := 'extendWall';
  6963.     x := iNil;
  6964.     y := iNil;
  6965.     infl := 11;
  6966.     for i := 2 to maxPoint - 2 do
  6967.       for j := 2 to maxPoint - 2 do
  6968.         if legal[i, j] then
  6969.           if connectMap[i, j] > 0 then
  6970.             if (kleim[i, j] < infl) and
  6971.                (ndbord[i - 1, j] < 1) and
  6972.                (ndbord[i + 1, j] < 1) and
  6973.                (ndbord[i, j - 1] < 1) and
  6974.                (ndbord[i, j + 1] < 1) and
  6975.                ((kleim[i - 1, j] < 0) or
  6976.                 (kleim[i + 1, j] < 0) or
  6977.                 (kleim[i, j - 1] < 0) or
  6978.                 (kleim[i, j + 1] < 0)) then
  6979.               if safeMove(i, j) then
  6980.                 begin
  6981.                   infl := kleim[i, j];
  6982.                   x := i;
  6983.                   y := j;
  6984.                 end;
  6985.     extendWall := x <> iNil;
  6986.   end { extendWall };
  6987.  
  6988.   {
  6989.     Pushes walls in a tightly connected fashion.
  6990.     Finds the lowest influence (mine) point that is connected to one
  6991.     of my groups.
  6992.   }
  6993.   function pushWall(var x, y: integer): boolean;
  6994.   var
  6995.     infl, i, j, na: integer;
  6996.   begin { pushWall }
  6997.     playReason := 'pushWall';
  6998.     x := iNil;
  6999.     y := iNil;
  7000.     infl := 11;
  7001.     for i := 0 to maxPoint do
  7002.       for j := 0 to maxPoint do
  7003.         if legal[i, j] then
  7004.           if connectMap[i, j] > 0 then
  7005.             if (kleim[i, j] < infl) and
  7006.                (((i > 0) and (ndbord[i - 1, j] = 1)) or
  7007.                 ((i < maxPoint) and (ndbord[i + 1, j] = 1)) or
  7008.                 ((j > 0) and (ndbord[i, j - 1] = 1)) or
  7009.                 ((j < maxPoint) and (ndbord[i, j + 1] = 1)) or
  7010.                 ((i > 0) and (j > 0) and (ndbord[i - 1, j - 1] = 1)) or
  7011.                 ((i < maxPoint) and (j > 0) and (ndbord[i + 1, j - 1] = 1)) or
  7012.                 ((i > 0) and (j < maxPoint) and (ndbord[i - 1, j + 1] = 1)) or
  7013.                 ((i < maxPoint) and (j < maxPoint) and
  7014.                  (ndbord[i + 1, j + 1] = 1))) and
  7015.                (((i > 0) and (kleim[i - 1, j] < 0)) or
  7016.                 ((i < maxPoint) and (kleim[i + 1, j] < 0)) or
  7017.                 ((j > 0) and (kleim[i, j - 1] < 0)) or
  7018.                 ((j < maxPoint) and (kleim[i, j + 1] < 0))) then
  7019.               begin
  7020.                 na := 0;
  7021.                 if (i > 0) and (ndbord[i - 1, j] <> 0) then
  7022.                   na := na + 1;
  7023.                 if (i < maxPoint) and (ndbord[i + 1, j] <> 0) then
  7024.                   na := na + 1;
  7025.                 if (j > 0) and (ndbord[i, j - 1] <> 0) then
  7026.                   na := na + 1;
  7027.                 if (j < maxPoint) and (ndbord[i, j + 1] <> 0) then
  7028.                   na := na + 1;
  7029.                 if na < 3 then
  7030.                   if safeMove(i, j) then
  7031.                     begin
  7032.                       infl := kleim[i, j];
  7033.                       x := i;
  7034.                       y := j;
  7035.                     end;
  7036.               end;
  7037.     pushWall := x <> iNil;
  7038.   end { pushWall };
  7039.  
  7040.   {
  7041.     check to see if I can kill anything
  7042.   }
  7043.   function lookForKill(var x, y: integer): boolean;
  7044.   var
  7045.     i: integer;
  7046.   begin { lookForKill }
  7047.     playReason := 'lookForKill';
  7048.     lookForKill := true;
  7049.     for i := 1 to maxGroupID do       { scan the group list }
  7050.       with gList[i] do
  7051.         if (libC = 1) and
  7052.            (ndbord[lx, ly] = -1) then 
  7053.           begin    { we found a live enemy group with one liberty }
  7054.             spanGroup(lx, ly, pList); { find the liberty }
  7055.             x := pList.p[1].px;
  7056.             y := pList.p[1].py;
  7057.             if legal[x, y] then
  7058.               exit(lookForKill);
  7059.           end;
  7060.     lookForKill := false;
  7061.   end { lookForKill };
  7062.  
  7063.   {
  7064.     check to see if I can save anything in atari
  7065.   }
  7066.   function lookForSave(var x, y: integer): boolean;
  7067.   var
  7068.     i: integer;
  7069.   begin { lookForSave }
  7070.     playReason := 'lookForSave';
  7071.     lookForSave := true;
  7072.     for i := 1 to maxGroupID do       { scan the group list }
  7073.       with gList[i] do
  7074.         if (libC = 1) and
  7075.            (ndbord[lx, ly] = 1) then 
  7076.             begin
  7077.               if saveable(lx, ly, x, y) then { see if I can save it }
  7078.                 exit(lookForSave);
  7079.             end;
  7080.     lookForSave := false;
  7081.   end { lookForSave };
  7082.  
  7083.   {
  7084.     check to see if I can save anything with n libs
  7085.   }
  7086.   function lookForSaveN(var x, y: integer): boolean;
  7087.   var
  7088.     i: integer;
  7089.   begin { lookForSaveN }
  7090.     if saveNLibs then
  7091.       begin
  7092.         playReason := 'lookForSaveN';
  7093.         lookForSaveN := true;
  7094.         for i := 1 to maxGroupID do       { scan the group list }
  7095.           with gList[i] do
  7096.             if (libC > 1) and
  7097.                (libC <= treeLibLim) and
  7098.                (ndbord[lx, ly] = 1) then 
  7099.                 begin
  7100.                   if killable(lx, ly, x, y) then
  7101.                     if saveable(lx, ly, x, y) then { see if I can save it }
  7102.                       exit(lookForSaveN);
  7103.                 end;
  7104.       end;
  7105.     lookForSaveN := false;
  7106.   end { lookForSaveN };
  7107.  
  7108.   {
  7109.     check to see if I can attack one of his groups
  7110.   }
  7111.   function lookForAttack(var x, y: integer): boolean;
  7112.   var
  7113.     tx, ty, i: integer;
  7114.   begin { lookForAttack }
  7115.     playReason := 'lookForAttack';
  7116.     lookForAttack := true;
  7117.     for i := 1 to maxGroupID do       { scan the group list }
  7118.       with gList[i] do
  7119.         if (not isLive) and
  7120.            (libC > 1) and
  7121.            (libC <= (treeLibLim + 1)) and
  7122.            (ndbord[lx, ly] = -1) then 
  7123.               begin
  7124.                 if killable(lx, ly, tx, ty) then { can we kill it? }
  7125.                   begin
  7126.                     x := tx;        { yep - do so }
  7127.                     y := ty;
  7128.                     exit(lookForAttack);
  7129.                   end;
  7130.               end;
  7131.     lookForAttack := false;
  7132.   end { lookForAttack };
  7133.  
  7134.   {
  7135.     check to see if I can attack one of his groups
  7136.     uses limited depth search so that it can work on larger lib counts
  7137.   }
  7138.   function findAttack2(var x, y: integer): boolean;
  7139.   var
  7140.     tx, ty, i, otll: integer;
  7141.   begin { findAttack2 }
  7142.     if playLevel < 7 then
  7143.       begin
  7144.         findAttack2 := false;
  7145.         exit(findAttack2);
  7146.       end;
  7147.     playReason := 'findAttack2';
  7148.     findAttack2 := true;
  7149.     depthLimit := 8;
  7150.     otll := treeLibLim;
  7151.     for i := 1 to maxGroupID do       { scan the group list }
  7152.       with gList[i] do
  7153.         if (not isLive) and
  7154.            (ndBord[lx, ly] = -1) and
  7155.            (libC > 1) then
  7156.               begin
  7157.                 treeLibLim := 6;
  7158.                 if killable(lx, ly, tx, ty) then { can we kill it? }
  7159.                   begin
  7160.                     x := tx;        { yep - do so }
  7161.                     y := ty;
  7162.                     exit(findAttack2);
  7163.                   end;
  7164.                 treeLibLim := otll;
  7165.               end;
  7166.     findAttack2 := false;
  7167.     depthLimit := 100;
  7168.   end { findAttack2 };
  7169.  
  7170.   function doubleAtari(var x, y: integer): boolean;
  7171.   var
  7172.     i, j: integer;
  7173.   begin { doubleAtari }
  7174.     playReason := 'doubleAtari';
  7175.     doubleAtari := true;
  7176.     for i := 1 to maxGroupID - 1 do
  7177.       with gList[i] do
  7178.         if (libC = 2) and
  7179.            (ndbord[lx, ly] = -1) then { found an atariable group of his }
  7180.           begin
  7181.             spanGroup(lx, ly, dapList1);
  7182.             for j := i + 1 to maxGroupID do
  7183.               with gList[j] do
  7184.                 if (libC = 2) and
  7185.                    (ndbord[lx, ly] = -1) then
  7186.                 begin
  7187.                   spanGroup(lx, ly, dapList2);
  7188.                   intersectPlist(dapList1, dapList2, dapList3);
  7189.                   if dapList3.indx > 0 then
  7190.                     with dapList3.p[1] do
  7191.                       if legal[px, py] then
  7192.                         begin
  7193.                           plei(px, py, 1);
  7194.                           if gList[groupIDs[px, py]].libC > 1 then
  7195.                             begin
  7196.                               x := px;
  7197.                               y := py;
  7198.                               restoreState;
  7199.                               exit(doubleAtari);
  7200.                             end;
  7201.                           restoreState;
  7202.                         end;
  7203.                 end;
  7204.           end; 
  7205.     doubleAtari := false;
  7206.   end { doubleAtari };
  7207.  
  7208.   {
  7209.     ataris a group just for the hell of it
  7210.   }
  7211.   function atariAnyway(var x, y: integer): boolean;
  7212.   var
  7213.     i: integer;
  7214.   begin { atariAnyway }
  7215.     playReason := 'atariAnyway';
  7216.     atariAnyway := true;
  7217.     for i := 1 to maxGroupID do       { scan the group list }
  7218.       with gList[i] do
  7219.         if (libC = 2) and
  7220.            (ndbord[lx, ly] = -1) then 
  7221.               begin
  7222.                 spanGroup(lx, ly, pList);
  7223.                 with pList.p[1] do
  7224.                   if legal[px, py] and
  7225.                      ((connectMap[px, py] > 0) or
  7226.                       ((px > 0) and (connectMap[px - 1, py] > 0)) or
  7227.                       ((px < maxPoint) and (connectMap[px + 1, py] > 0)) or
  7228.                       ((py > 0) and (connectMap[px, py - 1] > 0)) or
  7229.                       ((py < maxPoint) and (connectMap[px, py + 1] > 0))) then
  7230.                     if safeMove(px, py) then
  7231.                       begin
  7232.                         x := px;
  7233.                         y := py;
  7234.                         exit(atariAnyway);
  7235.                       end;
  7236.                 with pList.p[2] do
  7237.                   if legal[px, py] and
  7238.                      ((connectMap[px, py] > 0) or
  7239.                       ((px > 0) and (connectMap[px - 1, py] > 0)) or
  7240.                       ((px < maxPoint) and (connectMap[px + 1, py] > 0)) or
  7241.                       ((py > 0) and (connectMap[px, py - 1] > 0)) or
  7242.                       ((py < maxPoint) and (connectMap[px, py + 1] > 0))) then
  7243.                     if safeMove(px, py) then
  7244.                       begin
  7245.                         x := px;
  7246.                         y := py;
  7247.                         exit(atariAnyway);
  7248.                       end;
  7249.               end;
  7250.     atariAnyway := false;
  7251.   end { atariAnyway };
  7252.  
  7253.   {
  7254.     undercuts his groups
  7255.   }
  7256.   function underCut(var x, y: integer): boolean;
  7257.   var
  7258.     i, j: integer;
  7259.   begin { underCut }
  7260.     playReason := 'underCut';
  7261.     underCut := true;
  7262.     for i := 1 to maxPoint - 1 do
  7263.       begin
  7264.         if legal[0, i] then
  7265.           begin
  7266.             if ndbord[1, i] = -1 then
  7267.               if safeMove(0, i) then
  7268.                 begin
  7269.                   x := 0;
  7270.                   y := i;
  7271.                   exit(underCut);
  7272.                 end;
  7273.           end;
  7274.         if legal[maxPoint, i] then
  7275.           begin
  7276.             if ndbord[maxPoint - 1, i] = -1 then
  7277.               if safeMove(maxPoint, i) then
  7278.                 begin
  7279.                   x := maxPoint;
  7280.                   y := i;
  7281.                   exit(underCut);
  7282.                 end;
  7283.           end;
  7284.         if legal[i, 0] then
  7285.           begin
  7286.             if ndbord[i, 1] = -1 then
  7287.               if safeMove(i, 0) then
  7288.                 begin
  7289.                   x := i;
  7290.                   y := 0;
  7291.                   exit(underCut);
  7292.                 end;
  7293.           end;
  7294.         if legal[i, maxPoint] then
  7295.           begin
  7296.             if ndbord[i, maxPoint - 1] = -1 then
  7297.               if safeMove(i, maxPoint) then
  7298.                 begin
  7299.                   x := i;
  7300.                   y := maxPoint;
  7301.                   exit(underCut);
  7302.                 end;
  7303.           end;
  7304.       end;
  7305.     underCut := false;
  7306.   end { underCut };
  7307.  
  7308.   {
  7309.     reduces the liberty count of one of his groups
  7310.   }
  7311.   function reduceHisLiberties(var x, y: integer): boolean;
  7312.   var
  7313.     i, j: integer;
  7314.   begin { reduceHisLiberties }
  7315.     playReason := 'reduceHisLiberties';
  7316.     reduceHisLiberties := true;
  7317.     sortLibs;
  7318.     for i := 1 to maxGroupID do
  7319.       with gList[sGList[i]] do
  7320.         if (not isLive) and
  7321.            (libC > 2) and
  7322.            (ndbord[lx, ly] = -1) then
  7323.           begin
  7324.             spanGroup(lx, ly, pList);
  7325.             for j := 1 to pList.indx do
  7326.               with pList.p[j] do
  7327.                 if legal[px, py] and
  7328.                    (connectMap[px, py] > 0) then
  7329.                   if safeMove(px, py) then
  7330.                     begin
  7331.                       x := px;
  7332.                       y := py;
  7333.                       exit(reduceHisLiberties);
  7334.                     end;
  7335.           end;
  7336.     reduceHisLiberties := false;
  7337.   end { reduceHisLiberties };
  7338.  
  7339.   {
  7340.     connects a group to the edge
  7341.   }
  7342.   function dropToEdge2(var x, y: integer): boolean;
  7343.   var
  7344.     i: integer;
  7345.   begin { dropToEdge2 }
  7346.     playReason := 'dropToEdge2';
  7347.     dropToEdge2 := true;
  7348.     for i := 1 to maxPoint - 1 do
  7349.       begin
  7350.         if legal[i, 0] then
  7351.           begin
  7352.             if (ndbord[i, 1] = 1) and
  7353.                ((ndbord[i - 1, 0] < 1) or
  7354.                 (groupIDs[i - 1, 0] <> groupIDs[i, 1])) and
  7355.                ((ndbord[i + 1, 0] < 1) or
  7356.                 (groupIDs[i + 1, 0] <> groupIDs[i, 1])) and
  7357.                ((ndbord[i - 1, 1] = -1) or
  7358.                 (ndbord[i + 1, 1] = -1)) then
  7359.               begin
  7360.                 x := i;
  7361.                 y := 0;
  7362.                 if safeMove(x, y) then
  7363.                   exit(dropToEdge2);
  7364.               end;
  7365.           end;
  7366.         if legal[0, i] then
  7367.           begin
  7368.             if (ndbord[1, i] = 1) and
  7369.                ((ndbord[0, i - 1] < 1) or
  7370.                 (groupIDs[0, i - 1] <> groupIDs[1, i])) and
  7371.                ((ndbord[0, i + 1] < 1) or
  7372.                 (groupIDs[0, i + 1] <> groupIDs[1, i])) and
  7373.                ((ndbord[1, i - 1] = -1) or
  7374.                 (ndbord[1, i + 1] = -1)) then
  7375.               begin
  7376.                 x := 0;
  7377.                 y := i;
  7378.                 if safeMove(x, y) then
  7379.                   exit(dropToEdge2);
  7380.               end;
  7381.           end;
  7382.         if legal[i, maxPoint] then
  7383.           begin
  7384.             if (ndbord[i, maxPoint - 1] = 1) and
  7385.                ((ndbord[i - 1, maxPoint] < 1) or
  7386.                 (groupIDs[i - 1, maxPoint] <> groupIDs[i, maxPoint - 1])) and
  7387.                ((ndbord[i + 1, maxPoint] < 1) or
  7388.                 (groupIDs[i + 1, maxPoint] <> groupIDs[i, maxPoint - 1])) and
  7389.                ((ndbord[i - 1, maxPoint - 1] = -1) or
  7390.                 (ndbord[i + 1, maxPoint - 1] = -1)) then
  7391.               begin
  7392.                 x := i;
  7393.                 y := maxPoint;
  7394.                 if safeMove(x, y) then
  7395.                   exit(dropToEdge2);
  7396.               end;
  7397.           end;
  7398.         if legal[maxPoint, i] then
  7399.           begin
  7400.             if (ndbord[maxPoint - 1, i] = 1) and
  7401.                ((ndbord[maxPoint, i - 1] < 1) or
  7402.                 (groupIDs[maxPoint, i - 1] <> groupIDs[maxPoint - 1, i])) and
  7403.                ((ndbord[maxPoint, i + 1] < 1) or
  7404.                 (groupIDs[maxPoint, i + 1] <> groupIDs[maxPoint - 1, i])) and
  7405.                ((ndbord[maxPoint - 1, i - 1] = -1) or
  7406.                 (ndbord[maxPoint - 1, i + 1] = -1)) then
  7407.               begin
  7408.                 x := maxPoint;
  7409.                 y := i;
  7410.                 if safeMove(x, y) then
  7411.                   exit(dropToEdge2);
  7412.               end;
  7413.           end;
  7414.       end;
  7415.     dropToEdge2 := false;
  7416.   end { dropToEdge2 };
  7417.  
  7418. begin { blek }
  7419.   saveState;                    { save state of the world }
  7420.   if takeCorner(x, y) then
  7421.     goto 1;
  7422.   if lookForSave(x, y) then
  7423.     goto 1;
  7424.   if lookForSaveN(x, y) then
  7425.     goto 1;
  7426.   if extend(x, y) then         { check for possible 3-line extentions }
  7427.     goto 1;
  7428.   if lookForKill(x, y) then
  7429.     goto 1;
  7430.   if doubleAtari(x, y) then
  7431.     goto 1;
  7432.   if lookForAttack(x, y) then
  7433.     goto 1;
  7434.   if threaten(x, y) then
  7435.     goto 1;
  7436.   if extend2(x, y) then
  7437.     goto 1; 
  7438.   if connectCut(x, y) then
  7439.     goto 1;
  7440.   if blockCut(x, y) then
  7441.     goto 1;
  7442.   if cutHim(x, y) then
  7443.     goto 1;
  7444.   if extendWall(x, y) then
  7445.     goto 1; 
  7446.   if findAttack2(x, y) then
  7447.     goto 1;
  7448.   if atariAnyway(x, y) then
  7449.     goto 1;
  7450.   if underCut(x, y) then
  7451.     goto 1;
  7452.   if dropToEdge(x, y) then
  7453.     goto 1;
  7454.   if pushWall(x, y) then
  7455.     goto 1;
  7456.   if reduceHisLiberties(x, y) then
  7457.     goto 1;
  7458.   if dropToEdge2(x, y) then
  7459.     goto 1;
  7460.   moveX := iNil; { pass }
  7461.   moveY := iNil;
  7462.   exit(blek);
  7463. 1: { done }
  7464.   moveX := x;
  7465.   moveY := y;   
  7466. end { blek };
  7467.  
  7468. procedure genBord(who: sType);
  7469. var
  7470.   i, j: integer;
  7471.   noMoves: boolean;
  7472. begin { genBord }
  7473.   utilPlayLevel := playLevel;
  7474.   showTrees := debug;
  7475.   depthLimit := 100;
  7476.   mySType := who;
  7477.   if playLevel < 2 then
  7478.     treeLibLim := 2
  7479.   else
  7480.     treeLibLim := 3;
  7481.   noMoves := true;
  7482.   for i := 0 to maxPoint do
  7483.     for j := 0 to maxPoint do
  7484.       if board[i, j].val = who then
  7485.         begin
  7486.           bord[i, j] := 1;
  7487.           legal[i, j] := false;
  7488.           noMoves := false;
  7489.         end
  7490.       else if board[i, j].val = empty then
  7491.         begin
  7492.           bord[i, j] := 0;
  7493.           legal[i, j] := true;
  7494.         end
  7495.       else
  7496.         begin
  7497.           bord[i, j] := -1;
  7498.           legal[i, j] := false;
  7499.           noMoves := false;
  7500.         end;
  7501.   if koX >= 0 then
  7502.     legal[koX, koY] := false;
  7503.   if noMoves then
  7504.     initState
  7505.   else
  7506.     genState;
  7507. end { genBord };
  7508.  
  7509. function playMove(who: sType; var xLoc, yLoc: integer): boolean;
  7510. var
  7511.   i, j: integer;
  7512.   noMoves: boolean;
  7513. begin { playMove }
  7514.   saveNLibs := playLevel > 2;
  7515.   genBord(who);
  7516.   blek(xLoc, yLoc);
  7517.   playMove := xLoc <> iNil;
  7518. end { playMove };
  7519.  
  7520. procedure showPlayState(who: sType);
  7521. var
  7522.   res: resres;
  7523.   shown: boolean;
  7524.   cx, cy: integer;
  7525.  
  7526.   handler outside;
  7527.   begin { outside }
  7528.     write(''); {control-G}
  7529.     if shown then
  7530.       refreshBoard;
  7531.     exit(showPlayState);
  7532.   end { outside };
  7533.  
  7534.   procedure showIntBord(ib: intBoard);
  7535.   var
  7536.     i, j: integer;
  7537.     s: string;
  7538.   begin { showIntBord }
  7539.     for i := 0 to maxPoint do
  7540.       for j := 0 to maxPoint do
  7541.         if ib[i, j] <> 0 then
  7542.           begin
  7543.             s := intToStr(ib[i, j]);
  7544.             putBString(i, j, s);
  7545.           end;
  7546.   end { showIntBord };
  7547.  
  7548.   procedure showGroupState(sn: integer);
  7549.   var
  7550.     g: integer;
  7551.     s: string;
  7552.  
  7553.     procedure span(x, y: integer);
  7554.     begin { span }
  7555.       markBoard[x, y] := marker;
  7556.       putBString(x, y, s);
  7557.       if (x > 0) and
  7558.          (groupIDs[x - 1, y] = g) and
  7559.          (markBoard[x - 1, y] <> marker) then
  7560.         span(x - 1, y);
  7561.       if (x < maxPoint) and
  7562.          (groupIDs[x + 1, y] = g) and
  7563.          (markBoard[x + 1, y] <> marker) then
  7564.         span(x + 1, y);
  7565.       if (y > 0) and
  7566.          (groupIDs[x, y - 1] = g) and
  7567.          (markBoard[x, y - 1] <> marker) then
  7568.         span(x, y - 1);
  7569.       if (y < maxPoint) and
  7570.          (groupIDs[x, y + 1] = g) and
  7571.          (markBoard[x, y + 1] <> marker) then
  7572.         span(x, y + 1);
  7573.     end { span };
  7574.  
  7575.   begin { showGroupState }
  7576.     marker := marker + 1;
  7577.     if marker = 0 then
  7578.       begin
  7579.         initArray(markBoard);
  7580.         marker := 1;
  7581.       end;
  7582.     if sn < 3 then
  7583.       s := '*';
  7584.     for g := 1 to maxGroupID do
  7585.       with gList[g] do
  7586.         begin
  7587.           case sn of
  7588.             1: { isLive }
  7589.               if isLive then
  7590.                 span(lx, ly);
  7591.             2: { isDead }
  7592.               if isDead then
  7593.                 span(lx, ly);
  7594.             3: { libertyCount }
  7595.               begin
  7596.                 s := intToStr(libC);
  7597.                 span(lx, ly);
  7598.               end;
  7599.           end; { case }
  7600.         end;
  7601.   end { showGroupState };
  7602.  
  7603. begin { showPlayState }
  7604.   genBord(who);
  7605.   shown := false;
  7606.   cx := tabRelX;
  7607.   cy := tabRelY;
  7608.   repeat
  7609.     menu(stateMenu, false, 1, 11, cx, cy, -1, res);
  7610.     if shown then
  7611.       refreshBoard;
  7612.     case res^.indices[1] of
  7613.       1: { bord }
  7614.         showIntBord(bord);
  7615.       2: { ndBord }
  7616.         showIntBord(ndBord);
  7617.       3: { kleim }
  7618.         showIntBord(kleim);
  7619.       4: { sGroups }
  7620.         showIntBord(sGroups);
  7621.       5: { groupIDs }
  7622.         showIntBord(groupIDs);
  7623.       6: { connectMap }
  7624.         showIntBord(connectMap);
  7625.       7: { protPoints }
  7626.         showIntBord(protPoints);
  7627.       8: { isLive }
  7628.         showGroupState(1);
  7629.       9: { isDead }
  7630.         showGroupState(2);
  7631.       10: { libC }
  7632.         showGroupState(3);
  7633.       11: { done }
  7634.         exit(showPlayState);
  7635.     end; { case }
  7636.     shown := true;
  7637.     destroyRes(res);
  7638.   until false;
  7639. end { showPlayState };
  7640.  
  7641. procedure initGoPlayer;
  7642. begin { initGoPlayer }
  7643.   initGPUtils;
  7644.   maxPlayLevel := 7;
  7645.   allocNameDesc(11, 0, stateMenu);
  7646.   with stateMenu^ do
  7647.     begin
  7648.       header := 'State to Display?';
  7649. {$R-}
  7650.       commands[1] := 'Bord';
  7651.       commands[2] := 'NdBord';
  7652.       commands[3] := 'Influence';
  7653.       commands[4] := 'Space Groups';
  7654.       commands[5] := 'Group IDs';
  7655.       commands[6] := 'Connect Map';
  7656.       commands[7] := 'Protected Points';
  7657.       commands[8] := 'Live Groups';
  7658.       commands[9] := 'Dead Groups';
  7659.       commands[10] := 'Liberty Counts';
  7660.       commands[11] := 'Done';
  7661. {$R=}
  7662.     end;
  7663. end. { initGoPlayer }
  7664. SHAR_EOF
  7665. fi
  7666. if test -f 'goTree.pas'
  7667. then
  7668.     echo shar: "will not over-write existing file 'goTree.pas'"
  7669. else
  7670. cat << \SHAR_EOF > 'goTree.pas'
  7671. {---------------------------------------------------------------}
  7672. { GoTree.Pas                                                    }
  7673. {                                                               }
  7674. { Go Game Tree Manager                                          }
  7675. { Copyright (c) 1982 by Three Rivers Computer Corp.             }
  7676. {                                                               }
  7677. { Written: June 3, 1982 by Stoney Ballard                       }
  7678. { Edit History:                                                 }
  7679. {    June  3, 1982  Started                                     }
  7680. {    June  4, 1982  Add dead group removal                      }
  7681. {    June 10, 1982  Use new go file manager                     }
  7682. {    Nov   9, 1982  Extracted from GO.PAS                       }
  7683. {    Nov  15, 1982  Added tag and comment deletion              }
  7684. {    Jan   5, 1983  Increased segment max sizes                 }
  7685. {    Jan   7, 1983  Changed File Format to have global comment  }
  7686. {---------------------------------------------------------------}
  7687.  
  7688. module goTree;
  7689.  
  7690. exports
  7691.  
  7692. imports goCom from goCom;
  7693. imports getTimeStamp from getTimeStamp;
  7694.  
  7695. type
  7696.   pMRec = ^moveRec;
  7697.  
  7698.   tagStr = string[maxTagLen];
  7699.   tagPtr = ^tagRec;
  7700.   tagRec = record
  7701.              mPtr: pMRec;
  7702.              nextTag: tagPtr;
  7703.              sTag: tagStr;
  7704.            end;
  7705.  
  7706.   mType = (header, move, remove, hcPlay, pass);
  7707.   moveRec = packed record
  7708.               mark: boolean;
  7709.               flink: pMRec;
  7710.               case id: mType of
  7711.                 header:
  7712.                   (lastMove: pMRec;
  7713.                    freePool: pMRec;
  7714.                    lastTag: tagPtr;
  7715.                    nextMRec: integer;
  7716.                    nextMBlock: integer;
  7717.                    nextTRec: integer;
  7718.                    nextTBlock: integer;
  7719.                    nextCIdx: integer;
  7720.                    nextCBlock: integer;
  7721.                    freeTags: tagPtr);
  7722.                 hcPlay, move, remove, pass:
  7723.                   (blink: pMRec;
  7724.                    slink: pMRec;
  7725.                    tag: tagPtr;
  7726.                    who: sType;
  7727.                    moveN: integer;
  7728.                    cmtBase: integer;
  7729.                    cmtLen: integer;
  7730.                    case {id:} mType of
  7731.                      hcPlay:
  7732.                        (hcNum: integer);
  7733.                      move, remove:
  7734.                        (mx: integer;
  7735.                         my: integer;
  7736.                         ox: integer;
  7737.                         oy: integer;
  7738.                         kx: integer;
  7739.                         ky: integer) )
  7740.             end;
  7741.  
  7742.   baseBlock = packed record
  7743.                 case boolean of
  7744.                   false:
  7745.                     (padding: array[1..512] of char);
  7746.                   true:
  7747.                     (randBool: boolean;
  7748.                      oldTest: pointer;
  7749.                      fileVersion: integer;
  7750.                      created: timeStamp;
  7751.                      rootComment: string[127])
  7752.               end;
  7753.  
  7754.   pBaseBlock = ^baseBlock;
  7755.  
  7756. var
  7757.   treeRoot: pMRec;
  7758.   stepTag: tagPtr;
  7759.   hdrBlock: pBaseBlock;
  7760.  
  7761. exception goFNF;
  7762. exception badGoWrite;
  7763. exception badFileVersion;
  7764.  
  7765. procedure initGoTree;
  7766. procedure makeGoTree;
  7767. procedure readTree(nam: string);
  7768. procedure writeTree(nam: string; lm: pMRec);
  7769. function newMove(cm: pMRec): pMRec;
  7770. function delBranch(pm: pMRec): pMRec;
  7771. function hasAlts(pm: pMRec): boolean;
  7772. function isBranch(pm: pMRec): boolean;
  7773. function hasBranch(pm: pMRec): boolean;
  7774. function mergeMove(cm: pMRec): pMRec;
  7775. procedure tagMove(cm: pMRec; ts: tagStr);
  7776. function tagExists(ts: tagStr): boolean;
  7777. procedure commentMove(cm: pMRec; cs: string);
  7778. function getComment(cm: pMRec; var cs: string): boolean;
  7779. function getTag(cm: pMRec; var ts: string): boolean;
  7780. procedure delTag(tp: tagPtr);
  7781. procedure getFNameString(var fs: string);
  7782.  
  7783. private
  7784.  
  7785. imports fileSystem from fileSystem;
  7786. imports memory from memory;
  7787. imports perq_string from perq_string;
  7788. imports clock from clock;
  7789.  
  7790. const
  7791.   curFileVersion = 1;
  7792.   minTreeSize = 20;
  7793.   minTagSize = 4;
  7794.   minCmtSize = 4;
  7795.   maxTreeSize = 255;
  7796.   maxTagSize = 64;
  7797.   maxCmtSize = 128;
  7798.   treeSegInc = 8;
  7799.   tagSegInc = 4;
  7800.   cmtSegInc = 4;
  7801.  
  7802. type
  7803.   caType = packed array[0..1] of char;
  7804.   pCmtArray = ^caType;
  7805.  
  7806. var
  7807.   mFID: FileID;
  7808.   treeSeg, tagSeg, cmtSeg: integer;
  7809.   trSegSize, tagSegSize, cmtSegSize: integer;
  7810.   cmtArray: pCmtArray;
  7811.   cmtCmpArray: array[1..1024] of pMRec;
  7812.  
  7813. procedure getFNameString(var fs: string);
  7814. var
  7815.   ts: string;
  7816. begin  { getFNameString }
  7817.   fs := gameFName;
  7818.   if fs <> '' then
  7819.     begin
  7820.       stampToString(hdrBlock^.created, ts);
  7821.       fs := concat(fs, '  ');
  7822.       fs := concat(fs, ts);
  7823.     end;
  7824. end { getFNameString };
  7825.  
  7826. function isBranch(pm: pMRec): boolean;
  7827. begin { isBranch }
  7828.   repeat
  7829.     if pm = treeRoot then
  7830.       begin
  7831.         isBranch := false;
  7832.         exit(isBranch);
  7833.       end;
  7834.     pm := pm^.blink;
  7835.   until pm^.flink^.slink <> nil;
  7836.   isBranch := true;
  7837. end { isBranch };
  7838.  
  7839. function hasBranch(pm: pMRec): boolean;
  7840. begin { hasBranch }
  7841.   while pm^.flink <> nil do
  7842.     if pm^.flink^.slink <> nil then
  7843.       begin
  7844.         hasBranch := true;
  7845.         exit(hasBranch);
  7846.       end
  7847.     else
  7848.       pm := pm^.flink;
  7849.   hasBranch := false;
  7850. end { hasBranch };
  7851.  
  7852. procedure initSegs(trSize, tagSize, cmtSize: integer);
  7853. begin { initSegs }
  7854.   if treeSeg <> -1 then
  7855.     begin
  7856.       changeSize(treeSeg, trSize);
  7857.       changeSize(tagSeg, tagSize);
  7858.       changeSize(cmtSeg, cmtSize);
  7859.     end
  7860.   else
  7861.     begin
  7862.       createSegment(treeSeg, trSize, treeSegInc, maxTreeSize);
  7863.       createSegment(tagSeg, tagSize, tagSegInc, maxTagSize);
  7864.       createSegment(cmtSeg, cmtSize, cmtSegInc, maxCmtSize);
  7865.     end;
  7866.   trSegSize := trSize;
  7867.   tagSegSize := tagSize;
  7868.   cmtSegSize := cmtSize;
  7869. end { initSegs };
  7870.  
  7871. procedure initHdrBlock;
  7872. begin { initHdrBlock }
  7873.   with hdrBlock^ do
  7874.     begin
  7875.       oldTest := nil;
  7876.       fileVersion := curFileVersion;
  7877.       getTStamp(created);
  7878.       rootComment := '';
  7879.     end;
  7880. end { initHdrBlock };
  7881.  
  7882. procedure makeGoTree;
  7883. begin { makeGoTree }
  7884.   initSegs(minTreeSize, minTagSize, minCmtSize);
  7885.   initHdrBlock;
  7886.   treeRoot := makePtr(treeSeg, 0, pMRec);
  7887.   with treeRoot^ do
  7888.     begin
  7889.       id := header;
  7890.       freePool := nil;
  7891.       flink := nil;
  7892.       lastTag := nil;
  7893.       nextMRec := wordSize(moveRec);
  7894.       nextMBlock := minTreeSize * 256;
  7895.       nextTRec := 0;
  7896.       nextTBlock := minTagSize * 256;
  7897.       nextCIdx := 0;
  7898.       nextCBlock := minCmtSize * 512;
  7899.       freeTags := nil;
  7900.     end;
  7901.   cmtArray := makePtr(cmtSeg, 0, pCmtArray);
  7902.   stepTag := nil;
  7903. end { makeGoTree };
  7904.  
  7905. procedure readTree(nam: string);
  7906. type
  7907.    ptrHack = record
  7908.                case integer of
  7909.                  0: (p: pMRec);
  7910.                  1: (pt: tagPtr);
  7911.                  2: (po: integer;
  7912.                      ps: integer);
  7913.              end;
  7914. var
  7915.   size, gbg, i, b: integer;
  7916.   pd: pDirBlk;
  7917.   ph: ptrHack;
  7918.   pm: pMRec;
  7919.   tm: tagPtr;
  7920.   mBlks, tBlks, cBlks: integer;
  7921. begin { readTree }
  7922.   initSegs(minTreeSize, minTagSize, minCmtSize);
  7923.   mFID := FSLookup(nam, size, gbg);
  7924.   if mFID = 0 then
  7925.     raise goFNF;
  7926.   FSBlkRead(mFID, 0, recast(hdrBlock, pDirBlk));
  7927.   if hdrBlock^.oldTest <> nil then
  7928.     begin
  7929.       initHdrBlock;
  7930.       b := 0;
  7931.     end
  7932.   else if hdrBlock^.fileVersion <> curFileVersion then
  7933.     begin
  7934.       makeGoTree;
  7935.       raise badFileVersion;
  7936.     end
  7937.   else
  7938.     b := 1;
  7939.   pd := makePtr(treeSeg, 0, pDirBlk);
  7940.   FSBlkRead(mFID, b, pd);
  7941.   b := b + 1;
  7942.   treeRoot := makePtr(treeSeg, 0, pMRec);
  7943.   with treeRoot^ do
  7944.     begin
  7945.       mBlks := nextMBlock div 256;
  7946.       tBlks := nextTBlock div 256;
  7947.       cBlks := nextCBlock div 512;
  7948.     end;
  7949.   initSegs(mBlks, tBlks, cBlks);
  7950.   for i := 1 to mBlks - 1 do
  7951.     begin
  7952.       pd := makePtr(treeSeg, i * 256, pDirBlk);
  7953.       FSBlkRead(mFID, b, pd);
  7954.       b := b + 1;
  7955.     end;
  7956.   for i := 0 to tBlks - 1 do
  7957.     begin
  7958.       pd := makePtr(tagSeg, i * 256, pDirBlk);
  7959.       FSBlkRead(mFID, b, pd);
  7960.       b := b + 1;
  7961.     end;
  7962.   for i := 0 to cBlks - 1 do
  7963.     begin
  7964.       pd := makePtr(cmtSeg, i * 256, pDirBlk);
  7965.       FSBlkRead(mFID, b, pd);
  7966.       b := b + 1;
  7967.     end;
  7968.   with treeRoot^ do
  7969.     begin
  7970.       if freePool <> nil then
  7971.         begin
  7972.           ph.p := freePool;
  7973.           ph.ps := treeSeg;
  7974.           freePool := ph.p;
  7975.         end;
  7976.       if flink <> nil then
  7977.         begin
  7978.           ph.p := flink;
  7979.           ph.ps := treeSeg;
  7980.           flink := ph.p;
  7981.         end;
  7982.       if lastMove <> nil then
  7983.         begin
  7984.           ph.p := lastMove;
  7985.           ph.ps := treeSeg;
  7986.           lastMove := ph.p;
  7987.         end;
  7988.       if lastTag <> nil then
  7989.         begin
  7990.           ph.pt := lastTag;
  7991.           ph.ps := tagSeg;
  7992.           lastTag := ph.pt;
  7993.         end;
  7994.       if freeTags <> nil then
  7995.         begin
  7996.           ph.pt := freeTags;
  7997.           ph.ps := tagSeg;
  7998.           freeTags := ph.pt;
  7999.         end;
  8000.     end;
  8001.   i := wordSize(moveRec);
  8002.   while i < treeRoot^.nextMRec do
  8003.     begin
  8004.       pm := makePtr(treeSeg, i, pMRec);
  8005.       with pm^ do
  8006.         begin
  8007.           if flink <> nil then
  8008.             begin
  8009.               ph.p := flink;
  8010.               ph.ps := treeSeg;
  8011.               flink := ph.p;
  8012.             end;
  8013.           if blink <> nil then
  8014.             begin
  8015.               ph.p := blink;
  8016.               ph.ps := treeSeg;
  8017.               blink := ph.p;
  8018.             end;
  8019.           if slink <> nil then
  8020.             begin
  8021.               ph.p := slink;
  8022.               ph.ps := treeSeg;
  8023.               slink := ph.p;
  8024.             end;
  8025.           if tag <> nil then
  8026.             begin
  8027.               ph.pt := tag;
  8028.               ph.ps := tagSeg;
  8029.               tag := ph.pt;
  8030.             end;
  8031.         end;
  8032.       i := i + wordSize(moveRec);
  8033.     end;
  8034.   i := 0;
  8035.   while i < treeRoot^.nextTRec do
  8036.     begin
  8037.       tm := makePtr(tagSeg, i, tagPtr);
  8038.       with tm^ do
  8039.         begin
  8040.           if mPtr <> nil then
  8041.             begin
  8042.               ph.p := mPtr;
  8043.               ph.ps := treeSeg;
  8044.               mPtr := ph.p;
  8045.             end;
  8046.           if nextTag <> nil then
  8047.             begin
  8048.               ph.pt := nextTag;
  8049.               ph.ps := tagSeg;
  8050.               nextTag := ph.pt;
  8051.             end;
  8052.         end;
  8053.       i := i + wordSize(tagRec);
  8054.     end;
  8055.   stepTag := nil;
  8056. end { readTree };
  8057.  
  8058. procedure writeTree(nam: string; lm: pMRec);
  8059. var
  8060.   pd: pDirBlk;
  8061.   treeBlks, tagBlks, cmtBlks: integer;
  8062.   b, i: integer;
  8063.  
  8064.   procedure compressCmts;
  8065.   var
  8066.     numCmts: integer;
  8067.     cp: pMRec;
  8068.  
  8069.     procedure spanComments(m: pMRec);
  8070.     begin { spanComments }
  8071.       while m <> nil do
  8072.         begin
  8073.           if m^.cmtLen > 0 then
  8074.             begin
  8075.               numCmts := numCmts + 1;
  8076.               cmtCmpArray[numCmts] := m;
  8077.             end;
  8078.           spanComments(m^.slink);
  8079.           m := m^.flink;
  8080.         end;
  8081.     end { spanComments };
  8082.  
  8083.     procedure sortComments;
  8084.     var
  8085.       i, j: integer;
  8086.       t: pMRec;
  8087.     begin { sortComments }
  8088.       for i := 1 to numCmts - 1 do
  8089.         for j := i + 1 to numCmts do
  8090.           if cmtCmpArray[i]^.cmtBase > cmtCmpArray[j]^.cmtBase then
  8091.             begin
  8092.               t := cmtCmpArray[i];
  8093.               cmtCmpArray[i] := cmtCmpArray[j];
  8094.               cmtCmpArray[j] := t;
  8095.             end;
  8096.     end { sortComments };
  8097.  
  8098.     procedure squeezeComments;
  8099.     var
  8100.       i, j, cgi, lastCB: integer;
  8101.       mp: pMRec;
  8102.     begin { squeezeComments }
  8103.       lastCB := 0;
  8104.       for i := 1 to numCmts do
  8105.         begin
  8106.           if cmtCmpArray[i]^.cmtBase > lastCB then
  8107.             begin
  8108.               cgi := cmtCmpArray[i]^.cmtBase;
  8109.               for j := 0 to cmtCmpArray[i]^.cmtLen - 1 do
  8110.                 begin
  8111.     {$R-}
  8112.                   cmtArray^[lastCB + j] := cmtArray^[cgi + j];
  8113.     {$R=}
  8114.                 end;
  8115.               cmtCmpArray[i]^.cmtBase := lastCB;
  8116.             end;
  8117.           lastCB := cmtCmpArray[i]^.cmtBase + cmtCmpArray[i]^.cmtLen;
  8118.         end;
  8119.       treeRoot^.nextCIdx := lastCB;
  8120.     end { squeezeComments };
  8121.  
  8122.   begin { compressCmts }
  8123.     numCmts := 0;
  8124.     cp := treeRoot^.flink;
  8125.     if cp <> nil then
  8126.       begin
  8127.         spanComments(cp);
  8128.         sortComments;
  8129.         squeezeComments;
  8130.       end;
  8131.   end { compressCmts };
  8132.  
  8133. begin { writeTree }
  8134.   mFID := FSEnter(nam);
  8135.   if mFID = 0 then
  8136.     raise badGoWrite
  8137.   else
  8138.     begin
  8139.       compressCmts;
  8140.       with treeRoot^ do
  8141.         begin
  8142.           lastMove := lm;
  8143.           treeBlks := nextMBlock div 256;
  8144.           tagBlks := nextTBlock div 256;
  8145.           cmtBlks := nextCBlock div 512;
  8146.         end;
  8147.       FSBlkWrite(mFID, 0, recast(hdrBlock, pDirBlk));
  8148.       b := 1;
  8149.       for i := 0 to treeBlks - 1 do
  8150.         begin
  8151.           pd := makePtr(treeSeg, i * 256, pDirBlk);
  8152.           FSBlkWrite(mFID, b, pd);
  8153.           b := b + 1;
  8154.         end;
  8155.       for i := 0 to tagBlks - 1 do
  8156.         begin
  8157.           pd := makePtr(tagSeg, i * 256, pDirBlk);
  8158.           FSBlkWrite(mFID, b, pd);
  8159.           b := b + 1;
  8160.         end;
  8161.       for i := 0 to cmtBlks - 1 do
  8162.         begin
  8163.           pd := makePtr(cmtSeg, i * 256, pDirBlk);
  8164.           FSBlkWrite(mFID, b, pd);
  8165.           b := b + 1;
  8166.         end;
  8167.       FSClose(mFID, treeBlks + tagBlks + cmtBlks, 4096);
  8168.     end;
  8169. end { writeTree };
  8170.  
  8171. function newMove(cm: pMRec): pMRec;
  8172. var
  8173.   pm: pMRec;
  8174. begin { newMove }
  8175.   with treeRoot^ do
  8176.     if freePool <> nil then
  8177.       begin
  8178.         pm := freePool;
  8179.         freePool := pm^.flink;
  8180.       end
  8181.     else
  8182.       begin
  8183.         if nextMRec + wordSize(moveRec) > nextMBlock then
  8184.           begin
  8185.             trSegSize := trSegSize + treeSegInc;
  8186.             changeSize(treeSeg, trSegSize);
  8187.             nextMBlock := nextMBlock + (treeSegInc * 256);
  8188.           end;
  8189.         pm := makePtr(treeSeg, nextMRec, pMRec);
  8190.         nextMRec := nextMRec + wordSize(moveRec);
  8191.       end;
  8192.   with pm^ do
  8193.     begin
  8194.       flink := nil;
  8195.       blink := cm;
  8196.       slink := nil;
  8197.       tag := nil;
  8198.       cmtLen := 0;
  8199.     end;
  8200.   if cm^.flink <> nil then
  8201.     pm^.slink := cm^.flink;
  8202.   cm^.flink := pm;
  8203.   newMove := pm;
  8204. end { newMove };
  8205.  
  8206. procedure tagMove(cm: pMRec; ts: tagStr);
  8207. var
  8208.   tp: tagPtr;
  8209. begin { tagMove }
  8210.   if cm^.tag <> nil then
  8211.     cm^.tag^.sTag := ts
  8212.   else
  8213.     with treeRoot^ do
  8214.       begin
  8215.         if freeTags <> nil then
  8216.           begin
  8217.             tp := freeTags;
  8218.             freeTags := tp^.nextTag;
  8219.           end
  8220.         else
  8221.           begin
  8222.             if nextTRec + wordSize(tagRec) > nextTBlock then
  8223.               begin
  8224.                 tagSegSize := tagSegSize + tagSegInc;
  8225.                 changeSize(tagSeg, tagSegSize);
  8226.                 nextTBlock := nextTBlock + (tagSegInc * 256);
  8227.               end;
  8228.             tp := makePtr(tagSeg, nextTRec, tagPtr);
  8229.             nextTRec := nextTRec + wordSize(tagRec);
  8230.           end;
  8231.         cm^.tag := tp;
  8232.         with tp^ do
  8233.           begin
  8234.             mPtr := cm;
  8235.             nextTag := lastTag;
  8236.             sTag := ts;
  8237.           end;
  8238.         lastTag := tp;
  8239.       end;
  8240.   treeDirty := true;
  8241. end { tagMove };
  8242.  
  8243. function tagExists(ts: tagStr): boolean;
  8244. var
  8245.   tp: tagPtr;
  8246.  
  8247.   function upCmp(s1, s2: pString): boolean;
  8248.   begin { upCmp }
  8249.     convUpper(s1);
  8250.     convUpper(s2);
  8251.     upCmp := s1 = s2;
  8252.   end { upCmp };
  8253.  
  8254. begin { tagExists }
  8255.   tp := treeRoot^.lastTag;
  8256.   while tp <> nil do
  8257.     if upCmp(tp^.sTag, ts) then
  8258.       begin
  8259.         tagExists := true;
  8260.         exit(tagExists);
  8261.       end
  8262.     else
  8263.       tp := tp^.nextTag;
  8264.   tagExists := false;
  8265. end { tagExists };
  8266.  
  8267. procedure commentMove(cm: pMRec; cs: string);
  8268. var
  8269.   sl, i: integer;
  8270. begin { commentMove }
  8271.   if cm = treeRoot then
  8272.     hdrBlock^.rootComment := cs
  8273.   else
  8274.     begin
  8275.       sl := length(cs);
  8276.       with cm^ do
  8277.         begin
  8278.           cmtLen := sl;
  8279.           if sl > 0 then
  8280.             begin
  8281.               cmtBase := treeRoot^.nextCIdx;
  8282.               treeRoot^.nextCIdx := cmtBase + sl;
  8283.               if cmtBase + cmtLen > treeRoot^.nextCBlock then
  8284.                 with treeRoot^ do
  8285.                   begin
  8286.                     cmtSegSize := cmtSegSize + cmtSegInc;
  8287.                     changeSize(cmtSeg, cmtSegSize);
  8288.                     nextCBlock := nextCBlock + (cmtSegInc * 512);
  8289.                   end;
  8290.               for i := 0 to sl - 1 do
  8291.                 begin
  8292. {$R-}
  8293.                   cmtArray^[cmtBase + i] := cs[i + 1];
  8294. {$R=}
  8295.                 end;
  8296.             end;
  8297.         end;
  8298.     end;
  8299.   treeDirty := true;
  8300. end { commentMove };
  8301.  
  8302. function getComment(cm: pMRec; var cs: string): boolean;
  8303. var
  8304.   i: integer;
  8305. begin { getComment }
  8306.   if cm = treeRoot then
  8307.     begin
  8308.       cs := hdrBlock^.rootComment;
  8309.       getComment := cs <> '';
  8310.     end
  8311.   else if cm^.cmtLen = 0 then
  8312.     getComment := false
  8313.   else
  8314.     with cm^ do
  8315.       begin
  8316.         getComment := true;
  8317.         adjust(cs, cmtLen);
  8318.         for i := 1 to cmtLen do
  8319.           begin
  8320. {$R-}
  8321.             cs[i] := cmtArray^[cmtBase + i - 1];
  8322. {$R=}
  8323.           end;
  8324.       end;
  8325. end { getComment };
  8326.  
  8327. function getTag(cm: pMRec; var ts: string): boolean;
  8328. begin { getTag }
  8329.   if cm = treeRoot then
  8330.     getTag := false
  8331.   else if cm^.tag = nil then
  8332.     getTag := false
  8333.   else
  8334.     begin
  8335.       ts := cm^.tag^.sTag;
  8336.       getTag := true;
  8337.     end;
  8338. end { getTag };
  8339.  
  8340. procedure delTag(tp: tagPtr);
  8341. var
  8342.   ttp: tagPtr;
  8343. begin { delTag }
  8344.   tp^.mPtr^.tag := nil;
  8345.   tp^.mPtr := nil;
  8346.   if stepTag = tp then
  8347.     stepTag := nil;
  8348.   ttp := treeRoot^.lastTag;
  8349.   if ttp = tp then
  8350.     treeRoot^.lastTag := tp^.nextTag
  8351.   else
  8352.     begin
  8353.       while ttp^.nextTag <> tp do
  8354.         ttp := ttp^.nextTag;
  8355.       ttp^.nextTag := tp^.nextTag;
  8356.     end;
  8357.   tp^.nextTag := treeRoot^.freeTags;
  8358.   treeRoot^.freeTags := tp;
  8359. end { delTag };
  8360.  
  8361. function delBranch(pm: pMRec): pMRec;
  8362. var
  8363.   sm: pMRec;
  8364.  
  8365.   procedure recDel(m: pMRec);
  8366.   var
  8367.     tp: tagPtr;
  8368.   begin { recDel }
  8369.     if m <> nil then
  8370.       begin
  8371.         recDel(m^.slink);
  8372.         recDel(m^.flink);
  8373.         m^.blink := nil;
  8374.         m^.slink := nil;
  8375.         m^.flink := treeRoot^.freePool;
  8376.         treeRoot^.freePool := m;
  8377.         if m^.tag <> nil then
  8378.           delTag(m^.tag);
  8379.       end;
  8380.   end { recDel };
  8381.  
  8382. begin { delBranch }
  8383.   if pm = treeRoot then
  8384.     exit(delBranch);
  8385.   while pm^.id = remove do
  8386.     pm := pm^.blink;
  8387.   if pm^.blink^.flink = pm then
  8388.     pm^.blink^.flink := pm^.slink
  8389.   else
  8390.     begin
  8391.       sm := pm^.blink^.flink;
  8392.       while sm^.slink <> pm do
  8393.         sm := sm^.slink;
  8394.       sm^.slink := pm^.slink;
  8395.     end;
  8396.   pm^.slink := nil;
  8397.   delBranch := pm^.blink;
  8398.   pm^.blink := nil;
  8399.   recDel(pm);
  8400. end { delBranch };
  8401.  
  8402. procedure delNode(pm: pMRec);
  8403. var
  8404.   sm: pMRec;
  8405. begin { delNode }
  8406.   if pm = treeRoot then
  8407.     exit(delNode);
  8408.   if pm^.blink^.flink = pm then
  8409.     pm^.blink^.flink := pm^.slink
  8410.   else
  8411.     begin
  8412.       sm := pm^.blink^.flink;
  8413.       while sm^.slink <> pm do
  8414.         sm := sm^.slink;
  8415.       sm^.slink := pm^.slink;
  8416.     end;
  8417.   pm^.blink := nil;
  8418.   pm^.slink := nil;
  8419.   pm^.flink := treeRoot^.freePool;
  8420.   treeRoot^.freePool := pm;
  8421. end { delNode };
  8422.  
  8423. function mergeMove(cm: pMRec): pMRec;
  8424. var
  8425.   tm: pMRec;
  8426. begin { mergeMove }
  8427.   tm := cm^.blink^.flink;
  8428.   mergeMove := cm;
  8429.   while tm <> nil do
  8430.     begin
  8431.       if tm <> cm then
  8432.         with tm^ do
  8433.           if id = cm^.id then
  8434.             if id = hcPlay then
  8435.               begin
  8436.                 mergeMove := tm;
  8437.                 delNode(cm);
  8438.                 exit(mergeMove);
  8439.               end            
  8440.             else if id = pass then
  8441.               begin
  8442.                 if who = cm^.who then
  8443.                   begin
  8444.                     mergeMove := tm;
  8445.                     delNode(cm);
  8446.                     exit(mergeMove);
  8447.                   end;
  8448.               end
  8449.             else if (mx = cm^.mx) and
  8450.                (my = cm^.my) and
  8451.                (who = cm^.who) then
  8452.               begin
  8453.                 mergeMove := tm;
  8454.                 delNode(cm);
  8455.                 exit(mergeMove);
  8456.               end;
  8457.       tm := tm^.slink;
  8458.     end;
  8459.   treeDirty := true;
  8460. end { mergeMove };
  8461.  
  8462. function hasAlts(pm: pMRec): boolean;
  8463. begin { hasAlts }
  8464.   while pm^.id = remove do
  8465.     pm := pm^.blink;
  8466.   hasAlts := pm^.blink^.flink^.slink <> nil;
  8467. end { hasAlts };
  8468.  
  8469. procedure initGoTree;
  8470. begin { initGoTree }
  8471.   treeSeg := -1;
  8472.   new(0, 256, hdrBlock);
  8473. end. { initGoTree }
  8474. SHAR_EOF
  8475. fi
  8476. exit 0
  8477. #    End of shell archive
  8478.