home *** CD-ROM | disk | FTP | other *** search
- /*
- * book.c - C source for GNU CHESS
- *
- * Copyright (c) 1988,1989,1990 John Stanback
- * Copyright (c) 1992 Free Software Foundation
- *
- * This file is part of GNU CHESS.
- *
- * GNU Chess is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Chess is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Chess; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include "gnuchess.h"
-
- unsigned int urand (void);
-
- extern char mvstr[4][6];
- int __aligned bookcount = 0;
- static struct bookentry
- {
- unsigned long bookkey;
- unsigned long bookbd;
- unsigned INTSIZE2 bmove;
- unsigned INTSIZE2 hint;
- unsigned char count;
- unsigned char flags;
- } __aligned *OpenBook=(struct bookentry *)0L;
- static struct bookentry __aligned *BookTable[BKTBLSIZE];
- int __aligned whichbookloaded=-1;
-
- void
- GetOpenings (op_option)
- int op_option;
-
- /*
- * Read in the Opening Book file and parse the algebraic notation for a move
- * into an unsigned integer format indicating the from and to square. Create
- * a linked list of opening lines of play, with entry->next pointing to the
- * next line and entry->move pointing to a chunk of memory containing the
- * moves. More Opening lines of up to 100 half moves may be added to
- * gnuchess.book.
- * But now its a hashed table by position which yields a move or moves for
- * each position. It no longer knows about openings per say only positions
- * and recommended moves in those positions.
- */
- #ifndef BOOK
- #define BOOK "/usr/games/lib/gnuchess.book"
- #endif /* BOOK */
- {
- FILE *fd;
- REG struct bookentry *OB, *OC;
- REG INTSIZE int i, f, t;
- char opening[80];
- char msg[80];
- INTSIZE int xside, doit, c, side;
- INTSIZE int rf, rt;
- unsigned INTSIZE mv;
- #ifndef AMIGA
- int bs;
- unsigned long ltmp;
- #endif
-
- /* allocate space for the book */
- if (whichbookloaded == op_option)
- return;
- if (!OpenBook)
- OpenBook = (struct bookentry *) malloc(BOOKSIZE*sizeof(struct bookentry));
- if (!OpenBook)
- {
- ShowMessage("Unable to alloc book");
- return;
- }
- ClearMem(OpenBook,BOOKSIZE*sizeof(struct bookentry));
- bookcount = 0;
- for (i = 0; i < BKTBLSIZE; i++)
- {
- BookTable[i] = &OpenBook[BOOKSIZE / BKTBLSIZE * i];
- }
- for (OB = OpenBook; OB < &OpenBook[BOOKSIZE]; OB++)
- OB->count = 0;
- if (op_option == white)
- {
- if ((fd = fopen ("uchess:uchesswhite.book", "r")) == NULL)
- {
- fd = fopen ("uchess:uchess.book", "r");
- op_option = 2;
- }
- }
- else
- {
- if ((fd = fopen ("uchess:uchessblack.book", "r")) == NULL)
- {
- fd = fopen ("uchess:uchess.book", "r");
- op_option = 2;
- }
- }
-
- if (fd != NULL)
- {
- whichbookloaded = -1;
- ShowMessage("Loading Book..");
- ShowMessage("Please Wait...");
- OC = NULL;
- /*setvbuf(fd,buffr,_IOFBF,2048);*/
- side = white;
- xside = black;
- hashbd = hashkey = 0;
- for (i = 0; i < 64; i++)
- {
- board[i] = Stboard[i];
- color[i] = Stcolor[i];
- }
- i = 0;
-
- while ((c = parse (fd, &mv, side, opening)) >= 0)
- if (c == 1)
- {
-
- /*
- * if not first move of an opening and first time we have
- * seen it save next move as hint
- */
- if (i && OB->count == 1)
- OB->hint = mv & 0x3f3f;
- OC = OB; /* save for end marking */
- doit = true;
-
- /*
- * see if this position and move already exist from some
- * other opening
- */
- /* is this ethical, to offer the bad move as a hint????? */
- for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
- {
- if (OB->bookkey == hashkey
- && OB->bookbd == hashbd
- && (OB->flags & SIDEMASK) == side
- && OB->bmove == mv)
- {
-
- /*
- * yes so just bump count - count is used to choose
- * opening move in proportion to its presence in the
- * book
- */
- doit = false;
- OB->count++;
- if (OB->count < 1)
- OB->count--;
- break;
- }
- /* Book is hashed into BKTBLSIZE chunks based on hashkey */
- if (OB == &OpenBook[BOOKSIZE - 1])
- OB = OpenBook;
- }
- /* doesn`t exist so add it to the book */
- if (doit)
- {
- bookcount++;
- OB->bookkey = hashkey;
- OB->bookbd = hashbd;
- OB->bmove = mv;
- OB->hint = 0;
- OB->count = 1;
- OB->flags = side;
- }
- /* now update the board and hash values */
- /* should really check the moves as we do this, but??? */
- f = mv >> 8 & 0x3F;
- t = mv & 0x3F;
- if (board[t] != no_piece)
- {
- if (color[t] != xside)
- {
- algbr (f, t, false);
- sprintf (msg, CP[211], i + 1, mvstr, opening);
- ShowMessage (msg);
- }
- UpdateHashbd (xside, board[t], -1, t);
- }
- if (board[f] == no_piece || color[f] != side)
- {
- algbr (f, t, false);
- sprintf (msg, CP[211], i + 1, mvstr, opening);
- ShowMessage (msg);
- }
- UpdateHashbd (side, board[f], f, t);
- board[t] = board[f];
- color[t] = color[f];
- color[f] = neutral;
- board[f] = no_piece;
- if ((board[t] == king) && ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE)))
- {
-
- if (t > f)
- {
- rf = f + 3;
- rt = t - 1;
- }
- else
- {
- rf = f - 4;
- rt = t + 1;
- }
- board[rt] = rook;
- color[rt] = side;
- board[rf] = no_piece;
- color[rf] = neutral;
- UpdateHashbd (side, rook, rf, rt);
- }
- i++;
- xside = side;
- side = side ^ 1;
- }
- else if (c == 0 && i > 0)
- {
- /* Mark last move as end of an opening */
- /* might want to terminate? */
- OB->flags |= BOOKEND;
- if (i > 1)
- OC->flags |= BOOKEND;
- /* reset for next opening */
- side = white;
- hashbd = hashkey = 0;
- for (i = 0; i < 64; i++)
- {
- board[i] = Stboard[i];
- color[i] = Stcolor[i];
- }
- i = 0;
-
- }
- fclose (fd);
- #ifdef BINBOOK
- fd = fopen (BINBOOK, "w");
- fprintf(fd, "%d\n%d\n", BOOKSIZE, bookcount);
- if(0>fwrite(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
- ShowMessage("fwrite");
- fclose (fd);
- #endif
- #if !defined CHESSTOOL && !defined XBOARD
- ShowMessage(" ");
- ShowMessage(" ");
- ShowMessage(" ");
- ShowMessage(" ");
- ShowMessage(" ");
- if (op_option == white)
- ShowMessage("White Book");
- else if (op_option == black)
- ShowMessage("Black Book");
- else
- ShowMessage("NOptml Book");
- sprintf (msg, CP[213], bookcount, BOOKSIZE);
- ShowMessage (msg);
- whichbookloaded = op_option;
- #endif
- /* set every thing back to start game */
- Book = BOOKFAIL;
- for (i = 0; i < 64; i++)
- {
- board[i] = Stboard[i];
- color[i] = Stcolor[i];
- }
- }
- else
- {
- #if !defined CHESSTOOL && !defined XBOARD
- ShowMessage (CP[212]);
- #endif
- Book = 0;
- }
- }
-
-
- int
- OpeningBook (unsigned INTSIZE *hint, INTSIZE int side)
-
- /*
- * Go thru each of the opening lines of play and check for a match with the
- * current game listing. If a match occurs, generate a random number. If this
- * number is the largest generated so far then the next move in this line
- * becomes the current "candidate". After all lines are checked, the
- * candidate move is put at the top of the Tree[] array and will be played by
- * the program. Note that the program does not handle book transpositions.
- */
-
- {
- INTSIZE pnt;
- unsigned INTSIZE m;
- unsigned r, cnt, tcnt, ccnt;
- REG struct bookentry *OB, *OC;
- int possibles = TrPnt[2] - TrPnt[1];
-
- gsrand ((unsigned int) time ((long *) 0));
- m = 0;
- cnt = 0;
- tcnt = 0;
- ccnt = 0;
- OC = NULL;
-
-
- /*
- * find all the moves for this position - count them and get their total
- * count
- */
- for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
- {
- if (OB->bookkey == hashkey
- && OB->bookbd == hashbd
- && ((OB->flags) & SIDEMASK) == side)
- {
- if (OB->bmove & BADMOVE)
- {
- m = OB->bmove ^ BADMOVE;
- /* is the move is in the MoveList */
- for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
- {
- if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
- {
- if (--possibles)
- {
- Tree[pnt].score = DONTUSE;
- break;
- }
- }
- }
-
- }
- else
- {
- OC = OB;
- cnt++;
- tcnt += OB->count;
- }
- }
- }
- /* if only one just do it */
- if (cnt == 1)
- {
- m = OC->bmove;
- }
- else
- /* more than one must choose one at random */
- if (cnt > 1)
- {
- /* pick a number */
- r = urand () % 1000;
-
- for (OC = BookTable[hashkey & BOOKMASK]; OC->count; OC++)
- {
- if (OC->bookkey == hashkey
- && OC->bookbd == hashbd
- && ((OC->flags) & SIDEMASK) == side
- && !(OC->bmove & BADMOVE))
- {
- ccnt += OC->count;
- if (((ccnt * BOOKRAND) / tcnt) >= r)
- {
- m = OC->bmove;
- break;
- }
- }
- }
- }
- else
- {
- /* none decrement count of no finds */
- Book--;
- return false;
- }
- /* make sure the move is in the MoveList */
- for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
- {
- if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
- {
- Tree[pnt].flags |= book;
- Tree[pnt].score = 0;
- break;
- }
- }
- /* Make sure its the best */
-
- pick (TrPnt[1], TrPnt[2] - 1);
- if (Tree[TrPnt[1]].score)
- {
- /* no! */
- Book--;
- return false;
- }
- /* ok pick up the hint and go */
- *hint = OC->hint;
- Book = ((OC->flags & BOOKEND) && ((urand () % 1000) > BOOKENDPCT)) ? 0 : BOOKFAIL;
- return true;
- }
-