home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gchsrc31.lzh / INTERACT.CC < prev    next >
C/C++ Source or Header  |  1992-04-27  |  26KB  |  1,255 lines

  1. /* interact.cc - Interactive component of CHESS
  2.         (parent module of *ui.cc modules)
  3.  
  4.     This file was extracted from the original GNU Chess file nuxui.c
  5.     and converted to C++ by Warwick Allison.  It is a the generic portion
  6.     of the user interface.
  7.  
  8.     Revision: 1990-05-09
  9.  
  10.     Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc.
  11.     Copyright (c) 1988, 1989, 1990    John Stanback
  12.  
  13.     Modified extensively Nov 1989 Christopher North-Keys
  14.         40x24 two-colour display
  15.                 option for shading black squares
  16.                 expanded game save, list, and restore features using $HOME
  17.                 option to disable display of coordinates
  18.                 optional auto-updating of positional information
  19.                 optional starring of black side
  20.                 mass toggle for reverse-video functions
  21.  
  22.     This file is part of CHESS.
  23.  
  24.     CHESS is distributed in the hope that it will be useful, but WITHOUT ANY
  25.     WARRANTY.    No author or distributor accepts responsibility to anyone for
  26.     the consequences of using it or for whether it serves any particular
  27.     purpose or works at all, unless he says so in writing.    Refer to the CHESS
  28.     General Public License for full details.
  29.  
  30.     Everyone is granted permission to copy, modify and redistribute CHESS, but
  31.     only under the conditions described in the CHESS General Public License.
  32.     A copy of this license is supposed to have been given to you along with
  33.     CHESS so you can know your rights and responsibilities.    It should be in a
  34.     file named COPYING.    Among other things, the copyright notice and this
  35.     notice must be preserved on all copies.
  36. */
  37.  
  38.  
  39. #include <ctype.h>
  40. #include <signal.h>
  41. #include <stdlib.h>
  42. #include <time.h>
  43. #ifdef MSDOS
  44. #include <dos.h>
  45. #include <conio.h>
  46. #include <string.h>
  47. #else
  48. #include <sys/param.h>
  49. #include <sys/types.h>
  50. #include <sys/file.h>
  51. #include <curses.h>
  52. #undef bool // curses.h defines it to char...
  53. #undef TRUE
  54. #undef FALSE
  55. #endif /* MSDOS */
  56.  
  57. #include "gnuchess.h"
  58. #include "ui.h"
  59.  
  60. #define pxx " PNBRQK"
  61. #define qxx " pnbrqk"
  62. #define rxx "12345678"
  63. #define cxx "abcdefgh"
  64.  
  65. /* coordinates within a square for the following are ([1,5],[1,3]) */
  66. #define VIR_C(s)    ((flag.reverse) ? 7-column(s) : column(s))
  67. #define VIR_R(s)    ((flag.reverse) ? 7-row(s) : row(s))
  68. #define Vblack(s) (!((VIR_C(s) + VIR_R(s)) % 2))
  69.  
  70. static char mvstr[4][6];
  71. static long evrate;
  72. short PositionFlag = 0;
  73. short coords = 1;
  74.  
  75. void TerminateSearch (int), Die (int);
  76.  
  77. void
  78. Initialize (void)
  79. {
  80.     signal (SIGINT, Die);
  81. #ifndef MSDOS
  82.     signal (SIGQUIT, Die);
  83. #endif
  84.     ui_Initialize();
  85. }
  86.  
  87. void
  88. ExitChess (void)
  89. {
  90.     //ListGame ();
  91.     ui_Finalize();
  92.     exit (0);
  93. }
  94.  
  95. void
  96. Die (int Sig)
  97. {
  98.     signal (SIGINT, SIG_IGN);
  99. #ifdef MSDOS
  100.     Sig++;                                                                /* shut up the compiler */
  101. #else
  102.     signal (SIGQUIT, SIG_IGN);
  103. #endif /* MSDOS */
  104.     if (ui_AskAbort())
  105.         ExitChess ();
  106.     signal (SIGINT, Die);
  107. #ifndef MSDOS
  108.     signal (SIGQUIT, Die);
  109. #endif /* MSDOS */
  110. }
  111.  
  112. void
  113. TerminateSearch (int Sig)
  114. {
  115.     signal (SIGINT, SIG_IGN);
  116. #ifdef MSDOS
  117.     Sig++;                                                                /* shut up the compiler */
  118. #else
  119.     signal (SIGQUIT, SIG_IGN);
  120. #endif /* MSDOS */
  121.     flag.timeout = true;
  122.     flag.bothsides = false;
  123.     signal (SIGINT, Die);
  124. #ifndef MSDOS
  125.     signal (SIGQUIT, Die);
  126. #endif /* MSDOS */
  127. }
  128.  
  129. void
  130. algbr (short int f, short int t, short int flag)
  131.  
  132. /*
  133.      Generate move strings in different formats.
  134. */
  135.  
  136. {
  137.     int m3p;
  138.  
  139.     if (f != t)
  140.         {
  141.             /* algebraic notation */
  142.             mvstr[0][0] = cxx[column (f)];
  143.             mvstr[0][1] = rxx[row (f)];
  144.             mvstr[0][2] = cxx[column (t)];
  145.             mvstr[0][3] = rxx[row (t)];
  146.             mvstr[0][4] = mvstr[3][0] = '\0';
  147.             if ((mvstr[1][0] = pxx[board[f]]) == 'P')
  148.                 {
  149.                     if (mvstr[0][0] == mvstr[0][2])                /* pawn did not eat */
  150.                         {
  151.                             mvstr[2][0] = mvstr[1][0] = mvstr[0][2];                /* to column */
  152.                             mvstr[2][1] = mvstr[1][1] = mvstr[0][3];                /* to row */
  153.                             m3p = 2;
  154.                         }
  155.                     else
  156.                         /* pawn ate */
  157.                         {
  158.                             mvstr[2][0] = mvstr[1][0] = mvstr[0][0];                /* from column */
  159.                             mvstr[2][1] = mvstr[1][1] = mvstr[0][2];                /* to column */
  160.                             mvstr[2][2] = mvstr[0][3];
  161.                             m3p = 3;                                /* to row */
  162.                         }
  163.                     mvstr[2][m3p] = mvstr[1][2] = '\0';
  164.                     if (flag & promote)
  165.                         {
  166.                             mvstr[0][4] = mvstr[1][2] = mvstr[2][m3p] = qxx[flag & pmask];
  167.                             mvstr[1][3] = mvstr[2][m3p + 1] = mvstr[0][5] = '\0';
  168.                         }
  169.                 }
  170.             else
  171.                 /* not a pawn */
  172.                 {
  173.                     mvstr[2][0] = mvstr[1][0];
  174.                     mvstr[2][1] = mvstr[0][1];
  175.                     mvstr[2][2] = mvstr[1][1] = mvstr[0][2];                /* to column */
  176.                     mvstr[2][3] = mvstr[1][2] = mvstr[0][3];                /* to row */
  177.                     mvstr[2][4] = mvstr[1][3] = '\0';
  178.                     strcpy (mvstr[3], mvstr[2]);
  179.                     mvstr[3][1] = mvstr[0][0];
  180.                     if (flag & cstlmask)
  181.                         {
  182.                             if (t > f)
  183.                                 {
  184.                                     strcpy (mvstr[1], "o-o");
  185.                                     strcpy (mvstr[2], "O-O");
  186.                                 }
  187.                             else
  188.                                 {
  189.                                     strcpy (mvstr[1], "o-o-o");
  190.                                     strcpy (mvstr[2], "O-O-O");
  191.                                 }
  192.                         }
  193.                 }
  194.         }
  195.     else
  196.         mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = '\0';
  197. }
  198.  
  199. int
  200. VerifyMove (char *s, short int iop, short unsigned int *mv)
  201.  
  202. /*
  203.      Compare the string 's' to the list of legal moves available for the
  204.      opponent. If a match is found, make the move on the board.
  205. */
  206.  
  207. {
  208.     static short pnt, tempb, tempc, tempsf, tempst, cnt;
  209.     static struct leaf xnode;
  210.     struct leaf *node;
  211.  
  212.     *mv = 0;
  213.     if (iop == 2) {
  214.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  215.         return (false);
  216.     }
  217.     cnt = 0;
  218.     MoveList (opponent, 2);
  219.     pnt = TrPnt[2];
  220.     while (pnt < TrPnt[3]) {
  221.         node = &Tree[pnt++];
  222.         algbr (node->f, node->t, (short) node->flags);
  223.         if (strcmp (s, mvstr[0]) == 0 || strcmp (s, mvstr[1]) == 0 ||
  224.                 strcmp (s, mvstr[2]) == 0 || strcmp (s, mvstr[3]) == 0) {
  225.             cnt++;
  226.             xnode = *node;
  227.         }
  228.     }
  229.     if (cnt == 1) {
  230.         MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
  231.         if (SqAtakd (PieceList[opponent][0], computer)) {
  232.             UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  233.             ShowMessage ("Illegal Move!");
  234.             return (false);
  235.         } else {
  236.             if (iop == 1)
  237.                 return (true);
  238.             UpdateDisplay (xnode.f, xnode.t, 0, (short) xnode.flags);
  239.             if ((board[xnode.t] == pawn)
  240.                     || (xnode.flags & capture)
  241.                     || (xnode.flags & cstlmask)) {
  242.                 Game50 = GameCnt;
  243.                 ZeroRPT ();
  244.             }
  245.             GameList[GameCnt].depth = GameList[GameCnt].score = 0;
  246.             GameList[GameCnt].nodes = 0;
  247.             ElapsedTime (1);
  248.             GameList[GameCnt].time = (short) et;
  249.             TimeControl.clock[opponent] -= et;
  250.             --TimeControl.moves[opponent];
  251.             *mv = (xnode.f << 8) | xnode.t;
  252.             algbr (xnode.f, xnode.t, false);
  253.             return (true);
  254.         }
  255.     }
  256.     if (cnt > 1) {
  257.         ShowMessage ("Ambiguous Move!");
  258.     }
  259.     return (false);
  260. }
  261.  
  262. void
  263. help (void)
  264. {
  265.     ui_GiveHelp(computer,Level,flag.easy,MaxSearchDepth,dither,flag.hash);
  266. }
  267.  
  268. void
  269. EditBoard (void)
  270.  
  271. /*
  272.     Set up a board position. Pieces are entered by typing the piece
  273.     followed by the location. For example, Nf3 will place a knight on
  274.     square f3.
  275. */
  276.  
  277. {
  278.     short a, r, c, sq, i;
  279.     char s[80];
  280.  
  281.     ui_ShowEditHelp();
  282.     a = white;
  283.     do
  284.         {
  285.             ui_ShowEditColor(a);
  286.             ui_GetPieceAndLocation(s);
  287.             if (s[0] == '#')
  288.                 {
  289.                     for(sq = 0; sq < 64; sq++)
  290.                         {
  291.                             board[sq] = no_piece;
  292.                             color[sq] = neutral;
  293.                             DrawPiece (sq);
  294.                         }
  295.                 }
  296.             if (s[0] == 'c' || s[0] == 'C')
  297.                 a = otherside[a];
  298.             c = s[1] - 'a';
  299.             r = s[2] - '1';
  300.             if ((c >= 0) && (c < 8) && (r >= 0) && (r < 8))
  301.                 {
  302.                     sq = locn (r, c);
  303.                     for (i = king; i > no_piece; i--)
  304.                         if ((s[0] == pxx[i]) || (s[0] == qxx[i]))
  305.                             break;
  306.                     board[sq] = i;
  307.                     color[sq] = (board[sq] == no_piece) ? neutral : a;        
  308.                     DrawPiece (sq);
  309.                 }
  310.     } while (s[0] != '.');
  311.  
  312.     for (sq = 0; sq < 64; sq++)
  313.         Mvboard[sq] = (board[sq] != Stboard[sq]) ? 10 : 0;
  314.     GameCnt = 0;
  315.     Game50 = 1;
  316.     ZeroRPT ();
  317.     Sdepth = 0;
  318.     InitializeStats ();
  319.     ui_ClearEditHelp();
  320.     UpdateDisplay (0, 0, 1, 0);
  321. }
  322.  
  323.  
  324.  
  325.  
  326. void
  327. ShowPlayers (void)
  328. {            
  329.     ui_ShowPlayers(flag.reverse,computer==black);
  330. }
  331.  
  332.  
  333. void
  334. ShowDepth (char ch)
  335. {
  336.     ui_ShowDepth(Sdepth,ch);
  337.     ui_RefreshEarly();
  338. }
  339.  
  340.  
  341. void
  342. ShowScore (short score)
  343. {
  344.     ui_ShowScore(score);
  345. }
  346.  
  347.  
  348. void
  349. ShowMessage (char *s)
  350. {
  351.     ui_ShowMessage(s);
  352. }
  353.  
  354.  
  355. void
  356. ClearMessage (void)
  357. {
  358.     ui_ClearMessage();
  359. }
  360.  
  361.  
  362. void
  363. ShowCurrentMove (short int pnt, short int f, short int t)
  364. {
  365.     algbr (f, t, false);
  366.     ui_ShowCurrentMove(pnt,mvstr[0]);
  367. }
  368.  
  369.  
  370. void
  371. ShowHeader (void)
  372. {
  373.     ui_ShowTitle();
  374. }
  375.  
  376.  
  377. void
  378. ShowSidetomove (void)
  379. {
  380.     ui_ShowSideToMove(1+GameCnt/2,player);
  381. }
  382.  
  383.  
  384. void
  385. ShowPrompt (void)
  386. {
  387.     ui_PromptForMove();
  388. }
  389.  
  390.  
  391. void
  392. ShowNodeCnt (long int NodeCnt, long int evrate)
  393. {            
  394.     ui_ShowNodeCnt(NodeCnt,evrate);
  395. }
  396.  
  397.  
  398. void
  399. ShowResults (short int score, short unsigned int *bstline, char ch)
  400. {
  401.     unsigned char d, ply;
  402.     if (flag.post)
  403.         {
  404.             ShowDepth (ch);
  405.             ShowScore (score);
  406.             d = 7;
  407.             for (ply = 1; bstline[ply] > 0; ply++)
  408.                 {
  409.                     algbr ((short) bstline[ply] >> 8, (short) bstline[ply] & 0xFF, false);
  410.                     ui_ShowPlyMove(ply,mvstr[0]);
  411.                 }
  412.             ui_NoMorePly(ply);
  413.         }
  414. }
  415.  
  416.  
  417.  
  418. void
  419. SearchStartStuff (short int side)
  420. {
  421.     ui_SearchStartStuff(side);
  422. }
  423.  
  424.  
  425. void
  426. OutputMove (void)
  427. {
  428.     int i;
  429.  
  430.     if (root->flags & draw)
  431.         i=1;
  432.     else if (root->score == -9999)
  433.         i=2;
  434.     else if (root->score == 9998)
  435.         i=3;
  436.     else if (root->score < -9000)
  437.         i=4;
  438.     else if (root->score > 9000)
  439.         i=5;
  440.     else
  441.         i=0;
  442.  
  443.     ui_ShowComputerMove(mvstr[0],i);
  444.  
  445.     UpdateDisplay (root->f, root->t, 0, (short) root->flags);
  446.  
  447.     if (flag.post)
  448.         {
  449.             ShowNodeCnt (NodeCnt, evrate);
  450.             for (i = 1999; i >= 0 && Tree[i].f == 0 && Tree[i].t == 0; i--);
  451.             ui_ShowMaxTree(i);
  452.         }
  453. }
  454.  
  455.  
  456.  
  457. void
  458. ElapsedTime (short int iop)
  459.  
  460. /*
  461.     Determine the time that has passed since the search was started. If
  462.     the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
  463.     timeout to true which will terminate the search.
  464. */
  465.  
  466. {
  467.     et = time ((long *) 0) - time0;
  468.     if (et < 0)
  469.         et = 0;
  470.     ETnodes += 50;
  471.     if (et > et0 || iop == 1)
  472.         {
  473.             if (et > ResponseTime + ExtraTime && Sdepth > 1)
  474.                 flag.timeout = true;
  475.             et0 = et;
  476.             if (iop == 1)
  477.                 {
  478.                     time0 = time ((long *) 0);
  479.                     et0 = 0;
  480.                 }
  481.             if (et > 0)
  482.                 /* evrate used to be Nodes / cputime I dont` know why */
  483.                 evrate = NodeCnt / (et + ft);
  484.             else
  485.                 evrate = 0;
  486.             ETnodes = NodeCnt + 50;
  487.             UpdateClocks ();
  488.         }
  489. }
  490.  
  491. void
  492. UpdateClocks (void)
  493. {
  494.     short m, s;
  495.     m = (short) (et / 60);
  496.     s = (short) (et - 60 * (long) m);
  497.     if (TCflag)
  498.         {
  499.             m = (short) ((TimeControl.clock[player] - et) / 60);
  500.             s = (short) (TimeControl.clock[player] - et - 60 * (long) m);
  501.         }
  502.     if (m < 0)
  503.         m = 0;
  504.     if (s < 0)
  505.         s = 0;
  506.  
  507.     ui_ShowClock(flag.reverse ^ (player==white),m,s);
  508.     if (flag.post)
  509.         ShowNodeCnt (NodeCnt, evrate);
  510.     /*refresh ();*/
  511. }
  512.  
  513.  
  514. void
  515. SetTimeControl (void)
  516. {
  517.     if (TCflag)
  518.         {
  519.             TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
  520.             TimeControl.clock[white] = TimeControl.clock[black] = 60 * (long) TCminutes;
  521.         }
  522.     else
  523.         {
  524.             TimeControl.moves[white] = TimeControl.moves[black] = 0;
  525.             TimeControl.clock[white] = TimeControl.clock[black] = 0;
  526.             Level = 60 * (long) TCminutes;
  527.         }
  528.     et = 0;
  529.     ElapsedTime (1);
  530. }
  531.  
  532. void
  533. DrawPiece (short int sq)
  534. {
  535.     ui_DrawPiece(color[sq]!=neutral,color[sq]==black,VIR_C(sq),VIR_R(sq),board[sq]);
  536. }
  537.  
  538.  
  539. void
  540. DrawSquare (short int sq)
  541. {
  542.     ui_DrawSquare(VIR_C(sq),VIR_R(sq),Vblack(sq));
  543. }
  544.  
  545.  
  546. void
  547. DrawCoords (void)
  548. {
  549.     ui_DrawCoords();
  550. }
  551.  
  552.  
  553. void
  554. ShowPostnValue (short int sq)
  555.  
  556. /*
  557.     must have called ExaminePosition() first
  558. */
  559.          
  560. {
  561.     short score;
  562.     
  563.     ScorePosition (color[sq], &score);
  564.     ui_ShowPosnValue(sq,score);
  565. }
  566.  
  567.  
  568.  
  569. void
  570. ShowPostnValues (void)
  571. {
  572.     short sq, score;
  573.  
  574.     ExaminePosition ();
  575.     for (sq = 0; sq < 64; sq++)
  576.         ShowPostnValue (sq);
  577.     ScorePosition (opponent, &score);
  578.     ShowScore (score);
  579. }
  580.  
  581. void
  582. UpdateDisplay (short int f, short int t, short int redraw, short int isspec)
  583. {
  584.     short sq;
  585.     
  586.     if (redraw)
  587.         {
  588.             ShowHeader ();
  589.             ShowPlayers ();
  590.             for (sq = 0; sq < 64; sq++)
  591.                 {
  592.                     DrawSquare (sq);
  593.                     DrawPiece (sq);
  594.                 }
  595.             if (coords)
  596.                 DrawCoords ();
  597.         }
  598.     else
  599.         {
  600.             DrawPiece (f);
  601.             DrawPiece (t);
  602.             if (isspec & cstlmask)
  603.                 if (t > f)
  604.                     {
  605.                         DrawPiece (f + 3);
  606.                         DrawPiece (t - 1);
  607.                     }
  608.                 else
  609.                     {
  610.                         DrawPiece (f - 4);
  611.                         DrawPiece (t + 1);
  612.                     }
  613.             else if (isspec & epmask)
  614.                 {
  615.                     DrawPiece (t - 8);
  616.                     DrawPiece (t + 8);
  617.                 }
  618.         }
  619.     if (PositionFlag)
  620.         ShowPostnValues ();
  621.     /*refresh ();*/
  622. }
  623.  
  624. void
  625. GetGame (void)
  626. {
  627.     FILE *fd;
  628.     char fname[256], tname[256];
  629.     char *tmp;
  630.     int c;
  631.     short sq;
  632.     unsigned short m;
  633.  
  634.     tname[0] = 0;
  635.  
  636.     if (tmp = getenv ("HOME")) {
  637.         strcpy (fname, tmp);
  638. #ifdef atarist
  639.         strcat (fname, "\\");
  640. #else
  641.         strcat (fname, "/");
  642. #endif
  643.     } else {
  644.         fname[0] = '\0';
  645.     }
  646.  
  647.     ui_GetFilename("Load",tname);
  648.  
  649.     if (tname[0])
  650.         strcat (fname, tname);
  651.     else
  652.         strcat (fname, "chess.000");
  653.  
  654.     ui_ShowFileLoading(fname);
  655.  
  656.     if ((fd = fopen (fname, "r")) == NULL) {
  657.         ui_LoadFailed();
  658.         return;
  659.     }
  660.  
  661.     fscanf (fd, "%hd%hd%hd", &computer, &opponent, &Game50);
  662.     fscanf (fd, "%hd%hd", &castld[white], &castld[black]);
  663.     fscanf (fd, "%hd%hd", &TCflag, &OperatorTime);
  664.     fscanf (fd, "%ld%ld%hd%hd",
  665.                     &TimeControl.clock[white], &TimeControl.clock[black],
  666.                     &TimeControl.moves[white], &TimeControl.moves[black]);
  667.     for (sq = 0; sq < 64; sq++)
  668.         {
  669.             fscanf (fd, "%hd%hd", &m, &Mvboard[sq]);
  670.             board[sq] = (m >> 8);
  671.             color[sq] = (m & 0xFF);
  672.             if (color[sq] == 0)
  673.                 color[sq] = neutral;
  674.             else
  675.                 --color[sq];
  676.         }
  677.     GameCnt = 0;
  678.     c = '?';
  679.     while (c != EOF)
  680.         {
  681.             ++GameCnt;
  682.             c = fscanf (fd, "%hd%hd%hd%ld%hd%hd%hd", &GameList[GameCnt].gmove,
  683.                                     &GameList[GameCnt].score, &GameList[GameCnt].depth,
  684.                                     &GameList[GameCnt].nodes, &GameList[GameCnt].time,
  685.                                     &GameList[GameCnt].piece, &GameList[GameCnt].color);
  686.             if (GameList[GameCnt].color == 0)
  687.                 GameList[GameCnt].color = neutral;
  688.             else
  689.                 --GameList[GameCnt].color;
  690.         }
  691.     GameCnt--;
  692.     if (TimeControl.clock[white] > 0)
  693.         TCflag = true;
  694.     computer--;
  695.     opponent--;
  696.  
  697.     fclose (fd);
  698.  
  699.     InitializeStats ();
  700.     Sdepth = 0;
  701.     ui_LoadDone();
  702.     UpdateDisplay (0, 0, 1, 0);
  703. }
  704.  
  705.  
  706. void
  707. SaveGame (void)
  708. {
  709.     FILE *fd;
  710.     char fname[256], tname[256];
  711.     char *tmp;
  712.     short sq, i, c;
  713.  
  714.     tname[0] = 0;
  715.  
  716.     if (tmp = getenv ("HOME"))
  717.         strcpy (fname, tmp);
  718.     else
  719.         fname[0] = '\0';
  720.  
  721. #ifdef atarist
  722.     strcat (fname, "\\");
  723. #else
  724.     strcat (fname, "/");
  725. #endif
  726.  
  727.     ui_GetFilename("Save",tname);
  728.  
  729.     if (tname[0])
  730.         strcat (fname, tname);
  731.     else
  732.         strcat (fname, "chess.000");
  733.  
  734.     ui_ShowFileSaving(fname);
  735.  
  736.     if (NULL == (fd = fopen (fname, "w"))) {
  737.         ui_SaveFailed();
  738.         return;
  739.     }
  740.  
  741.     fprintf (fd, "%d %d %d\n", computer + 1, opponent + 1, Game50);
  742.     fprintf (fd, "%d %d\n", castld[white], castld[black]);
  743.     fprintf (fd, "%d %d\n", TCflag, OperatorTime);
  744.     fprintf (fd, "%ld %ld %d %d\n",
  745.                      TimeControl.clock[white], TimeControl.clock[black],
  746.                      TimeControl.moves[white], TimeControl.moves[black]);
  747.     for (sq = 0; sq < 64; sq++)
  748.         {
  749.             if (color[sq] == neutral)
  750.                 c = 0;
  751.             else
  752.                 c = color[sq] + 1;
  753.             fprintf (fd, "%d %d\n", 256 * board[sq] + c, Mvboard[sq]);
  754.         }
  755.     for (i = 1; i <= GameCnt; i++)
  756.         {
  757.             if (GameList[i].color == neutral)
  758.                 c = 0;
  759.             else
  760.                 c = GameList[i].color + 1;
  761.             fprintf (fd, "%d %d %d %ld %d %d %d\n",
  762.                              GameList[i].gmove, GameList[i].score, GameList[i].depth,
  763.                              GameList[i].nodes, GameList[i].time,
  764.                              GameList[i].piece, c);
  765.         }
  766.     fclose (fd);
  767.     ui_SaveDone();
  768. }
  769.  
  770.  
  771.  
  772.  
  773. void
  774. ListGame (void)
  775. {
  776.     FILE *fd;
  777.     char fname[256];
  778.     char *tmp;
  779.     short i, f, t;
  780.  
  781.     if (tmp = getenv ("HOME")) {
  782.         strcpy (fname, tmp);
  783. #ifdef atarist
  784.         strcat (fname, "\\");
  785. #else
  786.         strcat (fname, "/");
  787. #endif
  788.     } else {
  789.         fname[0] = '\0';
  790.     }
  791.     strcat (fname, "chess.lst");
  792.  
  793.     if (fd = fopen (fname, "w"))
  794.         ShowMessage ("Writing ~/chess.lst");
  795.     else {
  796.         ShowMessage ("Cannot write ~/chess.lst");
  797.         return;
  798.     }
  799.  
  800.     fprintf (fd, "\n");
  801.     fprintf (fd, "       score  depth   nodes  time         ");
  802.     fprintf (fd, "       score  depth   nodes  time\n");
  803.     for (i = 1; i <= GameCnt; i++) {
  804.         f = GameList[i].gmove >> 8;
  805.         t = (GameList[i].gmove & 0xFF);
  806.         algbr (f, t, false);
  807.         if ((i % 2) == 1)
  808.             fprintf (fd, "\n");
  809.         else
  810.             fprintf (fd, "         ");
  811.         fprintf (fd, "%5s  %5d     %2d %7ld %5d", mvstr[0],
  812.                      GameList[i].score, GameList[i].depth,
  813.                      GameList[i].nodes, GameList[i].time);
  814.     }
  815.     fprintf (fd, "\n\n");
  816.     fclose (fd);
  817.     ShowMessage ("~/chess.lst written");
  818. }
  819.  
  820. void
  821. Undo (void)
  822.  
  823. /*
  824.     Undo the most recent half-move.
  825. */
  826.  
  827. {
  828.     short f, t;
  829.     f = GameList[GameCnt].gmove >> 8;
  830.     t = GameList[GameCnt].gmove & 0xFF;
  831.     if (board[t] == king && distance (t, f) > 1)
  832.         (void) castle (GameList[GameCnt].color, f, t, 2);
  833.     else {
  834.         /* Check for promotion: */
  835.         if ((color[t] == white && row (f) == 6 && row (t) == 7)
  836.                 || (color[t] == black && row (f) == 1 && row (t) == 0))
  837.             {
  838.                 int g, from = f;
  839.                 for (g = GameCnt - 1; g > 0; g--)
  840.                     if (GameList[g].gmove & 0xFF == from)
  841.                         from = GameList[g].gmove >> 8;
  842.                 if ((color[t] == white && row (from) == 1)
  843.                         || (color[t] == black && row (from) == 6))
  844.                     board[t] = pawn;
  845.             }
  846.         board[f] = board[t];
  847.         color[f] = color[t];
  848.         board[t] = GameList[GameCnt].piece;
  849.         color[t] = GameList[GameCnt].color;
  850.         if (color[t] != neutral)
  851.             Mvboard[t]--;
  852.         Mvboard[f]--;
  853.     }
  854.     if (TCflag)
  855.         ++TimeControl.moves[color[f]];
  856.     GameCnt--;
  857.     computer = otherside[computer];
  858.     opponent = otherside[opponent];
  859.     flag.mate = false;
  860.     Sdepth = 0;
  861.     UpdateDisplay (0, 0, 1, 0);
  862.     InitializeStats ();
  863. }
  864.  
  865. /*
  866. void
  867. ChangeAlphaWindow (void)
  868. {
  869.     ShowMessage ("Awindow= ");
  870.     scanz ("%hd", &Awindow);
  871. }
  872.  
  873. void
  874. ChangeBetaWindow (void)
  875. {
  876.     ShowMessage ("Bwindow= ");
  877.     scanz ("%hd", &Bwindow);
  878. }
  879. */
  880.  
  881. void
  882. GiveHint (void)
  883. {
  884.     algbr ((short) (hint >> 8), (short) (hint & 0xFF), false);
  885.     ui_ShowHint(mvstr[0]);
  886. }
  887.  
  888. void
  889. ChangeSearchDepth (void)
  890. {
  891.     int msd;
  892.     ui_ChangeSearchDepth(&msd);
  893.     MaxSearchDepth=(short)msd;
  894. }
  895.  
  896.  
  897. void
  898. SetContempt (void)
  899. {
  900.     int c;
  901.     ui_ChangeContempt(&c);
  902.     contempt=(short)c;
  903. }
  904.  
  905.  
  906. /*
  907. void
  908. ChangeXwindow (void)
  909. {
  910.     ShowMessage ("xwndw= ");
  911.     scanz ("%hd", &xwndw);
  912. }
  913. */
  914.  
  915. void
  916. SelectLevel (void)
  917. {
  918.     OperatorTime = 1;
  919.     TCmoves = 60;
  920.     TCminutes = 5;
  921.  
  922.     int Lev;
  923.     ui_ChangeLevel(&Lev);
  924.     Level=(short)Lev;
  925.  
  926.     switch ((int) Level)
  927.         {
  928.         case 1:
  929.             TCmoves = 60;
  930.             TCminutes = 5;
  931.             break;
  932.         case 2:
  933.             TCmoves = 60;
  934.             TCminutes = 15;
  935.             break;
  936.         case 3:
  937.             TCmoves = 60;
  938.             TCminutes = 30;
  939.             break;
  940.         case 4:
  941.             TCmoves = 40;
  942.             TCminutes = 30;
  943.             break;
  944.         case 5:
  945.             TCmoves = 40;
  946.             TCminutes = 60;
  947.             break;
  948.         case 6:
  949.             TCmoves = 40;
  950.             TCminutes = 120;
  951.             break;
  952.         case 7:
  953.             TCmoves = 40;
  954.             TCminutes = 240;
  955.             break;
  956.         case 8:
  957.             TCmoves = 1;
  958.             TCminutes = 15;
  959.             break;
  960.         case 9:
  961.             TCmoves = 1;
  962.             TCminutes = 60;
  963.             break;
  964.         case 10:
  965.             TCmoves = 1;
  966.             TCminutes = 600;
  967.             break;
  968.         }
  969.  
  970.     TCflag = (TCmoves > 1);
  971.     SetTimeControl ();
  972.     /*ClrScreen (); WHY?
  973.     UpdateDisplay (0, 0, 1, 0);*/
  974. }
  975.  
  976.  
  977. void
  978. DoDebug (void)
  979. {
  980.     short c, p, sq, tp, tc, tsq, score;
  981.     char s[40];
  982.     
  983.     ExaminePosition ();
  984.  
  985.     ui_ChoosePiece(s);
  986.  
  987.     c = neutral;
  988.     if (s[0] == 'w' || s[0] == 'W')
  989.         c = white;
  990.     if (s[0] == 'b' || s[0] == 'B')
  991.         c = black;
  992.     for(p = king; p > no_piece; p--)
  993.         if ((s[1] == pxx[p]) || (s[1] == qxx[p]))
  994.             break;
  995.     for (sq = 0; sq < 64; sq++)
  996.         {
  997.             tp = board[sq];
  998.             tc = color[sq];
  999.             board[sq] = p;
  1000.             color[sq] = c;
  1001.             tsq = PieceList[c][1];
  1002.             PieceList[c][1] = sq;
  1003.             ShowPostnValue (sq);
  1004.             PieceList[c][1] = tsq;
  1005.             board[sq] = tp;
  1006.             color[sq] = tc;
  1007.         }
  1008.     ScorePosition (opponent, &score);
  1009.     ShowScore (score);
  1010. }
  1011.  
  1012. void
  1013. // C header = TestSpeed(void (*f) (short int side, short int ply))
  1014. TestSpeed(void f(short int side, short int ply))
  1015. {
  1016.     short i;
  1017.     long t1, t2;
  1018.  
  1019.     t1 = time (0);
  1020.     for (i = 0; i < 10000; i++)
  1021.         {
  1022.             f (opponent, 2);
  1023.         }
  1024.     t2 = time (0);
  1025.     NodeCnt = 10000L * (TrPnt[3] - TrPnt[2]);
  1026.     evrate = NodeCnt / (t2 - t1);
  1027.     ShowNodeCnt (NodeCnt, evrate);
  1028. }
  1029.  
  1030.  
  1031. void
  1032. InputCommand (void)
  1033.  
  1034. /*
  1035.     Process the users command. If easy mode is OFF (the computer is thinking
  1036.     on opponents time) and the program is out of book, then make the 'hint'
  1037.     move on the board and call SelectMove() to find a response. The user
  1038.     terminates the search by entering ^C (quit siqnal) before entering a
  1039.     command. If the opponent does not make the hint move, then set Sdepth to
  1040.     zero.
  1041. */
  1042.  
  1043. {
  1044.     short ok, tmp;
  1045.     unsigned short mv;
  1046.     char s[80];
  1047.  
  1048.     ok = flag.quit = false;
  1049.     player = opponent;
  1050.     //ShowSidetomove ();    // Delayed until ready to GetMove
  1051.     ft = 0;
  1052.     if (hint > 0 && !flag.easy && Book == NULL)
  1053.         {
  1054.             fflush (stdout);
  1055.             time0 = time ((long *) 0);
  1056.             algbr ((short) hint >> 8, (short) hint & 0xFF, false);
  1057.             strcpy (s, mvstr[0]);
  1058.             tmp = epsquare;
  1059.             if (VerifyMove (s, 1, &mv))
  1060.                 {
  1061.                     ShowPrompt ();
  1062.                     SelectMove (computer, 2);
  1063.                     (void) VerifyMove (mvstr[0], 2, &mv);
  1064.                     if (Sdepth > 0)
  1065.                         Sdepth--;
  1066.                 }
  1067.             ft = time ((long *) 0) - time0;
  1068.             epsquare = tmp;
  1069.         }
  1070.     signal (SIGINT, Die);
  1071. #ifndef MSDOS
  1072.     signal (SIGQUIT, Die);
  1073. #endif /* MSDOS */
  1074.     while (!(ok || flag.quit))
  1075.         {
  1076.             player = opponent;
  1077.             ShowSidetomove();
  1078.             MoveList (opponent, 2); // For CalculateLegalMove
  1079.             ui_GetMove(s);
  1080.             ok = VerifyMove (s, 0, &mv);
  1081.             if (ok) {
  1082.                 if (mv != hint) {
  1083.                     Sdepth = 0;
  1084.                     ft = 0;
  1085.                 }
  1086.             } else if (*s == '\0')
  1087.                 UpdateDisplay (0, 0, 1, 0);
  1088.             else if (strcmp (s, "bd") == 0) {
  1089.                     /*ClrScreen ();*/
  1090.                     UpdateDisplay (0, 0, 1, 0);
  1091.             } else if ((strcmp (s, "quit") == 0) || (strcmp (s, "exit") == 0))
  1092.                 flag.quit = true;
  1093.             else if (strcmp (s, "post") == 0)
  1094.                 flag.post = !flag.post;
  1095.             else if (strcmp (s, "edit") == 0)
  1096.                 EditBoard ();
  1097.             else if (strcmp (s, "go") == 0)
  1098.                 ok = true;
  1099.             else if (strcmp (s, "help") == 0)
  1100.                 help ();
  1101.             else if (strcmp (s, "force") == 0)
  1102.                 flag.force = !flag.force;
  1103.             else if (strcmp (s, "book") == 0)
  1104.                 Book = NULL;
  1105.             else if (strcmp (s, "undo") == 0 && GameCnt > 0)
  1106.                 Undo ();
  1107.             else if (strcmp (s, "new") == 0)
  1108.                 NewGame ();
  1109.             else if (strcmp (s, "list") == 0)
  1110.                 ListGame ();
  1111.             else if (strcmp (s, "level") == 0)
  1112.                 SelectLevel ();
  1113.             else if (strcmp (s, "hash") == 0)
  1114.                 flag.hash = !flag.hash;
  1115.             else if (strcmp (s, "beep") == 0)
  1116.                 flag.beep = !flag.beep;
  1117. /*
  1118.             else if (strcmp (s, "Awindow") == 0)
  1119.                 ChangeAlphaWindow ();
  1120.             else if (strcmp (s, "Bwindow") == 0)
  1121.                 ChangeBetaWindow ();
  1122. */
  1123.             else if (strcmp (s, "hint") == 0)
  1124.                 GiveHint ();
  1125.             else if (strcmp (s, "both") == 0) {
  1126.                     flag.bothsides = !flag.bothsides;
  1127.                     Sdepth = 0;
  1128.                     SelectMove (opponent, 1);
  1129.                     ok = true;
  1130.             } else if (strcmp (s, "reverse") == 0) {
  1131.                     flag.reverse = !flag.reverse;
  1132.                     /*ClrScreen ();*/
  1133.                     UpdateDisplay (0, 0, 1, 0);
  1134.             }
  1135. #if !defined(MSDOS) || defined(SEVENBIT)
  1136.             else if (strcmp (s, "shade") == 0)
  1137.                 ui_ToggleShade();
  1138. #endif /* MSDOS && !SEVENBIT */
  1139.             else if (strcmp (s, "switch") == 0) {
  1140.                     computer = otherside[computer];
  1141.                     opponent = otherside[opponent];
  1142.                     flag.force = false;
  1143.                     Sdepth = 0;
  1144.                     ok = true;
  1145.             } else if (strcmp (s, "white") == 0) {
  1146.                     computer = white;
  1147.                     opponent = black;
  1148.                     ok = true;
  1149.                     flag.force = false;
  1150.                     Sdepth = 0;
  1151.             } else if (strcmp (s, "black") == 0) {
  1152.                     computer = black;
  1153.                     opponent = white;
  1154.                     ok = true;
  1155.                     flag.force = false;
  1156.                     Sdepth = 0;
  1157.             } else if (strcmp (s, "remove") == 0 && GameCnt > 1) {
  1158.                     Undo ();
  1159.                     Undo ();
  1160.             } else if (strcmp (s, "get") == 0)
  1161.                 GetGame ();
  1162.             else if (strcmp (s, "save") == 0)
  1163.                 SaveGame ();
  1164.             else if (strcmp (s, "depth") == 0)
  1165.                 ChangeSearchDepth ();
  1166.             else if (strcmp (s, "random") == 0)
  1167.                 dither = 6;
  1168.             else if (strcmp (s, "easy") == 0)
  1169.                 flag.easy = !flag.easy;
  1170.             else if (strcmp (s, "contempt") == 0)
  1171.                 SetContempt ();
  1172. /*
  1173.             else if (strcmp (s, "xwndw") == 0)
  1174.                 ChangeXwindow ();
  1175. */
  1176.             else if (strcmp (s, "coords") == 0) {
  1177.                     coords = !coords;
  1178.                     UpdateDisplay (0, 0, 1, 0);
  1179.             }
  1180. #if !defined(MSDOS) || defined(SEVENBIT)
  1181.             else if (strcmp (s, "stars") == 0)
  1182.                 ui_ToggleStars();
  1183. #endif /* MSDOS && !SEVENBIT */
  1184.             else if (strcmp (s, "test") == 0) {
  1185.                     ShowMessage("Testing MoveList Speed");
  1186.                     TestSpeed (MoveList);
  1187.                     ShowMessage("Testing CaptureList Speed");
  1188.                     TestSpeed (CaptureList);
  1189.             } else if (strcmp (s, "p") == 0)
  1190.                 ShowPostnValues ();
  1191.             else if (strcmp (s, "debug") == 0)
  1192.                 DoDebug ();
  1193.             else if (strcmp (s, "rv") == 0)
  1194.                 ui_ToggleRV();
  1195.             else
  1196.                 ui_RejectMove(s);
  1197.         }
  1198.  
  1199.     ClearMessage ();
  1200.     ElapsedTime (1);
  1201.     if (flag.force)
  1202.         {
  1203.             computer = opponent;
  1204.             opponent = otherside[computer];
  1205.         }
  1206.     signal (SIGINT, TerminateSearch);
  1207. #ifndef MSDOS
  1208.     signal (SIGQUIT, TerminateSearch);
  1209. #endif /* MSDOS */
  1210. }
  1211.  
  1212. int NeedPromotion(int x, int y)
  1213. {
  1214.     int sq=locn(y,x);
  1215.     return ((color[sq]==white && y==6) || (color[sq]==black && y==1)) && board[sq]==pawn;
  1216. }
  1217.  
  1218. int RankAt(int x,int y)
  1219. {
  1220.     return board[locn(y,x)];
  1221. }
  1222.  
  1223. int ColourAt(int x,int y)
  1224. {
  1225.     return color[locn(y,x)];
  1226. }
  1227.  
  1228.  
  1229. static int Legal[8][8];
  1230.  
  1231. void CalculateLegalMoves(int x,int y)
  1232. // Fairly fast
  1233. {
  1234.     for (int i=0; i<8; i++)
  1235.         for (int j=0; j<8; j++)
  1236.             Legal[i][j]=0;
  1237.  
  1238.     int pnt = TrPnt[2];
  1239.     while (pnt < TrPnt[3]) {
  1240.         int f=Tree[pnt].f;
  1241.         int t=Tree[pnt].t;
  1242.         if (x==column(f) && y==row(f)) {
  1243.             Legal[column(t)][row(t)]=1;
  1244.         }
  1245.         pnt++;
  1246.     }
  1247. }
  1248.  
  1249. int LegalMove(int x, int y)
  1250. // Very fast
  1251. {
  1252.     return Legal[x][y];
  1253. }
  1254.  
  1255.