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
- *
- // Project: OS/2 PM Port of GNU CHESS 4.0 (PmChess)
- //
- // Version: 1994-4-17
- //
- // Porter: Revised and ported to OS/2 2.1 by Yibing Fan
- //
- // System: OS2 2.1 using emx0.8g
- //
- * 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.
- */
- #define INCL_DOS
- #define INCL_PM
- #include <os2.h>
- #include "gnuchess.h"
- #include "ataks.h"
- #include <unistd.h>
- #include <io.h>
- #include <fcntl.h>
- extern int UseBook;
- unsigned booksize = BOOKSIZE;
- unsigned int BKTBLSIZE;
- unsigned long BOOKMASK;
- unsigned bookcount = 0;
- unsigned bookpocket = BOOKPOCKET;
- static struct bookentry
- {
- unsigned long bookkey;
- unsigned long bookbd;
- unsigned short bmove;
- unsigned short hint;
- unsigned short count;
- unsigned short flags;
- } *OBEND;
- struct bookentry *OpenBook = NULL;
- static struct bookentry **BookTable;
-
- unsigned short bookmaxply = BOOKMAXPLY;
-
- char *bookfile = NULL;
- char *binbookfile = BINBOOK;
-
- int GotBook = false;
- static char bmvstr[4][6];
- unsigned long bhashbd, bhashkey;
-
- #define pxx " PNBRQK"
- #define qxx " pnbrqk"
-
-
- void
- Balgbr (short int f, short int t, short int flag)
-
-
- /*
- * Generate move strings in different formats.
- */
-
- {
- int m3p;
- bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
-
- if (f != t)
- {
- /* algebraic notation */
- bmvstr[0][0] = cxx[column (f)];
- bmvstr[0][1] = rxx[row (f)];
- bmvstr[0][2] = cxx[column (t)];
- bmvstr[0][3] = rxx[row (t)];
- bmvstr[0][4] = bmvstr[3][0] = '\0';
- if (((bmvstr[1][0] = pxx[board[f]]) == 'P') || (flag & promote))
- {
- if (bmvstr[0][0] == bmvstr[0][2]) /* pawn did not eat */
- {
- bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][2]; /* to column */
- bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][3]; /* to row */
- m3p = 2;
- }
- else
- /* pawn ate */
- {
- bmvstr[2][0] = bmvstr[1][0] = bmvstr[0][0]; /* column */
- bmvstr[2][1] = bmvstr[1][1] = bmvstr[0][2]; /* to column */
- bmvstr[2][2] = bmvstr[0][3];
- m3p = 3; /* to row */
- }
- if (flag & promote)
- {
- bmvstr[0][4] = bmvstr[1][2] = bmvstr[2][m3p] = qxx[flag & pmask];
- bmvstr[0][5] = bmvstr[1][3] = bmvstr[2][m3p + 1] = bmvstr[3][0] = '\0';
- }
- else
- bmvstr[2][m3p] = bmvstr[1][2] = '\0';
- }
- else
- /* not a pawn */
- {
- bmvstr[2][0] = bmvstr[1][0];
- bmvstr[2][1] = bmvstr[0][1];
- bmvstr[2][2] = bmvstr[1][1] = bmvstr[0][2]; /* to column */
- bmvstr[2][3] = bmvstr[1][2] = bmvstr[0][3]; /* to row */
- bmvstr[2][4] = bmvstr[1][3] = '\0';
- strcpy (bmvstr[3], bmvstr[2]);
- bmvstr[3][1] = bmvstr[0][0];
- if (flag & cstlmask)
- {
- if (t > f)
- {
- strcpy (bmvstr[1], bmvstr[0]);
- strcpy (bmvstr[0], CP[5]);
- strcpy (bmvstr[2], CP[7]);
- }
- else
- {
- strcpy (bmvstr[1], bmvstr[0]);
- strcpy (bmvstr[0], CP[6]);
- strcpy (bmvstr[2], CP[8]);
- }
- }
- }
- }
- else
- bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = bmvstr[3][0] = '\0';
- }
-
- #ifndef QUIETBOOKGEN
- void
- bkdisplay (s, cnt, moveno)
- char *s;
- int cnt;
- int moveno;
- {
- static short pnt;
- struct leaf *node;
- int r, c, l;
-
- pnt = TrPnt[2];
- printf ("matches = %d\n", cnt);
- printf ("inout move is :%s:move number %d side %s\n", s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
- #ifndef SEMIQUIETBOOKGEN
- printf ("legal moves are \n");
- while (pnt < TrPnt[3])
- {
- node = &Tree[pnt++];
- Balgbr (node->f, node->t, (short) node->flags);
- printf ("%s %s %s %s\n", bmvstr[0], bmvstr[1], bmvstr[2], bmvstr[3]);
- }
- printf ("\n current board is\n");
- for (r = 7; r >= 0; r--)
- {
- for (c = 0; c <= 7; c++)
- {
- l = locn (r, c);
- if (color[l] == neutral)
- printf (" -");
- else if (color[l] == white)
- printf (" %c", qxx[board[l]]);
- else
- printf (" %c", pxx[board[l]]);
- }
- printf ("\n");
- }
- printf ("\n\n");
- #endif
- }
-
- #endif
-
- int
- BVerifyMove (char *s, short unsigned int *mv, int moveno)
-
- /*
- * Compare the string 's' to the list of legal moves available for the
- * opponent. If a match is found, make the move on the board.
- */
-
- {
- static short pnt, tempb, tempc, tempsf, tempst, cnt;
- static struct leaf xnode;
- struct leaf *node;
-
- *mv = 0;
- cnt = 0;
- MoveList (opponent, 2);
- pnt = TrPnt[2];
- while (pnt < TrPnt[3])
- {
- node = &Tree[pnt++];
- Balgbr (node->f, node->t, (short) node->flags);
- if (strcmp (s, bmvstr[0]) == 0 || strcmp (s, bmvstr[1]) == 0 ||
- strcmp (s, bmvstr[2]) == 0 || strcmp (s, bmvstr[3]) == 0)
- {
- cnt++;
- xnode = *node;
- }
- }
- if (cnt == 1)
- {
- MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
- if (SqAtakd (PieceList[opponent][0], computer))
- {
- UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
- /* Illegal move in check */
- #ifndef QUIETBOOKGEN
- printf (CP[77]);
- printf ("\n");
- bkdisplay (s, cnt, moveno);
- #endif
- return (false);
- }
- else
- {
- *mv = (xnode.f << 8) | xnode.t;
- Balgbr (xnode.f, xnode.t, false);
- return (true);
- }
- }
- /* Illegal move */
- #ifndef QUIETBOOKGEN
- printf (CP[75], s);
- bkdisplay (s, cnt, moveno);
- #endif
- return (false);
- }
-
- void
- RESET (void)
-
- /*
- * Reset the board and other variables to start a new game.
- */
-
- {
- short int l;
-
- flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
- flag.material = flag.coords = flag.hash = flag.easy = flag.rcptr = true;
- flag.beep = true;
- flag.stars = flag.shade = flag.back = flag.musttimeout = false;
- flag.gamein = false;
- GenCnt = epsquare = 0;
- GameCnt = 0;
- Developed[white] = Developed[black] = false;
- castld[white] = castld[black] = false;
- PawnThreat[0] = CptrFlag[0] = false;
- opponent = white;
- computer = black;
- for (l = 0; l < 64; l++)
- {
- board[l] = Stboard[l];
- color[l] = Stcolor[l];
- Mvboard[l] = 0;
- }
- InitializeStats ();
- /* hashbd = hashkey = 0;*/
- }
-
- int
- Vparse (FILE * fd, unsigned short *mv, short int side, char *opening, int moveno)
- {
- register int c, i;
- char s[128];
- char *p;
-
- while (true)
- {
-
- while ((c = getc (fd)) == ' ' || c == '\n');
- if (c == '\r')
- continue;
- i = 0;
- if (c == '!')
- { /* comment */
- p = opening;
- do
- {
- *p++ = c;
- c = getc (fd);
- if (c == '\r')
- continue;
- /* goes to end of line */
- if (c == '\n')
- {
- *p = '\0';
- return 0;
- } if (c == EOF)
- return -1;
- }
- while (true);
- }
- /* is it a move number or analysis ( in [ ] ) */
- /* number cannot start with a 0 because of 0-0 */
- else if (!isalpha (c) && c != '0')
- {
- int nonspace = false;
-
- /* analysis */
- if (c == '[')
- {
- /* scan to ] */
- while ((c = getc (fd)) != ']')
- {
- if (c == EOF)
- return -1;
- } continue;
- }
- while (true)
- {
- c = getc (fd);
- if (c == '\r')
- continue;
- if (c == '\n')
- return 0;
- if (c == EOF)
- {
- return -1;
- }
- /* stop at first nonspace a ... is space */
- /* must be nonspace because of 0-0 */
- if (nonspace)
- {
- if (c != '.' && c != ' ')
- break;
- }
- if (c == '.')
- {
- nonspace = true;
- }
- /* stop if alpha must be move */
- else if (isalpha (c))
- break;
- }
- }
- s[0] = (char) c;
- while ((c = getc (fd)) != '?' && c != '+' && c != ' ' && c != '\n' && c != '\t' && c != EOF)
- {
- if (c == '\r')
- continue;
- if (c != 'x')
- s[++i] = c;
- }
- s[++i] = '\0';
-
- if (c == EOF)
- return (-1);
- if (s[0] == '!' || s[0] == ';')
- {
- while (c != '\n' && c != EOF)
- c = getc (fd);
- if (c == EOF)
- return -1;
- else
- return (0);
- }
- if ((strcmp (s, "o-o-o") == 0) || (strcmp (s, "OOO") == 0) || (strcmp (s, "O-O-O") == 0) || (strcmp (s, "0-0-0") == 0))
- {
- if (side == black)
- strcpy (s, "e8c8");
- else
- strcpy (s, "e1c1");
- }
- else if ((strcmp ("o-o", s) == 0) || (strcmp (s, "OO") == 0) || (strcmp (s, "O-O") == 0) || (strcmp (s, "0-0") == 0))
- {
- if (side == black)
- strcpy (s, "e8g8");
- else
- strcpy (s, "e1g1");
- }
- else if (strcmp (s, "draw") == 0)
- continue;
- else if (strcmp (s, "1-0") == 0)
- continue;
- else if (strcmp (s, "0-1") == 0)
- continue;
- if (isupper (s[i - 1]))
- s[i - 1] = tolower (s[i - 1]);
-
- bhashkey = hashkey;
- bhashbd = hashbd;
-
- i = BVerifyMove (s, mv, i);
- if (c == '?')
- { /* Bad move, not for the program to play */
- *mv |= BADMOVE; /* Flag it ! */
- c = getc (fd);
- }
- else if (c == '+' || c == '\r')
- c = getc (fd);
- if (!i)
- {
- printf ("%s \n", opening);
- /* flush to start of next */
- while ((c = getc (fd)) != '!' && c != EOF);
- if (c == EOF)
- return -1;
- else
- {
- ungetc (c, fd);
- return i;
- }
- }
- return (i);
- }
- }
-
- struct gdxadmin
- {
- unsigned int bookcount;
- unsigned int booksize;
- unsigned long maxoffset;
- } ADMIN, B;
-
- struct gdxdata
- {
- unsigned long hashbd;
- unsigned short hashkey;
- unsigned short bmove;
- unsigned short hint;
- unsigned short count;
- } DATA;
-
- #define lts(x) (((x>>16)&0xfffe)|side)
- unsigned long currentoffset;
- int gfd;
-
- void
- GetOpenings (HWND hWnd)
-
- /*
- * 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.
- */
- {
- register short int i;
- char opening[256];
- char msg[256];
- int mustwrite = false;
- unsigned short xside, doit, side;
- short int c;
- unsigned short mv;
- unsigned short ix;
- unsigned int x;
- unsigned int games = 0;
-
- FILE *fd;
- if (binbookfile != NULL)
- {
- /* open book as writer */
- gfd = open (binbookfile, O_RDONLY | O_BINARY);
- if (gfd >= 0)
- {
- read (gfd, &ADMIN, sizeof (struct gdxadmin));
- B.bookcount = ADMIN.bookcount;
- B.booksize = ADMIN.booksize;
- B.maxoffset = ADMIN.maxoffset;
- if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
- {
- printf ("bad format %s\n", binbookfile);
- exit (1);
- }
-
- }
- else
- {
- B.bookcount = 0;
- B.booksize = booksize;
-
- }
-
- sprintf (msg, CP[213], B.bookcount, B.booksize);
- ShowMessage (hWnd, msg);
- }
- /* set every thing back to start game */
- if (UseBook) {
- Book = BOOKFAIL;
- } else {
- Book = 0;
- } /* endif */
- RESET ();
- /* now get ready to play */
- if (!B.bookcount)
- {
- ShowMessage (hWnd, "CP[212]");
- Book = 0;
- }
- }
-
-
- int
- OpeningBook (unsigned short *hint, short 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.
- */
-
- {
- unsigned short r, m;
- int possibles = TrPnt[2] - TrPnt[1];
-
- gsrand ((unsigned int) time ((long *) 0));
- m = 0;
-
- /*
- * find all the moves for this position - count them and get their
- * total count
- */
- {
- register unsigned short i, x;
- register unsigned short rec = 0;
- register unsigned short summ = 0;
- register unsigned short h = 0, b = 0;
- struct gdxdata OBB[128];
- if (B.bookcount == 0)
- {
- Book = 0;
- return false;
- }
- currentoffset = (unsigned long) (hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
- x = 0;
- lseek (gfd, currentoffset, SEEK_SET);
- while (true)
- {
- if (read (gfd, &OBB[x], sizeof (struct gdxdata)) == 0) break;
- if (OBB[x].bmove == 0) break;
-
-
- if (OBB[x].hashkey == (unsigned short)(lts(hashkey)) && OBB[x].hashbd == hashbd)
- {
- x++;if(OBB[x-1].bmove & LASTMOVE) break;
- }
- currentoffset += sizeof (struct gdxdata);
- if (currentoffset > B.maxoffset){
- lseek (gfd, sizeof (struct gdxadmin), SEEK_SET);
- currentoffset = sizeof (struct gdxadmin);
- }
-
- }
- if (x == 0)
- {
- Book = 0;
- return false;
- }
- for (i = 0; i < x; i++)
- {
- if ((m = OBB[i].bmove) & BADMOVE)
- {
- m ^= BADMOVE;
- /* is the move is in the MoveList */
- for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
- {
- if (((Tree[b].f << 8) | Tree[b].t) == m)
- {
-
- if (--possibles)
- Tree[b].score = DONTUSE;
- break;
- }
- }
- }
- else summ += OBB[i].count;
- }
- if (summ == 0)
- {
- Book = 0;
- return false;
- }
-
- r = (urand () % summ);
- for (i = 0; i < x; i++)
- if (!(OBB[i].bmove & BADMOVE) ){
- if( r < OBB[i].count)
- {
- rec = i;
- break;
- }
- else
- r -= OBB[i].count;
- }
-
- h = ((OBB[rec].hint) & 0x3f3f);
- m = ((OBB[rec].bmove) & 0x3f3f);
- /* make sure the move is in the MoveList */
- for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
- {
- if (((Tree[b].f << 8) | Tree[b].t) == m)
- {
- Tree[b].flags |= book;
- Tree[b].score = 0;
- break;
- }
- }
- /* Make sure its the best */
-
- pick (TrPnt[1], TrPnt[2] - 1);
- if (Tree[TrPnt[1]].score)
- {
- /* no! */
- Book = 0;
- return false;
- }
- /* ok pick up the hint and go */
- *hint = h;
- return true;
- }
- Book = 0;
- return false;
- }