home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 5 / ctrom5b.zip / ctrom5b / OS2 / SPEL / UCHESS / UCHESSRC / BOOK.C < prev    next >
Text File  |  1994-10-23  |  10KB  |  406 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback
  5.  * Copyright (c) 1992 Free Software Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2, or (at your option)
  12.  * any later version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with GNU Chess; see the file COPYING.  If not, write to
  21.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include "gnuchess.h"
  25.  
  26. unsigned int urand (void);
  27.  
  28. extern char mvstr[8][8];
  29. int __aligned bookcount = 0;
  30. static struct bookentry
  31. {
  32.   unsigned long bookkey;
  33.   unsigned long bookbd;
  34.   unsigned INTSIZE2 bmove;
  35.   unsigned INTSIZE2 hint;
  36.   unsigned char count;
  37.   unsigned char flags;
  38. } __aligned *OpenBook=(struct bookentry *)0L;
  39. static struct bookentry __aligned *BookTable[BKTBLSIZE];
  40. int __aligned whichbookloaded=-1;
  41.  
  42. void
  43. GetOpenings (op_option)
  44. int op_option;
  45.  
  46. /*
  47.  * Read in the Opening Book file and parse the algebraic notation for a move
  48.  * into an unsigned integer format indicating the from and to square. Create
  49.  * a linked list of opening lines of play, with entry->next pointing to the
  50.  * next line and entry->move pointing to a chunk of memory containing the
  51.  * moves. More Opening lines of up to 100 half moves may be added to
  52.  * gnuchess.book.
  53.  * But now its a hashed table by position which yields a move or moves for 
  54.  * each position. It no longer knows about openings per say only positions
  55.  * and recommended moves in those positions.
  56.  */
  57. #ifndef BOOK
  58. #define BOOK "/usr/games/lib/gnuchess.book"
  59. #endif /* BOOK */
  60. {
  61.   FILE *fd;
  62.   REG struct bookentry *OB, *OC;
  63.   REG INTSIZE int i, f, t;
  64.   char opening[80];
  65.   char msg[80];
  66.   INTSIZE int xside, doit, c, side;
  67.   INTSIZE int rf, rt;
  68.   unsigned INTSIZE mv;
  69. #ifndef AMIGA
  70. //  int bs;
  71. //  unsigned long ltmp;
  72. #endif
  73.  
  74.   /* allocate space for the book */
  75.   if (whichbookloaded == op_option)
  76.    return;
  77.   if (!OpenBook)
  78.    OpenBook = (struct bookentry *) malloc(BOOKSIZE*sizeof(struct bookentry));
  79.   if (!OpenBook)
  80.    {
  81.     ShowMessage("Unable to alloc book");
  82.     return;
  83.    }
  84.   ClearMem(OpenBook,BOOKSIZE*sizeof(struct bookentry));
  85.   bookcount = 0;
  86.   for (i = 0; i < BKTBLSIZE; i++)
  87.     {
  88.       BookTable[i] = &OpenBook[BOOKSIZE / BKTBLSIZE * i];
  89.     }
  90.   for (OB = OpenBook; OB < &OpenBook[BOOKSIZE]; OB++)
  91.     OB->count = 0;
  92.   if (op_option == white)
  93.    {
  94.     if ((fd = fopen ("uchessw.bok", "r")) == NULL)
  95.      {
  96.       fd = fopen ("uchess.bok", "r");
  97.       op_option = 2;
  98.      }
  99.    }
  100.   else
  101.    {
  102.     if ((fd = fopen ("uchessb.bok", "r")) == NULL)
  103.      {
  104.       fd = fopen ("uchess.bok", "r");
  105.       op_option = 2;
  106.      }
  107.    }
  108.   
  109.   if (fd != NULL)
  110.     {
  111.       whichbookloaded = -1;
  112.       ShowMessage("Loading Book..");
  113.       ShowMessage("Please Wait...");
  114.       OC = NULL;
  115.       /*setvbuf(fd,buffr,_IOFBF,2048);*/ 
  116.       side = white;
  117.       xside = black;
  118.       hashbd = hashkey = 0;
  119.       for (i = 0; i < 64; i++)
  120.     {
  121.       board[i] = Stboard[i];
  122.       color[i] = Stcolor[i];
  123.     }
  124.       i = 0;
  125.  
  126.       while ((c = parse (fd, &mv, side, opening)) >= 0)
  127.     if (c == 1)
  128.       {
  129.  
  130.         /*
  131.          * if not first move of an opening and first time we have
  132.          * seen it save next move as hint
  133.          */
  134.         if (i && OB->count == 1)
  135.           OB->hint = mv & 0x3f3f;
  136.         OC = OB;            /* save for end marking */
  137.         doit = true;
  138.  
  139.         /*
  140.          * see if this position and move already exist from some
  141.          * other opening
  142.          */
  143.         /* is this ethical, to offer the bad move as a hint????? */
  144.         for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  145.           {
  146.         if (OB->bookkey == hashkey
  147.             && OB->bookbd == hashbd
  148.             && (OB->flags & SIDEMASK) == side
  149.             && OB->bmove == mv)
  150.           {
  151.             
  152.             /*
  153.              * yes so just bump count - count is used to choose
  154.              * opening move in proportion to its presence in the
  155.              * book
  156.              */
  157.             doit = false;
  158.             OB->count++;
  159.             if (OB->count < 1)
  160.               OB->count--;
  161.             break;
  162.           }
  163.         /* Book is hashed into BKTBLSIZE chunks based on hashkey */
  164.         if (OB == &OpenBook[BOOKSIZE - 1])
  165.           OB = OpenBook;
  166.           }
  167.         /* doesn`t exist so add it to the book */
  168.         if (doit)
  169.           {
  170.         bookcount++;
  171.         OB->bookkey = hashkey;
  172.         OB->bookbd = hashbd;
  173.         OB->bmove = mv;
  174.         OB->hint = 0;
  175.         OB->count = 1;
  176.         OB->flags = side;
  177.           }
  178.         /* now update the board and hash values */
  179.         /* should really check the moves as we do this, but??? */
  180.         f = mv >> 8 & 0x3F;
  181.         t = mv & 0x3F;
  182.         if (board[t] != no_piece)
  183.           {
  184.         if (color[t] != xside)
  185.           {
  186.             algbr (f, t, false);
  187.             sprintf (msg, CP[211], i + 1, mvstr, opening);
  188.             ShowMessage (msg);
  189.           }
  190.                 UpdateHashbd2 (xside, board[t], -1, t); // this macro generates unreachable code when -1
  191.           }
  192.         if (board[f] == no_piece || color[f] != side)
  193.           {
  194.         algbr (f, t, false);
  195.         sprintf (msg, CP[211], i + 1, mvstr, opening);
  196.         ShowMessage (msg);
  197.           }
  198.         UpdateHashbd (side, board[f], f, t);
  199.         board[t] = board[f];
  200.         color[t] = color[f];
  201.         color[f] = neutral;
  202.         board[f] = no_piece;
  203.         if ((board[t] == king) && ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE)))
  204.           {
  205.  
  206.         if (t > f)
  207.           {
  208.             rf = f + 3;
  209.             rt = t - 1;
  210.           }
  211.         else
  212.           {
  213.             rf = f - 4;
  214.             rt = t + 1;
  215.           }
  216.         board[rt] = rook;
  217.         color[rt] = side;
  218.         board[rf] = no_piece;
  219.         color[rf] = neutral;
  220.         UpdateHashbd (side, rook, rf, rt);
  221.           }
  222.         i++;
  223.         xside = side;
  224.         side = side ^ 1;
  225.       }
  226.     else if (c == 0 && i > 0)
  227.       {
  228.         /* Mark last move as end of an opening */
  229.         /* might want to terminate? */
  230.         OB->flags |= BOOKEND;
  231.         if (i > 1)
  232.           OC->flags |= BOOKEND;
  233.         /* reset for next opening */
  234.         side = white;
  235.         hashbd = hashkey = 0;
  236.         for (i = 0; i < 64; i++)
  237.           {
  238.         board[i] = Stboard[i];
  239.         color[i] = Stcolor[i];
  240.           }
  241.         i = 0;
  242.  
  243.       }
  244.       fclose (fd);
  245. #ifdef BINBOOK
  246.       fd = fopen (BINBOOK, "w");
  247.       fprintf(fd, "%d\n%d\n", BOOKSIZE, bookcount);
  248.       if(0>fwrite(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  249.     ShowMessage("fwrite");
  250.       fclose (fd);
  251. #endif
  252. #if !defined CHESSTOOL && !defined XBOARD
  253.       ShowMessage("  ");
  254.       ShowMessage("  ");
  255.       ShowMessage("  ");
  256.       ShowMessage("  ");
  257.       ShowMessage("  ");
  258.       if (op_option == white)
  259.        ShowMessage("White Book");
  260.       else if (op_option == black)
  261.        ShowMessage("Black Book");
  262.       else
  263.        ShowMessage("NOptml Book");
  264.       sprintf (msg, CP[213], bookcount, BOOKSIZE);
  265.       ShowMessage (msg);
  266.       whichbookloaded = op_option;
  267. #endif
  268.       /* set every thing back to start game */
  269.       Book = BOOKFAIL;
  270.       for (i = 0; i < 64; i++)
  271.     {
  272.       board[i] = Stboard[i];
  273.       color[i] = Stcolor[i];
  274.     }
  275.     }
  276.   else
  277.     {
  278. #if !defined CHESSTOOL && !defined XBOARD
  279.       ShowMessage (CP[212]);
  280. #endif
  281.       Book = 0;
  282.     }
  283. }
  284.  
  285.  
  286. int
  287. OpeningBook (unsigned INTSIZE *hint, INTSIZE int side)
  288.      
  289. /*
  290.  * Go thru each of the opening lines of play and check for a match with the
  291.  * current game listing. If a match occurs, generate a random number. If this
  292.  * number is the largest generated so far then the next move in this line
  293.  * becomes the current "candidate". After all lines are checked, the
  294.  * candidate move is put at the top of the Tree[] array and will be played by
  295.  * the program. Note that the program does not handle book transpositions.
  296.  */
  297.  
  298. {
  299.   INTSIZE pnt;
  300.   unsigned INTSIZE m;
  301.   unsigned r, cnt, tcnt, ccnt;
  302.   REG struct bookentry *OB, *OC;
  303.   int possibles = TrPnt[2] - TrPnt[1];
  304.  
  305.   gsrand ((unsigned int) time (0L));
  306.   m = 0;
  307.   cnt = 0;
  308.   tcnt = 0;
  309.   ccnt = 0;
  310.   OC = NULL;
  311.   
  312.  
  313.   /*
  314.    * find all the moves for this position  - count them and get their total
  315.    * count
  316.    */
  317.   for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  318.     {
  319.       if (OB->bookkey == hashkey
  320.       && OB->bookbd == hashbd
  321.       && ((OB->flags) & SIDEMASK) == side)
  322.     {
  323.       if (OB->bmove & BADMOVE)
  324.         {
  325.           m = OB->bmove ^ BADMOVE;
  326.           /* is the move is in the MoveList */
  327.           for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  328.         {
  329.           if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  330.             {
  331.               if (--possibles)
  332.             {
  333.               Tree[pnt].score = DONTUSE;
  334.               break;
  335.             }
  336.             }
  337.         }
  338.  
  339.         }
  340.       else
  341.         {
  342.           OC = OB;
  343.           cnt++;
  344.           tcnt += OB->count;
  345.         }
  346.     }
  347.     }
  348.   /* if only one just do it */
  349.   if (cnt == 1)
  350.     {
  351.       m = OC->bmove;
  352.     }
  353.   else
  354.     /* more than one must choose one at random */
  355.   if (cnt > 1)
  356.     {
  357.       /* pick a number */
  358.       r = urand () % 1000;
  359.  
  360.       for (OC = BookTable[hashkey & BOOKMASK]; OC->count; OC++)
  361.     {
  362.       if (OC->bookkey == hashkey
  363.           && OC->bookbd == hashbd
  364.           && ((OC->flags) & SIDEMASK) == side
  365.           && !(OC->bmove & BADMOVE))
  366.         {
  367.           ccnt += OC->count;
  368.           if (((ccnt * BOOKRAND) / tcnt) >= r)
  369.         {
  370.           m = OC->bmove;
  371.           break;
  372.         }
  373.         }
  374.     }
  375.     }
  376.   else
  377.     {
  378.       /* none decrement count of no finds */
  379.       Book--;
  380.       return false;
  381.     }
  382.   /* make sure the move is in the MoveList */
  383.   for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  384.     {
  385.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  386.     {
  387.       Tree[pnt].flags |= book;
  388.       Tree[pnt].score = 0;
  389.       break;
  390.     }
  391.     }
  392.   /* Make sure its the best */
  393.  
  394.   pick (TrPnt[1], TrPnt[2] - 1);
  395.   if (Tree[TrPnt[1]].score)
  396.     {
  397.       /* no! */
  398.       Book--;
  399.       return false;
  400.     }
  401.   /* ok pick up the hint and go */
  402.   *hint = OC->hint;
  403.   Book = ((OC->flags & BOOKEND) && ((urand () % 1000) > BOOKENDPCT)) ? 0 : BOOKFAIL;
  404.   return true;
  405. }
  406.