home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuch40.zip / gnuchess-4.0.pl79 / src / book.c < prev    next >
C/C++ Source or Header  |  1999-01-15  |  30KB  |  1,259 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1985-1996 Stuart Cracraft, John Stanback,
  5.  *                         Daryl Baker, Conor McCarthy,
  6.  *                         Mike McGann, Chua Kong Sian
  7.  * Copyright (c) 1985-1996 Free Software Foundation
  8.  *
  9.  * This file is part of GNU CHESS.
  10.  *
  11.  * GNU Chess is free software; you can redistribute it and/or modify it under
  12.  * the terms of the GNU General Public License as published by the Free
  13.  * Software Foundation; either version 2, or (at your option) any later
  14.  * version.
  15.  *
  16.  * GNU Chess is distributed in the hope that it will be useful, but WITHOUT ANY
  17.  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  18.  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  19.  * details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License along with
  22.  * GNU Chess; see the file COPYING.  If not, write to the Free Software
  23.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25. #include "gnuchess.h"
  26. #include "ttable.h"        /* uses hashbd, hashkey */
  27. #include "ataks.h"
  28. #if !defined(AMIGADOS) && !defined(Think_C) && !defined(WIN32)
  29. #include <unistd.h>
  30. #endif
  31. #ifdef Think_C
  32. #include <unix.h>
  33. #endif
  34. #ifdef GENIT
  35. FILE *GEN;
  36. int GENline = 0;
  37. int GENmove = 0;
  38. CHAR gs0[12], gs1[12], gs2[12], gs3[12], GENITs[12];
  39. #endif
  40. #ifdef MSDOS
  41. #include <io.h>
  42. #endif
  43. #if !defined MSDOS && !defined(Think_C) && !defined (__EMX__)
  44. #define O_BINARY 0
  45. #endif
  46. #include <fcntl.h>
  47. unsigned long booksize = BOOKSIZE;
  48. unsigned long int BKTBLSIZE;
  49. unsigned long BOOKMASK;
  50. unsigned long bookcount = 0;
  51. unsigned long bookline = 0;
  52. unsigned bookpocket = BOOKPOCKET;
  53. UTSHORT bookmaxply = BOOKMAXPLY;
  54.  
  55. #ifdef ECO
  56. #include <sys/types.h>
  57. #include <sys/stat.h>
  58. #endif
  59.  
  60. CHAR *bookfile = NULL;
  61. CHAR *binbookfile = BINBOOK;
  62.  
  63. int GotBook = false;
  64. unsigned long bhashbd, bhashkey;
  65.  
  66.  
  67. #ifdef GENIT
  68. GENITchk (gs)
  69.      CHAR *gs;
  70. {
  71.     int gcnt, gpnt;
  72.     struct leaf *node = NULL;
  73.     gcnt = 0;
  74.     gpnt = TrPnt[2];
  75.     while (gpnt < TrPnt[3])
  76.       {
  77.       node = &Tree[gpnt++];
  78.       algbr (node->f, node->t, (SHORT) node->flags);
  79.       if (strcmp (gs, mvstr[0]) == 0 || strcmp (gs, mvstr[1]) == 0 ||
  80.           strcmp (gs, mvstr[2]) == 0 || strcmp (gs, mvstr[3]) == 0
  81.           || strcmp (gs, mvstr[4]) == 0)
  82.         {
  83.         gcnt++;
  84.         }
  85.       }
  86.     return gcnt;
  87. }
  88. #endif
  89.  
  90. #ifndef QUIETBOOKGEN
  91. void
  92. bkdisplay (s, cnt, moveno)
  93.      CHAR *s;
  94.      int cnt;
  95.      int moveno;
  96. {
  97.     static SHORT pnt;
  98. #ifndef SEMIQUIETBOOKGEN
  99.     struct leaf *node;
  100.     int r, c, l;
  101. #endif
  102.  
  103.     pnt = TrPnt[2];
  104.     printf ("matches = %d\n", cnt);
  105.     printf ("inout move is :%s:move number %d side %s\n", s, moveno / 2 + 1, !(moveno & 1) ? "white" : "black");
  106. #ifndef SEMIQUIETBOOKGEN
  107.     printf ("legal moves are \n");
  108.     while (pnt < TrPnt[3])
  109.       {
  110.       node = &Tree[pnt++];
  111.       algbr (node->f, node->t, (SHORT) node->flags);
  112.       printf ("%s %s %s %s %s\n", mvstr[0], mvstr[1], mvstr[2], mvstr[3], mvstr[4]);
  113.       }
  114.     printf ("\n current board is\n");
  115.     for (r = 7; r >= 0; r--)
  116.       {
  117.       for (c = 0; c <= 7; c++)
  118.         {
  119.         l = locn (r, c);
  120.         if (color[l] == neutral)
  121.             printf (" -");
  122.         else if (color[l] == white)
  123.             printf (" %c", qxx[board[l]]);
  124.         else
  125.             printf (" %c", pxx[board[l]]);
  126.         }
  127.       printf ("\n");
  128.       }
  129.     printf ("\n\n");
  130. #endif
  131. }
  132.  
  133. #endif
  134.  
  135. int
  136. BVerifyMove (CHAR * s, UTSHORT * mv, int moveno)
  137.  
  138.      /*
  139.       * Compare the string 's' to the list of legal moves available for the
  140.       * opponent. If a match is found, make the move on the board.
  141.       */
  142.  
  143. {
  144.     static SHORT pnt, tempb, tempc, tempsf, tempst, cnt;
  145.     static struct leaf xnode;
  146.     struct leaf *node;
  147.  
  148.     *mv = 0;
  149.     cnt = 0;
  150.     VMoveList (opponent, 2);
  151.     pnt = TrPnt[2];
  152.     while (pnt < TrPnt[3])
  153.       {
  154.       node = &Tree[pnt++];
  155.       algbr (node->f, node->t, (SHORT) node->flags);
  156.       if (strcmp (s, mvstr[0]) == 0 || strcmp (s, mvstr[1]) == 0 ||
  157.           strcmp (s, mvstr[2]) == 0 || strcmp (s, mvstr[3]) == 0 || strcmp (s, mvstr[4]) == 0)
  158.         {
  159.         cnt++;
  160.         xnode = *node;
  161.         }
  162.       }
  163.     if (cnt == 1)
  164.       {
  165. #ifdef GENIT
  166.  
  167.       algbr (xnode.f, xnode.t, (SHORT) xnode.flags);
  168.       strcpy (gs0, mvstr[0]);
  169.       strcpy (gs1, mvstr[1]);
  170.       strcpy (gs2, mvstr[2]);
  171.       strcpy (gs3, mvstr[3]);
  172.       if (GENITchk (gs1) == 1)
  173.           strcpy (GENITs, gs1);
  174.       else if (GENITchk (gs2) == 1)
  175.           strcpy (GENITs, gs2);
  176.       else if (GENITchk (gs2) == 1)
  177.           strcpy (GENITs, gs1);
  178.       else
  179.           strcpy (GENITs, gs0);
  180.       if (strcmp ("e8g8", GENITs) == 0 || strcmp ("e1g1", GENITs) == 0)
  181.           strcpy (GENITs, "o-o");
  182.       else if (strcmp ("e8c8", GENITs) == 0 || strcmp ("e1c1", GENITs) == 0)
  183.           strcpy (GENITs, "o-o-o");
  184. #endif
  185.       MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  186.       if (SqAtakd (PieceList[opponent][0], computer))
  187.         {
  188.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  189.         /* Illegal move in check */
  190. #ifndef QUIETBOOKGEN
  191.         printf (CP[77]);
  192.         printf ("\n");
  193.         bkdisplay (s, cnt, moveno);
  194. #endif
  195.         return (false);
  196.         }
  197.       else
  198.         {
  199.         *mv = (xnode.f << 8) | xnode.t;
  200.         algbr (xnode.f, xnode.t, false);
  201.         if (board[xnode.t] == pawn)
  202.           {
  203.               if (xnode.t - xnode.f == 16)
  204.               epsquare = xnode.f + 8;
  205.               else if (xnode.f - xnode.t == 16)
  206.               epsquare = xnode.f - 8;
  207.           }
  208.         else
  209.             epsquare = -1;
  210.  
  211.         return (true);
  212.         }
  213.       }
  214.     /* Illegal move */
  215. #ifndef QUIETBOOKGEN
  216.     printf (CP[75], s);
  217.     bkdisplay (s, cnt, moveno);
  218. #endif
  219.     return (false);
  220. }
  221.  
  222. void
  223. RESET (void)
  224.  
  225.      /*
  226.       * Reset the board and other variables to start a new game.
  227.       */
  228.  
  229. {
  230.     SHORT l;
  231.  
  232.     flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
  233.     flag.material = flag.coords = flag.hash = flag.easy = flag.rcptr = true;
  234.     flag.stars = flag.shade = flag.back = flag.musttimeout = false;
  235. #ifdef CHESSTOOL
  236.     flag.beep = false;
  237. #else
  238.     flag.beep = true;
  239. #endif
  240. #ifdef CLIENT
  241.     flag.gamein = true;
  242.     flag.post = true;
  243. #else
  244.     flag.gamein = false;
  245. #endif
  246.     GenCnt = epsquare = 0;
  247.     GameCnt = 0;
  248.     Developed[white] = Developed[black] = false;
  249.     castld[white] = castld[black] = false;
  250.     PawnThreat[0] = CptrFlag[0] = false;
  251.     opponent = white;
  252.     computer = black;
  253.     for (l = 0; l < 64; l++)
  254.       {
  255.       board[l] = Stboard[l];
  256.       color[l] = Stcolor[l];
  257.       Mvboard[l] = 0;
  258.       }
  259.     InitializeStats ();
  260. }
  261.  
  262. int
  263. gnc (FILE * fd)
  264. {
  265.     int c;
  266.     c = getc (fd);
  267.     if (c == '(')
  268.       {
  269. #ifdef GENIT
  270.       fputc (GEN, c);
  271. #endif
  272.       do
  273.         {
  274.         c = getc (fd);
  275. #ifdef GENIT
  276.         fputc (GEN, c);
  277. #endif
  278.         if (c == ')')
  279.           {
  280.               c = getc (fd);
  281.               break;
  282.           }
  283.         if (c == EOF)
  284.             break;
  285.         }
  286.       while (true);
  287.       }
  288.     else if (c == '{')
  289.       {
  290. #ifdef GENIT
  291.       fputc (GEN, c);
  292. #endif
  293.       do
  294.         {
  295.         c = getc (fd);
  296. #ifdef GENIT
  297.         fputc (GEN, c);
  298. #endif
  299.         if (c == '}')
  300.           {
  301.               c = getc (fd);
  302.               break;
  303.           }
  304.         if (c == EOF)
  305.             break;
  306.         }
  307.       while (true);
  308.       }
  309.     return c;
  310. }
  311.  
  312.  
  313. int
  314. Vparse (FILE * fd, UTSHORT * mv, SHORT side, CHAR * opening, int moveno)
  315. {
  316.     register int c, i;
  317.     CHAR s[1024];
  318.     CHAR *p;
  319.  
  320.     while (true)
  321.       {
  322.  
  323.       while ((c = gnc (fd)) == ' ' || c == '\n');
  324.       if (c == '\r')
  325.           continue;
  326.       i = 0;
  327.       if (c == '#' || c == '[' || c == '%')
  328.         {            /* comment */
  329. #ifdef GENIT
  330.         pcurr =
  331. #endif
  332.             p = opening;
  333.         do
  334.           {
  335.               *p++ = c;
  336.               c = gnc (fd);
  337.               if (c == '\r')
  338.               continue;
  339.               /* goes to end of line */
  340.               if (c == '\n')
  341.             {
  342.                 /* does the comment continue */
  343.                 if (opening[0] == '[')
  344.                   {
  345.                   if ((c = getc (fd)) == '[')
  346.                     {
  347. #ifdef GENIT
  348.                     *p = '\0';
  349.                     fprintf (GEN, "%s\n", pcurr);
  350.                     pcurr = p;
  351. #endif
  352.                     continue;
  353.                     }
  354.                   else
  355.                       ungetc (c, fd);
  356.                   }
  357.                 *p = '\0';
  358. #ifdef GENIT
  359.                 GENline = 0;
  360.                 fprintf (GEN, "%s\n", opening);
  361.                 GENmove = 0;
  362. #endif
  363.                 return 0;
  364.             }
  365.               if (c == EOF)
  366.               return -1;
  367.           }
  368.         while (true);
  369.         }
  370.       /* is it a move number or analysis ( in [ ] or in { } ) */
  371.       /* number cannot start with a 0 because of 0-0 */
  372.       else if (!isalpha (c) && c != '0')
  373.         {
  374.         int nlxx = false;
  375.         int nonspace = false;
  376.  
  377.         while (true)
  378.           {
  379.               c = gnc (fd);
  380.               if (nlxx)
  381.               if (c == '#' || c == '[' || c == '%')
  382.                 {
  383.                 ungetc (c, fd);
  384.                 return 0;
  385.                 }
  386.               if (c == '\r')
  387.               continue;
  388.               if (c == '\n')
  389.             {
  390.                 nlxx = true;
  391.                 continue;
  392.             }
  393.               else
  394.               nlxx = false;
  395.               if (c == EOF)
  396.             {
  397.                 return -1;
  398.             }
  399.               /* stop at first nonspace a ... is space */
  400.               /* must be nonspace because of 0-0 */
  401.               if (nonspace)
  402.             {
  403.                 if (c != '.' && c != ' ')
  404.                 break;
  405.             }
  406.               if (c == '.')
  407.             {
  408.                 nonspace = true;
  409.             }
  410.               /* stop if alpha must be move */
  411.               else if (isalpha (c))
  412.               break;
  413.           }
  414.         }
  415.       s[0] = (CHAR) c;
  416.  
  417.       while ((c = gnc (fd)) != '\n' && c != ' ' && c != '\t' && c != EOF)
  418.         {
  419.         if (isupper (c))
  420.           {
  421.               if (c != 'O')
  422.             {
  423.                 ungetc (c, fd);
  424.                 c = ' ';
  425.                 break;
  426.             }
  427.           }
  428.         if (c == '\r')
  429.             continue;
  430.         if (c == '?')
  431.             break;
  432.         if (c == '!')
  433.             continue;
  434.         if (c == '+')
  435.             continue;
  436.         if (c == '#')
  437.             continue;
  438.         if (c == '%')
  439.             continue;
  440.         if (c == '=')
  441.           {
  442.               c = gnc (fd);
  443.               c = tolower (c);
  444.           }
  445.         if (c != 'x')
  446.             s[++i] = c;
  447.         }
  448.       s[++i] = '\0';
  449.  
  450.       if (c == EOF)
  451.           return (-1);
  452.       if (s[0] == '!' || s[0] == ';')
  453.         {
  454.         while (c != '\n' && c != EOF)
  455.             c = gnc (fd);
  456.         if (c == EOF)
  457.             return -1;
  458.         else
  459.             return (0);
  460.         }
  461.       if ((strcmp (s, "o-o-o") == 0) || (strcmp (s, "OOO") == 0) || (strcmp (s, "O-O-O") == 0) || (strcmp (s, "0-0-0") == 0))
  462.         {
  463.         if (side == black)
  464.             strcpy (s, "e8c8");
  465.         else
  466.             strcpy (s, "e1c1");
  467.         }
  468.       else if ((strcmp ("o-o", s) == 0) || (strcmp (s, "OO") == 0) || (strcmp (s, "O-O") == 0) || (strcmp (s, "0-0") == 0))
  469.         {
  470.         if (side == black)
  471.             strcpy (s, "e8g8");
  472.         else
  473.             strcpy (s, "e1g1");
  474.         }
  475.       else if (strcmp (s, "draw") == 0)
  476.           continue;
  477.       else if (strcmp (s, "Draw") == 0)
  478.           continue;
  479.       else if (strcmp (s, "1-0") == 0)
  480.           continue;
  481.       else if (strcmp (s, "0-1") == 0)
  482.           continue;
  483.       else if (strcmp (s, "2-1/2") == 0)
  484.           continue;
  485.       if (isupper (s[i - 1]))
  486.           s[i - 1] = tolower (s[i - 1]);
  487.  
  488.       bhashkey = hashkey;
  489.       bhashbd = hashbd;
  490.  
  491.       i = BVerifyMove (s, mv, moveno);
  492.       if (c == '?')
  493.         {            /* Bad move, not for the program to play */
  494.         *mv |= BADMOVE;    /* Flag it ! */
  495.         c = getc (fd);
  496.         }
  497.       else if (c == '+' || c == '\r')
  498.           c = gnc (fd);
  499.       if (!i)
  500.         {
  501.         printf ("%s \n", opening);
  502.         /* flush to start of next */
  503.         while ((c = gnc (fd)) != '[' && c != EOF && c != '#');
  504.         if (c == EOF)
  505.             return -1;
  506.         else
  507.           {
  508.               ungetc (c, fd);
  509.               return i;
  510.           }
  511.         }
  512. #ifdef GENIT
  513.       if (GENline++ > 15)
  514.         {
  515.         GENline = 1;
  516.         fprintf (GEN, "\n");
  517.         }
  518.       if ((GENmove / 2) * 2 == GENmove)
  519.           fprintf ("%d. ", (GENmove / 2) + 1);
  520.       if (c == '?')
  521.           fprintf (GEN, "%s? ", GENITs);
  522.       else
  523.           fprintf (GEN, "%s ", GENITs);
  524.       if (!(GENline & 1))
  525.           fprintf (GEN, " ");
  526.       GENmove++;
  527. #endif
  528.       return (i);
  529.       }
  530. }
  531.  
  532.  
  533. /*===================================== GDX =======================================*/
  534.  
  535. struct gdxadmin
  536. {
  537.     unsigned long bookcount;
  538.     unsigned long booksize;
  539.     unsigned long maxoffset;
  540. }
  541. ADMIN, B;
  542.  
  543. struct gdxdata
  544.   {
  545.       unsigned long hashbd;
  546.       utshort hashkey;
  547.       utshort bmove;
  548.       utshort hint;
  549.       utshort count;
  550.   }
  551. DATA;
  552.  
  553. #ifdef LONG64
  554. #define lts(x) (utshort)(((x>>48)&0xfffe)|side)
  555. #else
  556. #define lts(x) (utshort)(((x>>16)&0xfffe)|side)
  557. #endif
  558. unsigned long currentoffset;
  559. int gfd;
  560.  
  561. void
  562. GetOpenings (void)
  563.  
  564.      /*
  565.       * If a text file of opening chess plays (the Opening Book) is available: 
  566.       * Read in the Opening Book file and parse the algebraic notation for a move
  567.       * into an unsigned integer format indicating the from and to square. Create
  568.       * or update a binary hash file with the recomended move/moves for each 
  569.       * position.  
  570.       * The binary hash file is opened with readonly access durring the game.
  571.       */
  572. {
  573.     register SHORT i;
  574.     CHAR opening[1024];
  575.     CHAR msg[1024];
  576.     int mustwrite = false;
  577.     UTSHORT xside, doit, side;
  578.     SHORT c;
  579.     UTSHORT mv;
  580.     UTSHORT ix;
  581.     unsigned long x;
  582.     unsigned long games = 0;
  583.  
  584.     FILE *fd;
  585.  
  586. #ifdef __EMX__
  587.     if (bookfile==NULL) fd = fopen ("gnuchess.book", "r");
  588.     else
  589. #endif
  590.     if ((fd = fopen (bookfile, "r")) == NULL)
  591.     fd = fopen ("gnuchess.book", "r");
  592. #ifdef GENIT
  593.     if ((GEN = fopen ("GEN", "w")) == NULL)
  594.       {
  595.       printf ("GEN FAIL\n");
  596.       exit (1);
  597.       }
  598. #endif
  599.     if (fd != NULL)
  600.       {
  601.       /* yes add to book */
  602.       /* open book as writer */
  603.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  604.       if (gfd >= 0)
  605.         {
  606.         if (sizeof (struct gdxadmin) == read (gfd, &ADMIN, sizeof (struct gdxadmin)))
  607.           {
  608.               B.bookcount = ADMIN.bookcount;
  609.               B.booksize = ADMIN.booksize;
  610.               B.maxoffset = ADMIN.maxoffset;
  611.               if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  612.             {
  613.                 printf ("bad format %s\n", binbookfile);
  614.                 exit (1);
  615.             }
  616.           }
  617.         else
  618.           {
  619.               printf ("bad format %s\n", binbookfile);
  620.               exit (1);
  621.           }
  622.         close (gfd);
  623.         gfd = open (binbookfile, O_RDWR | O_BINARY);
  624.  
  625.         }
  626.       else
  627.         {
  628. #ifdef Think_C
  629.         gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY);
  630. #else
  631.         gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY, 0644);
  632. #endif
  633.         ADMIN.bookcount = B.bookcount = 0;
  634.         ADMIN.booksize = B.booksize = booksize;
  635.         B.maxoffset = ADMIN.maxoffset = (unsigned long) (booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  636.         DATA.hashbd = 0;
  637.         DATA.hashkey = 0;
  638.         DATA.bmove = 0;
  639.         DATA.hint = 0;
  640.         DATA.count = 0;
  641.         write (gfd, &ADMIN, sizeof (struct gdxadmin));
  642.         printf ("creating bookfile %s  %ld %ld\n", binbookfile, B.maxoffset, B.booksize);
  643.         for (x = 0; x < B.booksize; x++)
  644.           {
  645.               write (gfd, &DATA, sizeof (struct gdxdata));
  646.           }
  647.  
  648.  
  649.         }
  650.       if (gfd >= 0)
  651.         {
  652.  
  653.  
  654.         /* setvbuf(fd,buffr,_IOFBF,2048); */
  655.         side = white;
  656.         xside = black;
  657.         InitializeStats ();
  658.         i = 0;
  659.  
  660.         while ((c = Vparse (fd, &mv, side, opening, i)) >= 0)
  661.           {
  662.               if (c == 1)
  663.             {
  664.  
  665.                 /*
  666.                  * if not first move of an opening and first
  667.                  * time we have seen it save next move as
  668.                  * hint
  669.                  */
  670.                 i++;
  671.                 if (i < bookmaxply + 2)
  672.                   {
  673.                   if (i > 1)
  674.                     {
  675.                     DATA.hint = mv & 0x3f3f;
  676.                     }
  677.                   if (i < bookmaxply + 1)
  678.                     {
  679.                     doit = true;
  680.  
  681.                     /*
  682.                      * see if this position and
  683.                      * move already exist from
  684.                      * some other opening
  685.                      */
  686.  
  687.                     /*
  688.                      * is this ethical, to offer
  689.                      * the bad move as a
  690.                      * hint?????
  691.                      */
  692.                     ix = 0;
  693.                     if (mustwrite)
  694.                       {
  695.                           lseek (gfd, currentoffset, SEEK_SET);
  696.                           write (gfd, &DATA, sizeof (struct gdxdata));
  697.                           mustwrite = false;
  698.                       }
  699.                     doit = true;
  700.                     currentoffset = (unsigned long) (bhashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  701.                     while (true)
  702.                       {
  703.  
  704.                           lseek (gfd, currentoffset, SEEK_SET);
  705.                           if ((read (gfd, &DATA, sizeof (struct gdxdata)) == 0))
  706.                             break;
  707.  
  708.                           if (DATA.bmove == 0)
  709.                           break;
  710.                           if (DATA.hashkey == (utshort) (lts (bhashkey)) && DATA.hashbd == bhashbd)
  711.                         {
  712.  
  713.                             if ((DATA.bmove & (~(LASTMOVE | BADMOVE))) == (mv & ~BADMOVE))
  714.                               {
  715.                               DATA.count++;
  716.                               if (mv & BADMOVE)
  717.                                   DATA.bmove |= BADMOVE;
  718.                               /*
  719.                                * yes so just bump count - count is
  720.                                * used to choose opening move in
  721.                                * proportion to its presence in the book
  722.                                */
  723.                               doit = false;
  724.                               mustwrite = true;
  725.                               break;
  726.                               }
  727.                             else if (DATA.bmove & LASTMOVE)
  728.                               {
  729.                               DATA.bmove &= (~LASTMOVE);
  730.                               lseek (gfd, currentoffset, SEEK_SET);
  731.                               write (gfd, &DATA, sizeof (struct gdxdata));
  732.                               }
  733.                         }
  734.                           currentoffset += sizeof (struct gdxdata);
  735.                           if (currentoffset > B.maxoffset)
  736.                           currentoffset = sizeof (struct gdxadmin);
  737.                       }
  738.  
  739.                     /*
  740.                      * doesn`t exist so add it to
  741.                      * the book
  742.                      */
  743.                     if (!mustwrite)
  744.                       {
  745.                           B.bookcount++;
  746. #if !defined CHESSTOOL && !defined XBOARD
  747.                           if (B.bookcount % 1000 == 0)
  748.                           printf ("%ld rec %ld openings processed\n", B.bookcount, games);
  749. #endif
  750.                           /* initialize a record */
  751.                           DATA.hashbd = bhashbd;
  752.                           DATA.hashkey = (utshort) (lts (bhashkey));
  753.                           DATA.bmove = mv | LASTMOVE;
  754.                           DATA.count = 1;
  755.                           DATA.hint = 0;
  756.  
  757.                           mustwrite = true;
  758.                       }
  759.                     }
  760.                   }
  761.                 computer = opponent;
  762.                 opponent = computer ^ 1;
  763.  
  764.                 xside = side;
  765.                 side = side ^ 1;
  766.             }
  767.               else if (i > 0)
  768.             {
  769.                 /* reset for next opening */
  770.                 games++;
  771.                 if (mustwrite)
  772.                   {
  773.                   lseek (gfd, currentoffset, SEEK_SET);
  774.                   write (gfd, &DATA, sizeof (struct gdxdata));
  775.                   mustwrite = false;
  776.                   }
  777.                 RESET ();
  778.                 i = 0;
  779.                 side = white;
  780.                 xside = black;
  781.  
  782.             }
  783.           }
  784.         if (mustwrite)
  785.           {
  786.               lseek (gfd, currentoffset, SEEK_SET);
  787.               write (gfd, &DATA, sizeof (struct gdxdata));
  788.               mustwrite = false;
  789.           }
  790.         fclose (fd);
  791.         /* write admin rec with counts */
  792.         ADMIN.bookcount = B.bookcount;
  793.         currentoffset = 0;
  794.         lseek (gfd, currentoffset, SEEK_SET);
  795.         write (gfd, &ADMIN, sizeof (struct gdxadmin));
  796.  
  797.         close (gfd);
  798.         }
  799.       }
  800.     if (binbookfile != NULL)
  801.       {
  802.       /* open book as reader */
  803.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  804.       if (gfd >= 0)
  805.         {
  806.         read (gfd, &ADMIN, sizeof (struct gdxadmin));
  807.         B.bookcount = ADMIN.bookcount;
  808.         B.booksize = ADMIN.booksize;
  809.         B.maxoffset = ADMIN.maxoffset;
  810.         if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  811.           {
  812.               printf ("bad format %s\n", binbookfile);
  813.               exit (1);
  814.           }
  815.  
  816.         }
  817.       else
  818.         {
  819.         B.bookcount = 0;
  820.         B.booksize = booksize;
  821.  
  822.         }
  823.  
  824. #if !defined CHESSTOOL && !defined XBOARD
  825.       sprintf (msg, CP[213], B.bookcount, B.booksize);
  826.       ShowMessage (msg);
  827. #endif
  828.       }
  829.     /* set every thing back to start game */
  830.     Book = BOOKFAIL;
  831.     RESET ();
  832.     /* now get ready to play */
  833.     if (!B.bookcount)
  834.       {
  835. #if !defined CHESSTOOL && !defined XBOARD
  836.       ShowMessage (CP[212]);
  837. #endif
  838.       Book = 0;
  839.       }
  840. }
  841.  
  842.  
  843. int
  844. OpeningBook (SHORT * hint, SHORT side)
  845.  
  846.      /*
  847.       * Go thru each of the opening lines of play and check for a match with the
  848.       * current game listing. If a match occurs, generate a random number. If this
  849.       * number is the largest generated so far then the next move in this line
  850.       * becomes the current "candidate". After all lines are checked, the
  851.       * candidate move is put at the top of the Tree[] array and will be played by
  852.       * the program. Note that the program does not handle book transpositions.
  853.       */
  854.  
  855. {
  856.     UTSHORT r, m;
  857.     int possibles = TrPnt[2] - TrPnt[1];
  858.     register UTSHORT i, x;
  859.     register UTSHORT rec = 0;
  860.     register UTSHORT summ = 0;
  861.     register UTSHORT h = 0, b = 0;
  862.     struct gdxdata OBB[128];
  863.  
  864.     gsrand ((unsigned int) time ((time_t *) 0));
  865.     m = 0;
  866.  
  867.     /*
  868.      * find all the moves for this position  - count them and get their
  869.      * total count
  870.      */
  871.     if (B.bookcount == 0)
  872.       {
  873.     Book--;
  874.     return false;
  875.       }
  876.     currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  877.     x = 0;
  878.     lseek (gfd, currentoffset, SEEK_SET);
  879.     while (true)
  880.       {
  881.         if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0)
  882.         break;
  883.         if (OBB[x].bmove == 0)
  884.         break;
  885.  
  886.         if (OBB[x].hashkey == (utshort) (lts (hashkey)) && OBB[x].hashbd == hashbd)
  887.       {
  888.         x++;
  889.         if (OBB[x - 1].bmove & LASTMOVE)
  890.         break;
  891.       }
  892.     currentoffset += sizeof (struct gdxdata);
  893.     if (currentoffset > B.maxoffset)
  894.       {
  895.         lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
  896.         currentoffset = sizeof (struct gdxadmin);
  897.       }
  898.  
  899.       }
  900.     if (x == 0)
  901.       {
  902.         Book--;
  903.         return false;
  904.       }
  905. #ifdef DEBUG33
  906.       {
  907.         int loop = true;
  908.         while (loop)
  909.       {
  910.         loop = false;
  911.         for (i = 1; i < x; i++)
  912.           {
  913.         struct gdxdata tmp;
  914.         if (OBB[i].count > OBB[i - 1].count)
  915.           {
  916.             loop = true;
  917.             tmp = OBB[i - 1];
  918.             OBB[i - 1] = OBB[i];
  919.             OBB[i] = tmp;
  920.           }
  921.           }
  922.       }
  923.       }
  924.     for (i = 0; i < x; i++)
  925.       {
  926.         algbr ((OBB[i].bmove >> 8) & 0x3f, (OBB[i].bmove) & 0x3f, 0);
  927.         printf (" %s ", mvstr[0], OBB[i].count);
  928.         algbr ((OBB[i].hint >> 8) & 0x3f, (OBB[i].hint) & 0x3f, 0);
  929.         printf ("%s %c %d\n", mvstr[0], (OBB[i].bmove & BADMOVE) ? '*' : ' ', OBB[i].count);
  930.       }
  931. #endif
  932.     for (i = 0; i < x; i++)
  933.       {
  934.         if ((m = OBB[i].bmove) & BADMOVE)
  935.       {
  936.         m &= 0x3f3f;
  937.         /* is the move is in the MoveList */
  938.         for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  939.           {
  940.           if (((Tree[b].f << 8) | Tree[b].t) == m)
  941.           {
  942.             if (--possibles)
  943.                 Tree[b].score = DONTUSE;
  944.             pick (TrPnt[1], TrPnt[2] - 1);
  945.             break;
  946.           }
  947.           }
  948.       }
  949.     else
  950.       summ += OBB[i].count;
  951.       }
  952.     if (summ == 0)
  953.       {
  954.         Book--;
  955.         return false;
  956.       }
  957.  
  958.     r = (urand () % summ);
  959. #ifdef DEBUG33
  960.     printf ("rand is %d, sum is %d\n", r, summ);
  961. #endif
  962.     for (i = 0; i < x; i++)
  963.     if (!(OBB[i].bmove & BADMOVE))
  964.       {
  965.         if (r < OBB[i].count)
  966.       {
  967.         rec = i;
  968.         break;
  969.       }
  970.     else
  971.         r -= OBB[i].count;
  972. #ifdef DEBUG33
  973.     printf ("rand is %d, sum is %d\n", r, summ);
  974. #endif
  975.  
  976.       }
  977.  
  978.     h = ((OBB[rec].hint) & 0x3f3f);
  979.     m = ((OBB[rec].bmove) & 0x3f3f);
  980.     /* make sure the move is in the MoveList */
  981.     for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  982.       {
  983.         if (((Tree[b].f << 8) | Tree[b].t) == m)
  984.       {
  985.         Tree[b].flags |= book;
  986.         Tree[b].score = 0;
  987.         break;
  988.       }
  989.       }
  990.     /* Make sure its the best */
  991.  
  992.     pick (TrPnt[1], TrPnt[2] - 1);
  993.     if (Tree[TrPnt[1]].score)
  994.       {
  995.         /* no! */
  996.         Book--;
  997.         return false;
  998.       }
  999.     /* ok pick up the hint and go */
  1000.     *hint = h;
  1001.     return true;
  1002. }
  1003.  
  1004. void
  1005. LOpeningBook (SHORT side)
  1006.  
  1007.      /*
  1008.       * Go thru each of the opening lines of play and check for a match with the
  1009.       * current game listing. If a match occurs, generate a random number. If this
  1010.       * number is the largest generated so far then the next move in this line
  1011.       * becomes the current "candidate". After all lines are checked, the
  1012.       * candidate move is put at the top of the Tree[] array and will be played by
  1013.       * the program. Note that the program does not handle book transpositions.
  1014.       */
  1015.  
  1016. {
  1017.     char Lmove[12], Lhint[12];
  1018.     /*
  1019.      * find all the moves for this position  - count them and get their
  1020.      * total count
  1021.      */
  1022.     struct gdxdata OBB[128];
  1023.     SHORT x;
  1024.     if (B.bookcount == 0)
  1025.       {
  1026.       return;
  1027.       }
  1028.     Ldisplay1 ();
  1029.     currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  1030.     x = 0;
  1031.     lseek (gfd, currentoffset, SEEK_SET);
  1032.     while (true)
  1033.       {
  1034.       if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0)
  1035.             return;
  1036.       if (OBB[x].bmove == 0)
  1037.           return;
  1038.  
  1039.  
  1040.       if (OBB[x].hashkey == (utshort) (lts (hashkey)) && OBB[x].hashbd == hashbd)
  1041.         {
  1042.         algbr ((OBB[x].bmove >> 8) & 0x3f, (OBB[x].bmove) & 0x3f, 0);
  1043.         strcpy (Lmove, mvstr[1]);
  1044.         if (OBB[x].bmove & BADMOVE)
  1045.             strcat (Lmove, "?");
  1046.         algbr ((OBB[x].hint >> 8) & 0x3f, (OBB[x].hint) & 0x3f, 0);
  1047.         strcpy (Lhint, mvstr[1]);
  1048.         Ldisplay (Lmove, Lhint, OBB[x].count);
  1049.         if (OBB[x++].bmove & LASTMOVE)
  1050.             break;
  1051.         }
  1052.       currentoffset += sizeof (struct gdxdata);
  1053.       if (currentoffset > B.maxoffset)
  1054.         {
  1055.         lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
  1056.         currentoffset = sizeof (struct gdxadmin);
  1057.         }
  1058.  
  1059.       }
  1060.     Ldisplay2 ();
  1061.     return;
  1062. }
  1063.  
  1064. #ifdef IGNUAN
  1065. int
  1066. GOpeningBook (SHORT * hint, SHORT side, CHAR * mv)
  1067.  
  1068.      /*
  1069.       * Go thru each of the opening lines of play and check for a match with the
  1070.       * current game listing. If a match occurs, generate a random number. If this
  1071.       * number is the largest generated so far then the next move in this line
  1072.       * becomes the current "candidate". After all lines are checked, the
  1073.       * candidate move is put at the top of the Tree[] array and will be played by
  1074.       * the program. Note that the program does not handle book transpositions.
  1075.       */
  1076.  
  1077. {
  1078.     char Lmove[12], Lhint[12];
  1079.     /*
  1080.      * find all the moves for this position  - count them and get their
  1081.      * total count
  1082.      */
  1083.     struct gdxdata OBB[128];
  1084.     SHORT x;
  1085.     if (B.bookcount == 0)
  1086.       {
  1087.       return false;
  1088.       }
  1089.     currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  1090.     x = 0;
  1091.     lseek (gfd, currentoffset, SEEK_SET);
  1092.     while (true)
  1093.       {
  1094.       if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0)
  1095.             return false;
  1096.       if (OBB[x].bmove == 0)
  1097.           return false;
  1098.  
  1099.  
  1100.       if (OBB[x].hashkey == (utshort) (lts (hashkey)) && OBB[x].hashbd == hashbd)
  1101.         {
  1102.         algbr ((OBB[x].bmove >> 8) & 0x3f, (OBB[x].bmove) & 0x3f, 0);
  1103.         if ((strcmp (mvstr[0], mv) == 0) ||
  1104.             strcmp (mvstr[1], mv) == 0 ||
  1105.             strcmp (mvstr[2], mv) == 0 ||
  1106.             strcmp (mvstr[3], mv) == 0 ||
  1107.             strcmp (mvstr[4], mv) == 0)
  1108.             return true;
  1109.         if (OBB[x++].bmove & LASTMOVE)
  1110.             return false;
  1111.         }
  1112.       currentoffset += sizeof (struct gdxdata);
  1113.       if (currentoffset > B.maxoffset)
  1114.         {
  1115.         lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
  1116.         currentoffset = sizeof (struct gdxadmin);
  1117.         }
  1118.  
  1119.       }
  1120.     return false;
  1121. }
  1122. #endif
  1123.  
  1124. #ifdef ECO
  1125. #ifdef LONG64
  1126. #define rts(x) (unsigned long)(((x)&(~1))|(side))
  1127. #else
  1128. #define rts(x) (unsigned long)(((x)&(~1))|(side))
  1129. #endif
  1130. extern SHORT ecomove;
  1131. int efd = 0;
  1132. FILE *Efd;
  1133. unsigned int efdsize = 0;
  1134. void
  1135. EOpeningBook (SHORT side)
  1136. {
  1137.     char E[256];
  1138.     struct gdxecodata
  1139.       {
  1140.       unsigned long hashbd;
  1141.       unsigned long hashkey;
  1142.       unsigned int ecoptr;
  1143.       utshort cntr;
  1144.       };
  1145.     SHORT ECOmove = ecomove;
  1146.  
  1147.     /*
  1148.      * find all the moves for this position  - count them and get their
  1149.      * total count
  1150.      */
  1151.     struct gdxecodata OBB;
  1152.     SHORT x, k;
  1153.     int h = 0;
  1154.     int l = 0;
  1155.     unsigned int ecocur;
  1156.     k = 0;
  1157.     if (efd == 0)
  1158.       {
  1159.       struct stat buf;
  1160.       efd = open (BINECO, O_RDONLY | O_BINARY);
  1161.       if (efd < 0)
  1162.         {
  1163.         perror ("BINECO \n");
  1164.         return;
  1165.         }
  1166.       stat (BINECO, &buf);
  1167.       efdsize = buf.st_size / sizeof (struct gdxecodata);
  1168.       Efd = fopen (PGNECO, "r");
  1169.       if (Efd == (FILE *) NULL)
  1170.         {
  1171.         perror ("PGNECO \n");
  1172.         return;
  1173.         }
  1174.       }
  1175.     Ldisplay3 ();
  1176.     while (ECOmove > 0)
  1177.       {
  1178.       h = efdsize;
  1179.       l = 0;
  1180.       ecocur = (h + l) / 2;
  1181.       x = 0;
  1182.  
  1183.       while (true)
  1184.         {
  1185.         SHORT ecofirst;
  1186.         currentoffset = ecocur * sizeof (struct gdxecodata);
  1187.         if (lseek (efd, currentoffset, SEEK_SET) < 0)
  1188.           {
  1189.               perror ("seek error\n");
  1190.               exit (0);
  1191.           }
  1192.         if (read (efd, &OBB, sizeof (struct gdxecodata)) == 0) break;
  1193.         if (OBB.hashbd == GameList[ECOmove].hashbd && OBB.hashkey == (unsigned long) (rts (GameList[ECOmove].hashkey))
  1194.             && OBB.cntr == 0)
  1195.           {
  1196.               /* got it */
  1197.               printf ("After %d plys:\n", ECOmove);
  1198.               ecofirst = true;
  1199.               while (true)
  1200.             {
  1201.                 if (!ecofirst) { if (read (efd, &OBB, sizeof (struct gdxecodata)) == 0) break; }
  1202.                 else ecofirst = false;
  1203.                 if (OBB.hashbd != GameList[ECOmove].hashbd) break;
  1204.                 if (OBB.hashkey != (unsigned long) (rts (GameList[ECOmove].hashkey))) continue;
  1205.                 if (fseek (Efd, (long) OBB.ecoptr, SEEK_SET) < 0)
  1206.                   { perror ("Eseek PGNECO"); exit (1); }
  1207.                 if (fgets (E, sizeof (E), Efd) <= (char *) NULL)
  1208.                   { perror ("fget "); exit (1); }
  1209.                 Ldisplay4 (E);
  1210.                 k++;
  1211.                 if (fgets (E, sizeof (E), Efd) <= (char *) NULL)
  1212.                   { perror ("fget "); exit (1); }
  1213.                 k += 2;
  1214.                 while (E[0] != '[')
  1215.                   {
  1216.                   Ldisplay4 (E);
  1217.                   k++;
  1218.                   if (fgets (E, sizeof (E), Efd) <= (char *) NULL)
  1219.                     { perror ("fget "); exit (1); }
  1220.                   }
  1221.                 Ldisplay4 ("\n");
  1222.                 k++;
  1223.  
  1224.                 if (k++ > 32){
  1225.                 if (getchar () == 'q')
  1226.                   { k = 999; break; }
  1227.                 else
  1228.                     k = 1;}
  1229.             }
  1230.           }
  1231.         else if (OBB.hashbd > GameList[ECOmove].hashbd
  1232.              || (OBB.hashbd == GameList[ECOmove].hashbd
  1233.                  && OBB.hashkey > (unsigned long) (rts (GameList[ECOmove].hashkey))
  1234.                  && OBB.cntr > 0)
  1235.              || (OBB.hashbd == GameList[ECOmove].hashbd
  1236.                  && OBB.hashkey == (unsigned long) (rts (GameList[ECOmove].hashkey))
  1237.                  && OBB.cntr > 0))
  1238.           {        /* high */
  1239.               h = ecocur;
  1240.           }
  1241.         else
  1242.           {        /* low */
  1243.               l = ecocur;
  1244.           }
  1245.         if ((h == l) || (h - l) == 1)
  1246.             break;
  1247.         ecocur = (h + l) / 2;
  1248.  
  1249.         if (k > 0)
  1250.             break;
  1251.         }
  1252.       if (k > 0)
  1253.           break;
  1254.       ECOmove--;
  1255.       }
  1256.     Ldisplay2 ();
  1257. }
  1258. #endif
  1259.