home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / SPEL / GC_OS2_M / SRC-M.ZIP / book.c < prev    next >
Text File  |  1994-01-31  |  15KB  |  619 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
  5.  * Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify it under
  10.  * the terms of the GNU General Public License as published by the Free
  11.  * Software Foundation; either version 2, or (at your option) any later
  12.  * version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful, but WITHOUT ANY
  15.  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16.  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  17.  * details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License along with
  20.  * GNU Chess; see the file COPYING.  If not, write to the Free Software
  21.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23. #include "gnuchess.h"
  24. #include "ataks.h"
  25. #include <unistd.h>
  26. #include <io.h>
  27. #include <fcntl.h>
  28. unsigned booksize = BOOKSIZE;
  29. unsigned int BKTBLSIZE;
  30. unsigned long BOOKMASK;
  31. unsigned bookcount = 0;
  32. unsigned bookpocket = BOOKPOCKET;
  33. static struct bookentry
  34. {
  35.     unsigned long bookkey;
  36.     unsigned long bookbd;
  37.     unsigned short bmove;
  38.     unsigned short hint;
  39.     unsigned short count;
  40.     unsigned short flags;
  41. } *OBEND;
  42. struct bookentry *OpenBook = NULL;
  43. static struct bookentry **BookTable;
  44.  
  45. unsigned short bookmaxply = BOOKMAXPLY;
  46.  
  47. char *bookfile = NULL;
  48. char *binbookfile = BINBOOK;
  49.  
  50. int GotBook = false;
  51. static char bmvstr[4][6];
  52. unsigned long bhashbd, bhashkey;
  53.  
  54.  
  55. void
  56. Balgbr (short int f, short int t, short int flag)
  57.  
  58.  
  59.      /*
  60.       * Generate move strings in different formats.
  61.       */
  62.  
  63. {
  64.     int m3p;
  65.     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
  66.  
  67.     if (f != t)
  68.       {
  69.       /* algebraic notation */
  70.       bmvstr[0][0] = cxx[column (f)];
  71.       bmvstr[0][1] = rxx[row (f)];
  72.       bmvstr[0][2] = cxx[column (t)];
  73.       bmvstr[0][3] = rxx[row (t)];
  74.       bmvstr[0][4] = bmvstr[3][0] = '\0';
  75.       if (((bmvstr[1][0] = pxx[board[f]]) == 'P') || (flag & promote))
  76.         {
  77.         if (bmvstr[0][0] == bmvstr[0][2])    /* pawn did not eat */
  78.           {
  79.               bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][2];    /* to column */
  80.               bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][3];    /* to row */
  81.               m3p = 2;
  82.           }
  83.         else
  84.             /* pawn ate */
  85.           {
  86.               bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][0];    /* column */
  87.               bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][2];    /* to column */
  88.               bmvstr[2][2] = bmvstr[0][3];
  89.               m3p = 3;    /* to row */
  90.           }
  91.         if (flag & promote)
  92.           {
  93.               bmvstr[0][4] = bmvstr[1][2] = bmvstr[2][m3p] = qxx[flag & pmask];
  94.               bmvstr[0][5] = bmvstr[1][3] = bmvstr[2][m3p + 1] = bmvstr[3][0] = '\0';
  95.           }
  96.         else
  97.             bmvstr[2][m3p] = bmvstr[1][2] = '\0';
  98.         }
  99.       else
  100.           /* not a pawn */
  101.         {
  102.         bmvstr[2][0] = bmvstr[1][0];
  103.         bmvstr[2][1] = bmvstr[0][1];
  104.         bmvstr[2][2] = bmvstr[1][1] = bmvstr[0][2];    /* to column */
  105.         bmvstr[2][3] = bmvstr[1][2] = bmvstr[0][3];    /* to row */
  106.         bmvstr[2][4] = bmvstr[1][3] = '\0';
  107.         strcpy (bmvstr[3], bmvstr[2]);
  108.         bmvstr[3][1] = bmvstr[0][0];
  109.         if (flag & cstlmask)
  110.           {
  111.               if (t > f)
  112.             {
  113.                 strcpy (bmvstr[1], bmvstr[0]);
  114.                 strcpy (bmvstr[0], CP[5]);
  115.                 strcpy (bmvstr[2], CP[7]);
  116.             }
  117.               else
  118.             {
  119.                 strcpy (bmvstr[1], bmvstr[0]);
  120.                 strcpy (bmvstr[0], CP[6]);
  121.                 strcpy (bmvstr[2], CP[8]);
  122.             }
  123.           }
  124.         }
  125.       }
  126.     else
  127.     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
  128. }
  129.  
  130. #ifndef QUIETBOOKGEN
  131. void
  132. bkdisplay (s, cnt, moveno)
  133.      char *s;
  134.      int cnt;
  135.      int moveno;
  136. {
  137.     static short pnt;
  138.     struct leaf *node;
  139.     int r, c, l;
  140.  
  141.     pnt = TrPnt[2];
  142.     printf ("matches = %d\n", cnt);
  143.     printf ("inout move is :%s:move number %d side %s\n", s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
  144. #ifndef SEMIQUIETBOOKGEN
  145.     printf ("legal moves are \n");
  146.     while (pnt < TrPnt[3])
  147.       {
  148.       node = &Tree[pnt++];
  149.       Balgbr (node->f, node->t, (short) node->flags);
  150.       printf ("%s %s %s %s\n", bmvstr[0], bmvstr[1], bmvstr[2], bmvstr[3]);
  151.       }
  152.     printf ("\n current board is\n");
  153.     for (r = 7; r >= 0; r--)
  154.       {
  155.       for (c = 0; c <= 7; c++)
  156.         {
  157.         l = locn (r, c);
  158.         if (color[l] == neutral)
  159.             printf (" -");
  160.         else if (color[l] == white)
  161.             printf (" %c", qxx[board[l]]);
  162.         else
  163.             printf (" %c", pxx[board[l]]);
  164.         }
  165.       printf ("\n");
  166.       }
  167.     printf ("\n\n");
  168. #endif
  169. }
  170.  
  171. #endif
  172.  
  173. int
  174. BVerifyMove (char *s, short unsigned int *mv, int moveno)
  175.  
  176.      /*
  177.       * Compare the string 's' to the list of legal moves available for the
  178.       * opponent. If a match is found, make the move on the board.
  179.       */
  180.  
  181. {
  182.     static short pnt, tempb, tempc, tempsf, tempst, cnt;
  183.     static struct leaf xnode;
  184.     struct leaf *node;
  185.  
  186.     *mv = 0;
  187.     cnt = 0;
  188.     MoveList (opponent, 2);
  189.     pnt = TrPnt[2];
  190.     while (pnt < TrPnt[3])
  191.       {
  192.       node = &Tree[pnt++];
  193.       Balgbr (node->f, node->t, (short) node->flags);
  194.       if (strcmp (s, bmvstr[0]) == 0 || strcmp (s, bmvstr[1]) == 0 ||
  195.           strcmp (s, bmvstr[2]) == 0 || strcmp (s, bmvstr[3]) == 0)
  196.         {
  197.         cnt++;
  198.         xnode = *node;
  199.         }
  200.       }
  201.     if (cnt == 1)
  202.       {
  203.       MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
  204.       if (SqAtakd (PieceList[opponent][0], computer))
  205.         {
  206.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  207.         /* Illegal move in check */
  208. #ifndef QUIETBOOKGEN
  209.         printf (CP[77]);
  210.         printf ("\n");
  211.         bkdisplay (s, cnt, moveno);
  212. #endif
  213.         return (false);
  214.         }
  215.       else
  216.         {
  217.         *mv = (xnode.f << 8) | xnode.t;
  218.         Balgbr (xnode.f, xnode.t, false);
  219.         return (true);
  220.         }
  221.       }
  222.     /* Illegal move */
  223. #ifndef QUIETBOOKGEN
  224.     printf (CP[75], s);
  225.     bkdisplay (s, cnt, moveno);
  226. #endif
  227.     return (false);
  228. }
  229.  
  230. void
  231. RESET (void)
  232.  
  233.      /*
  234.       * Reset the board and other variables to start a new game.
  235.       */
  236.  
  237. {
  238.     short int l;
  239.  
  240.     flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
  241.     flag.material = flag.coords = flag.hash = flag.easy = flag.rcptr = true;
  242.     flag.beep = true;
  243.     flag.stars = flag.shade = flag.back = flag.musttimeout = false;
  244.     flag.gamein = false;
  245.     GenCnt = epsquare = 0;
  246.     GameCnt = 0;
  247.     Developed[white] = Developed[black] = false;
  248.     castld[white] = castld[black] = false;
  249.     PawnThreat[0] = CptrFlag[0] = false;
  250.     opponent = white;
  251.     computer = black;
  252.     for (l = 0; l < 64; l++)
  253.       {
  254.       board[l] = Stboard[l];
  255.       color[l] = Stcolor[l];
  256.       Mvboard[l] = 0;
  257.       }
  258.     InitializeStats ();
  259. /*    hashbd = hashkey = 0;*/
  260. }
  261.  
  262. int
  263. Vparse (FILE * fd, unsigned short *mv, short int side, char *opening, int moveno)
  264. {
  265.     register int c, i;
  266.     char s[128];
  267.     char *p;
  268.  
  269.     while (true)
  270.       {
  271.  
  272.       while ((c = getc (fd)) == ' ' || c == '\n');
  273.       if (c == '\r')
  274.           continue;
  275.       i = 0;
  276.       if (c == '!')
  277.         {            /* comment */
  278.         p = opening;
  279.         do
  280.           {
  281.               *p++ = c;
  282.               c = getc (fd);
  283.               if (c == '\r')
  284.               continue;
  285.               /* goes to end of line */
  286.               if (c == '\n')
  287.             {
  288.                 *p = '\0';
  289.                 return 0;
  290.               } if (c == EOF)
  291.               return -1;
  292.           }
  293.         while (true);
  294.         }
  295.       /* is it a move number or analysis ( in [ ] ) */
  296.       /* number cannot start with a 0 because of 0-0 */
  297.       else if (!isalpha (c) && c != '0')
  298.         {
  299.         int nonspace = false;
  300.  
  301.         /* analysis */
  302.         if (c == '[')
  303.           {
  304.               /* scan to ] */
  305.               while ((c = getc (fd)) != ']')
  306.             {
  307.                 if (c == EOF)
  308.                 return -1;
  309.             } continue;
  310.           }
  311.         while (true)
  312.           {
  313.               c = getc (fd);
  314.               if (c == '\r')
  315.               continue;
  316.               if (c == '\n')
  317.               return 0;
  318.               if (c == EOF)
  319.             {
  320.                 return -1;
  321.             }
  322.               /* stop at first nonspace a ... is space */
  323.               /* must be nonspace because of 0-0 */
  324.               if (nonspace)
  325.             {
  326.                 if (c != '.' && c != ' ')
  327.                 break;
  328.             }
  329.               if (c == '.')
  330.             {
  331.                 nonspace = true;
  332.             }
  333.               /* stop if alpha must be move */
  334.               else if (isalpha (c))
  335.               break;
  336.           }
  337.         }
  338.       s[0] = (char) c;
  339.       while ((c = getc (fd)) != '?' && c != '+' && c != ' ' && c != '\n' && c != '\t' && c != EOF)
  340.         {
  341.         if (c == '\r')
  342.             continue;
  343.         if (c != 'x')
  344.             s[++i] = c;
  345.         }
  346.       s[++i] = '\0';
  347.  
  348.       if (c == EOF)
  349.           return (-1);
  350.       if (s[0] == '!' || s[0] == ';')
  351.         {
  352.         while (c != '\n' && c != EOF)
  353.             c = getc (fd);
  354.         if (c == EOF)
  355.             return -1;
  356.         else
  357.             return (0);
  358.         }
  359.       if ((strcmp (s, "o-o-o") == 0) || (strcmp (s, "OOO") == 0) || (strcmp (s, "O-O-O") == 0) || (strcmp (s, "0-0-0") == 0))
  360.         {
  361.         if (side == black)
  362.             strcpy (s, "e8c8");
  363.         else
  364.             strcpy (s, "e1c1");
  365.         }
  366.       else if ((strcmp ("o-o", s) == 0) || (strcmp (s, "OO") == 0) || (strcmp (s, "O-O") == 0) || (strcmp (s, "0-0") == 0))
  367.         {
  368.         if (side == black)
  369.             strcpy (s, "e8g8");
  370.         else
  371.             strcpy (s, "e1g1");
  372.         }
  373.       else if (strcmp (s, "draw") == 0)
  374.           continue;
  375.       else if (strcmp (s, "1-0") == 0)
  376.           continue;
  377.       else if (strcmp (s, "0-1") == 0)
  378.           continue;
  379.       if (isupper (s[i - 1]))
  380.           s[i - 1] = tolower (s[i - 1]);
  381.  
  382.       bhashkey = hashkey;
  383.       bhashbd = hashbd;
  384.  
  385.       i = BVerifyMove (s, mv, i);
  386.       if (c == '?')
  387.         {            /* Bad move, not for the program to play */
  388.         *mv |= BADMOVE;    /* Flag it ! */
  389.         c = getc (fd);
  390.         }
  391.       else if (c == '+' || c == '\r')
  392.           c = getc (fd);
  393.       if (!i)
  394.         {
  395.         printf ("%s \n", opening);
  396.         /* flush to start of next */
  397.         while ((c = getc (fd)) != '!' && c != EOF);
  398.         if (c == EOF)
  399.             return -1;
  400.         else
  401.           {
  402.               ungetc (c, fd);
  403.               return i;
  404.           }
  405.         }
  406.       return (i);
  407.       }
  408. }
  409.  
  410. struct gdxadmin
  411. {
  412.     unsigned int bookcount;
  413.     unsigned int booksize;
  414.     unsigned long maxoffset;
  415. } ADMIN, B;
  416.  
  417. struct gdxdata
  418. {
  419.     unsigned long hashbd;
  420.     unsigned short hashkey;
  421.     unsigned short bmove;
  422.     unsigned short hint;
  423.     unsigned short count;
  424. } DATA;
  425.  
  426. #define lts(x) (((x>>16)&0xfffe)|side)
  427. unsigned long currentoffset;
  428. int gfd;
  429.  
  430. void
  431. GetOpenings (void)
  432.  
  433.      /*
  434.       * Read in the Opening Book file and parse the algebraic notation for a move
  435.       * into an unsigned integer format indicating the from and to square. Create
  436.       * a linked list of opening lines of play, with entry->next pointing to the
  437.       * next line and entry->move pointing to a chunk of memory containing the
  438.       * moves. More Opening lines of up to 100 half moves may be added to
  439.       * gnuchess.book. But now its a hashed table by position which yields a move
  440.       * or moves for each position. It no longer knows about openings per say only
  441.       * positions and recommended moves in those positions.
  442.       */
  443. {
  444.     register short int i;
  445.     char opening[256];
  446.     char msg[256];
  447.     int mustwrite = false;
  448.     unsigned short xside, doit, side;
  449.     short int c;
  450.     unsigned short mv;
  451.     unsigned short ix;
  452.     unsigned int x;
  453.     unsigned int games = 0;
  454.  
  455.     FILE *fd;
  456.     if (binbookfile != NULL)
  457.       {
  458.       /* open book as writer */
  459.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  460.       if (gfd >= 0)
  461.         {
  462.         read (gfd, &ADMIN, sizeof (struct gdxadmin));
  463.         B.bookcount = ADMIN.bookcount;
  464.         B.booksize = ADMIN.booksize;
  465.         B.maxoffset = ADMIN.maxoffset;
  466.                 if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  467.           {
  468.               printf ("bad format %s\n", binbookfile);
  469.               exit (1);
  470.           }
  471.  
  472.         }
  473.       else
  474.         {
  475.         B.bookcount = 0;
  476.         B.booksize = booksize;
  477.  
  478.         }
  479.  
  480.       sprintf (msg, CP[213], B.bookcount, B.booksize);
  481.       ShowMessage (msg);
  482.       }
  483.     /* set every thing back to start game */
  484.     Book = BOOKFAIL;
  485.     RESET ();
  486.     /* now get ready to play */
  487.     if (!B.bookcount)
  488.       {
  489.       ShowMessage (CP[212]);
  490.       Book = 0;
  491.       }
  492. }
  493.  
  494.  
  495. int
  496. OpeningBook (unsigned short *hint, short int side)
  497.  
  498.      /*
  499.       * Go thru each of the opening lines of play and check for a match with the
  500.       * current game listing. If a match occurs, generate a random number. If this
  501.       * number is the largest generated so far then the next move in this line
  502.       * becomes the current "candidate". After all lines are checked, the
  503.       * candidate move is put at the top of the Tree[] array and will be played by
  504.       * the program. Note that the program does not handle book transpositions.
  505.       */
  506.  
  507. {
  508.     unsigned short r, m;
  509.     int possibles = TrPnt[2] - TrPnt[1];
  510.  
  511.     gsrand ((unsigned int) time ((long *) 0));
  512.     m = 0;
  513.  
  514.     /*
  515.      * find all the moves for this position  - count them and get their
  516.      * total count
  517.      */
  518.     {
  519.     register unsigned short i, x;
  520.     register unsigned short rec = 0;
  521.     register unsigned short summ = 0;
  522.     register unsigned short h = 0, b = 0;
  523.     struct gdxdata OBB[128];
  524.     if (B.bookcount == 0)
  525.       {
  526.           Book--;
  527.           return false;
  528.       }
  529.         currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  530.     x = 0;
  531.     lseek (gfd, currentoffset, SEEK_SET);
  532.     while (true)
  533.       {
  534.           if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0) break;
  535.           if (OBB[x].bmove == 0) break;
  536.  
  537.  
  538.           if (OBB[x].hashkey == (unsigned short)(lts(hashkey)) && OBB[x].hashbd == hashbd)
  539.         {
  540.             x++;if(OBB[x-1].bmove & LASTMOVE) break;
  541.         }
  542.         currentoffset += sizeof (struct gdxdata); 
  543.           if (currentoffset > B.maxoffset){
  544.           lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
  545.           currentoffset = sizeof (struct gdxadmin); 
  546.         }
  547.  
  548.       }
  549.     if (x == 0)
  550.       {
  551.           Book--;
  552.           return false;
  553.       }
  554.     for (i = 0; i < x; i++)
  555.       {
  556.           if ((m = OBB[i].bmove) & BADMOVE)
  557.         {
  558.             m ^= BADMOVE;
  559.             /* is the move is in the MoveList */
  560.             for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  561.               {
  562.               if (((Tree[b].f << 8) | Tree[b].t) == m)
  563.                 {
  564.  
  565.                 if (--possibles)
  566.                     Tree[b].score = DONTUSE;
  567.                 break;
  568.                 }
  569.               }
  570.         }
  571.           else summ += OBB[i].count;
  572.       }
  573.     if (summ == 0)
  574.           {
  575.               Book--;
  576.               return false;
  577.           }
  578.  
  579.     r = (urand () % summ);
  580.     for (i = 0; i < x; i++)
  581.         if (!(OBB[i].bmove & BADMOVE) ){
  582.             if( r < OBB[i].count)
  583.                 {
  584.                 rec = i;
  585.                 break;
  586.                 }
  587.               else
  588.               r -= OBB[i].count;
  589.         } 
  590.  
  591.     h = ((OBB[rec].hint) & 0x3f3f);
  592.     m = ((OBB[rec].bmove) & 0x3f3f);
  593.     /* make sure the move is in the MoveList */
  594.     for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  595.       {
  596.           if (((Tree[b].f << 8) | Tree[b].t) == m)
  597.         {
  598.             Tree[b].flags |= book;
  599.             Tree[b].score = 0;
  600.             break;
  601.         }
  602.       }
  603.     /* Make sure its the best */
  604.  
  605.     pick (TrPnt[1], TrPnt[2] - 1);
  606.     if (Tree[TrPnt[1]].score)
  607.       {
  608.           /* no! */
  609.           Book--;
  610.           return false;
  611.       }
  612.     /* ok pick up the hint and go */
  613.     *hint = h;
  614.     return true;
  615.     }
  616.     Book--;
  617.     return false;
  618. }
  619.