c0c2686f4c60d55b31d8e4f5483826dab2d0f612
[gnushogi.git] / src / book.c
1 /*
2  * book.c - C source for GNU SHOGI
3  *
4  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
5  *
6  * GNU SHOGI is based on GNU CHESS
7  *
8  * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
9  * Foundation
10  *
11  * This file is part of GNU SHOGI.
12  *
13  * GNU Shogi is free software; you can redistribute it and/or modify it under
14  * the terms of the GNU General Public License as published by the Free
15  * Software Foundation; either version 1, or (at your option) any later
16  * version.
17  *
18  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT ANY
19  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
21  * details.
22  *
23  * You should have received a copy of the GNU General Public License along with
24  * GNU Shogi; see the file COPYING.  If not, write to the Free Software
25  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27
28 #include "gnushogi.h"
29 #ifdef MSDOS
30 #include <io.h>
31 #endif
32 #if !defined MSDOS && !defined THINK_C
33 #define O_BINARY 0
34 #endif
35 #include <fcntl.h>
36 #ifdef THINK_C
37 #include <unix.h>
38 /* #define BOOKTEST */
39 #endif
40
41
42 #include "book.h"
43
44
45
46 unsigned booksize = BOOKSIZE;
47 unsigned short bookmaxply = BOOKMAXPLY;
48 unsigned bookcount = 0;
49
50 #ifdef BOOK
51 char *bookfile = BOOK;
52 #else
53 char *bookfile = NULL;
54 #endif
55 #ifdef BINBOOK
56 char *binbookfile = BINBOOK;
57 #else
58 char *binbookfile = NULL;
59 #endif
60
61
62
63 static char bmvstr[3][7];
64
65 static ULONG bhashbd;
66 static ULONG bhashkey;
67
68
69 void
70 Balgbr (short int f, short int t, short int flag)
71
72
73      /*
74       * Generate move strings in different formats.
75       */
76
77 {
78   short promoted = false;
79
80   if ( (f & 0x80) != 0)
81     {                
82       f &= 0x7f;
83       promoted = true;
84     }
85
86   if ( f > NO_SQUARES ) 
87     { short piece;
88       piece = f - NO_SQUARES;
89       if ( f > (NO_SQUARES+NO_PIECES) )
90         piece -= NO_PIECES;
91       flag = (dropmask | piece); 
92     }
93   if ( (t & 0x80) != 0 )
94     {
95       flag |= promote;
96       t &= 0x7f;
97     }
98   if ( f == t && (f != 0 || t != 0) ) 
99     { 
100 #if !defined XSHOGI
101       char buffer[80];
102       sprintf(buffer,"error in algbr: FROM=TO=%d, flag=0x%4x\n",t,flag);
103       ShowMessage(buffer);
104 #endif
105       bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
106     }
107   else
108   if ( (flag & dropmask) != 0 )
109     {
110       /* bmvstr[0]: P*3c bmvstr[1]: P'3c */ 
111       short piece = flag & pmask;
112       bmvstr[0][0] = pxx[piece];
113       bmvstr[0][1] = '*';
114       bmvstr[0][2] = cxx[column (t)];
115       bmvstr[0][3] = rxx[row (t)];
116       bmvstr[0][4] = bmvstr[2][0] = '\0';
117       strcpy (bmvstr[1], bmvstr[0]);
118       bmvstr[1][1] = '\'';
119     }
120   else
121   if (f != 0 || t != 0)
122     {
123       /* algebraic notation */
124       /* bmvstr[0]: 7g7f bmvstr[1]: (+)P7g7f(+) bmvstr[2]: (+)P7f(+) */
125       bmvstr[0][0] = cxx[column (f)];
126       bmvstr[0][1] = rxx[row (f)];
127       bmvstr[0][2] = cxx[column (t)];
128       bmvstr[0][3] = rxx[row (t)];
129       bmvstr[0][4] = '\0';
130       if (promoted)
131         {
132           bmvstr[1][0] = bmvstr[2][0] = '+';
133           bmvstr[1][1] = bmvstr[2][1] = pxx[board[f]];
134           strcpy(&bmvstr[1][2],&bmvstr[0][0]);
135           strcpy(&bmvstr[2][2],&bmvstr[0][2]);
136         }                                  
137       else
138         {
139           bmvstr[1][0] = bmvstr[2][0] = pxx[board[f]];
140           strcpy(&bmvstr[1][1],&bmvstr[0][0]);
141           strcpy(&bmvstr[2][1],&bmvstr[0][2]);
142         }
143       if (flag & promote)
144         {
145                 strcat(bmvstr[0], "+");
146                 strcat(bmvstr[1], "+");
147                 strcat(bmvstr[2], "+");
148         }
149     }
150   else
151     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
152 }
153
154
155
156
157 #ifndef QUIETBOOKGEN
158 void
159 bkdisplay (s, cnt, moveno)
160      char *s;
161      int cnt;
162      int moveno;
163 {
164     static short pnt;
165     struct leaf far *node;
166     int r, c, l;
167
168     pnt = TrPnt[2];
169     printf ("matches = %d\n", cnt);
170     printf ("inout move is :%s: move number %d side %s\n", 
171                 s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
172 #ifndef SEMIQUIETBOOKGEN
173     printf ("legal moves are \n");
174     while (pnt < TrPnt[3])
175       {
176           node = &Tree[pnt++];
177           if ( is_promoted[board[node->f]] )
178             Balgbr (node->f | 0x80, node->t, (short) node->flags);
179           else
180             Balgbr (node->f, node->t, (short) node->flags);
181           printf ("%s %s %s\n", 
182             bmvstr[0], bmvstr[1], bmvstr[2]);
183       }
184     printf ("\n current board is\n");
185     for (r = (NO_ROWS-1); r >= 0; r--)
186         {
187           for (c = 0; c <= (NO_COLS-1); c++)
188             { char pc;
189               l = locn (r, c);
190               pc = (is_promoted[board[l]] ? '+' : ' ');
191               if (color[l] == neutral)
192                 printf (" -");
193               else if (color[l] == black)
194                 printf ("%c%c", pc, qxx[board[l]]);
195               else
196                 printf ("%c%c", pc, pxx[board[l]]);
197             }
198           printf ("\n");
199         }
200     printf ("\n");
201     {  
202         short color;
203         for (color = black; color <= white; color++)
204           { short piece, c;
205             printf((color==black)?"black ":"white ");
206             for (piece = pawn; piece <= king; piece++)
207               if (c = Captured[color][piece]) 
208                 printf("%i%c ",c,pxx[piece]);
209             printf("\n");
210           };
211     }
212 #endif /* SEMIQUIETBOOKGEN */
213 }
214
215 #endif /* QUIETBOOKGEN */
216
217 int
218 BVerifyMove (char *s, short unsigned int *mv, int moveno)
219
220      /*
221       * Compare the string 's' to the list of legal moves available for the
222       * opponent. If a match is found, make the move on the board.
223       */
224
225 {
226     static short pnt, tempb, tempc, tempsf, tempst, cnt;
227     static struct leaf xnode;
228     struct leaf far *node;
229
230     *mv = 0;
231     cnt = 0;
232     MoveList (opponent, 2, -2, true);
233     pnt = TrPnt[2];
234     while (pnt < TrPnt[3])
235       {
236           node = &Tree[pnt++];
237           if ( is_promoted[board[node->f]] )
238             Balgbr (node->f | 0x80, node->t, (short) node->flags);
239           else
240             Balgbr (node->f, node->t, (short) node->flags);
241           if (strcmp (s, bmvstr[0]) == 0 || strcmp (s, bmvstr[1]) == 0 ||
242               strcmp (s, bmvstr[2]) == 0)
243             {
244                 cnt++;
245                 xnode = *node;
246             }
247       }
248     if (cnt == 1)
249       {   short blockable;
250           MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
251           if (SqAtakd (PieceList[opponent][0], computer, &blockable))
252             {
253                 UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
254                 /* Illegal move in check */
255 #if !defined QUIETBOOKGEN
256 #ifdef XSHOGI
257                 printf ("Illegal move (in check)");
258 #else
259                 printf (CP[77]);
260 #endif
261                 printf ("\n");
262                 bkdisplay (s, cnt, moveno);
263 #endif
264                 return (false);
265             }
266           else
267             {
268                 *mv = (xnode.f << 8) | xnode.t;
269                 if ( is_promoted[board[xnode.t]] )
270                   Balgbr (xnode.f | 0x80, xnode.t, false);
271                 else
272                   Balgbr (xnode.f, xnode.t, false);
273                 return (true);
274             }
275       }
276     /* Illegal move */
277 #if !defined QUIETBOOKGEN
278 #ifdef XSHOGI
279     printf ("Illegal move (no match) %s\n", s);
280 #else
281     printf (CP[75], s);
282 #endif
283     bkdisplay (s, cnt, moveno);
284 #endif
285     return (false);
286 }
287
288 void
289 RESET (void)
290
291      /*
292       * Reset the board and other variables to start a new game.
293       */
294
295 {
296     short int l;
297
298     flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
299     flag.material = flag.coords = flag.hash = flag.easy = flag.beep = flag.rcptr = true;
300     flag.stars = flag.shade = flag.back = flag.musttimeout = false;
301     flag.gamein = false;
302     GenCnt = 0;
303     GameCnt = 0;
304     CptrFlag[0] = TesujiFlag[0] = false;
305     opponent = black;
306     computer = white;
307     for (l = 0; l < NO_SQUARES; l++)
308       {
309           board[l] = Stboard[l];
310           color[l] = Stcolor[l];
311           Mvboard[l] = 0;
312       }
313     ClearCaptured ();
314     InitializeStats ();
315     hashbd = hashkey = 0; 
316 }
317
318 static
319 int
320 Vparse (FILE * fd, USHORT *mv, USHORT *flags, USHORT side, int moveno)
321 {
322     int c, i;
323     char s[255];
324
325     *flags = 0;
326
327     while (true)
328       {
329           
330           while ((c = getc (fd)) == ' ' || c == '!' || c == '/' || c == '\n');
331
332           if ( c == '(' ) 
333             {   /* amount of time spent for the last move */
334                 while ((c = getc(fd)) != ')' && c != EOF);
335                 if ( c == ')' ) 
336                   while ((c = getc (fd)) == ' ' || c == '\n');
337             }
338
339           if (c == '[')
340             {   /* comment for the actual game */
341                 while ( (c = getc(fd)) != ']' && c != EOF );
342                 if ( c == ']' ) 
343                   while ((c = getc (fd)) == ' ' || c == '\n');
344             }
345           
346           if (c == '\r')
347               continue;
348
349           if (c == '#')
350             {   /* comment */
351                 do
352                   {
353                       c = getc (fd);
354                       if (c == '\r')
355                           continue;
356                       /* goes to end of line */
357                       if (c == '\n')
358                         {
359                             return 0;
360                         } 
361                       if (c == EOF)
362                         return -1;
363                   }
364                 while (true);
365             }
366
367           s[i = 0] = (char) c;
368
369           while ( c >= '0' && c <= '9' )
370             { 
371               c = getc(fd);
372               s[++i] = (char) c;
373             }
374
375           if ( c == '.' )
376             { 
377               while ((c = getc (fd)) == ' ' || c == '.' || c == '\n');
378               s[i = 0] = (char) c;
379             }     
380
381           while ((c = getc (fd)) != '?' && c != '!' && c != ' ' && c != '(' && c != '\n' && c != '\t' && c != EOF)
382             {
383                 if (c == '\r')
384                     continue;
385                 if (c != 'x' && c != '-' && c != ',' && c != ';' && c != '=')
386                     s[++i] = (char) c;
387             }
388           s[++i] = '\0';
389
390           if ( c == '(' ) 
391             {
392               while ((c = getc(fd)) != ')' && c != EOF);
393               if ( c == ')' ) 
394                 c = getc(fd);
395             }
396
397           if (c == EOF)
398               return (-1);
399
400           if (s[0] == '#')
401             {
402                 while (c != '\n' && c != EOF)
403                     c = getc (fd);
404                 if (c == EOF)
405                     return -1;
406                 else
407                     return (0);
408             }
409
410           if (strcmp (s, "draw") == 0)
411               continue;
412           else if (strcmp (s, "1-0") == 0)
413               continue;
414           else if (strcmp (s, "0-1") == 0)
415               continue;
416           else if (strcmp (s, "Resigns") == 0)
417               continue;
418           else if (strcmp (s, "Resigns.") == 0)
419               continue;
420           else if (strcmp (s, "Sennichite") == 0)
421               continue;
422           else if (strcmp (s, "Sennichite.") == 0)
423               continue;
424           else if (strcmp (s, "Jishogi") == 0)
425               continue;
426           else if (strcmp (s, "Jishogi.") == 0)
427               continue;
428
429           bhashkey = hashkey;
430           bhashbd  = hashbd;
431
432           i = BVerifyMove (s, mv, moveno);
433
434           if (c == '?')
435             {                   /* Bad move, not for the program to play */
436                 *flags |= BADMOVE;      /* Flag it ! */
437                 while ((c = getc (fd)) == '?' || c == '!' || c == '/');
438             }                      
439 #ifdef EASY_OPENINGS
440           else if (c == '~')
441             {                   /* Do not use by computer */
442                 *flags |= BADMOVE;      /* Flag it ! */
443                 while ((c = getc (fd)) == '?' || c == '!' || c == '/');
444             }            
445 #endif
446           else if (c == '!')
447             {                   /* Good move */
448                 *flags |= GOODMOVE;     /* Flag it ! */
449                 while ((c = getc (fd)) == '?' || c == '!' || c == '/');
450             }
451           else if (c == '\r')
452               c = getc (fd);
453
454           if ( c == '(' ) 
455             while ((c = getc(fd)) != ')' && c != EOF);
456
457           if (!i)
458             {
459                 /* flush to start of next */
460                 while ((c = getc (fd)) != '#' && c != EOF);
461                 if (c == EOF)
462                     return -1;
463                 else
464                   {
465                       ungetc (c, fd);
466                       return i;
467                   }
468             }
469
470           return (i);
471       }
472 }
473
474
475 static struct gdxadmin ADMIN;
476 struct gdxadmin B;
477
478 static struct gdxdata DATA;
479
480
481
482 /* lts(l) returns most significant 16 bits of l */
483
484 #ifdef LONG64
485 #define lts(x) (USHORT)(((x>>48)&0xfffe)|side)
486 #else
487 #if defined THINK_C || defined USE_LTSIMP
488 static USHORT ltsimp (long x)
489 { USHORT n;
490   n = (((x>>16)&0xfffe));
491 #if 0
492   printf("x=0x%lx lts(x)=0x%x\n",x,n);
493 #endif
494   return(n);
495 }
496 #define lts(x) (USHORT)(ltsimp(x) | side)
497 #else
498 #define lts(x) (USHORT)(((x>>16)&0xfffe) | side)
499 #endif
500 #endif
501
502
503 /* #define HashValue(l) lts(l) */
504 #define HashValue(l) (USHORT)(l & 0xffff)
505
506
507 static int gfd;
508
509
510 static ULONG currentoffset;
511
512
513 #define MAXOFFSET(B) ((B.booksize-1)*sizeof_gdxdata + sizeof_gdxadmin)
514
515 #define HashOffset(hashkey,B) { \
516   currentoffset = ((ULONG)hashkey % B.booksize)*sizeof_gdxdata + sizeof_gdxadmin; \
517 }
518
519 #define NextOffset(B) { \
520   currentoffset += sizeof_gdxdata; \
521   if (currentoffset > B.maxoffset) \
522     currentoffset = sizeof_gdxadmin; \
523 }
524
525
526
527
528 #define WriteAdmin() { \
529   lseek (gfd, 0, 0); \
530   write (gfd, (char *)&ADMIN, sizeof_gdxadmin); \
531 }
532
533 #define WriteData() { \
534   if ( mustwrite ) { \
535     lseek (gfd, currentoffset, 0); \
536     write (gfd, (char *)&DATA, sizeof_gdxdata); \
537     mustwrite = false; \
538   } \
539 }
540
541 static int ReadAdmin(void) {
542   lseek (gfd, 0, 0); 
543   return (sizeof_gdxadmin == read (gfd, (char *)&ADMIN, sizeof_gdxadmin));
544 }
545
546 static int ReadData(struct gdxdata *DATA) {
547   lseek (gfd, currentoffset, 0); 
548   return (sizeof_gdxdata == read (gfd, (char *)DATA, sizeof_gdxdata));
549 }
550
551
552 void
553 GetOpenings (void)
554
555      /*
556       * Read in the Opening Book file and parse the algebraic notation for a move
557       * into an unsigned integer format indicating the from and to square. Create
558       * a linked list of opening lines of play, with entry->next pointing to the
559       * next line and entry->move pointing to a chunk of memory containing the
560       * moves. More Opening lines of up to 100 half moves may be added to
561       gnuchess.book. But now its a hashed table by position which yields a move
562       * or moves for each position. It no longer knows about openings per say only
563       * positions and recommended moves in those positions.
564       */
565 {
566     short int i;
567     char opening[80];
568     char msg[80];
569     int mustwrite = false, first;
570     unsigned short xside, side;
571     short int c;
572     USHORT mv, flags; unsigned int x;
573     unsigned int games = 0;
574     LONG collisions = 0;
575
576     FILE *fd;
577
578     if ((fd = fopen (bookfile, "r")) == NULL)
579         fd = fopen ("gnushogi.tbk", "r");
580     if (fd != NULL)
581       {
582           /* yes add to book */
583           /* open book as writer */
584           gfd = open (binbookfile, O_RDONLY | O_BINARY);
585           if (gfd >= 0)
586             {
587                 if ( ReadAdmin() ) 
588                   {
589                       B.bookcount = ADMIN.bookcount;
590                       B.booksize = ADMIN.booksize;
591                       B.maxoffset = ADMIN.maxoffset;
592                       if (B.booksize && !(B.maxoffset == MAXOFFSET(B)))
593                         {
594                             printf ("bad format %s\n", binbookfile);
595                             exit (1);
596                         }
597                   }
598                 else
599                   {
600                       printf ("bad format %s\n", binbookfile);
601                       exit (1);
602                   }
603                 close (gfd);
604                 gfd = open (binbookfile, O_RDWR | O_BINARY);
605
606             }
607           else
608             {
609 #if defined THINK_C || defined MSDOS
610                 gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY);
611 #else
612                 gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY, 0644);
613 #endif
614                 ADMIN.bookcount = B.bookcount = 0;
615                 ADMIN.booksize = B.booksize = booksize;
616                 B.maxoffset = ADMIN.maxoffset = MAXOFFSET(B);
617                 DATA.hashbd = 0;
618                 DATA.hashkey = 0;
619                 DATA.bmove = 0;
620                 DATA.flags = 0;
621                 DATA.hint = 0;
622                 DATA.count = 0;
623                 write (gfd, (char *)&ADMIN, sizeof_gdxadmin);
624                 printf ("creating bookfile %s  %ld %d\n", binbookfile, B.maxoffset, B.booksize);
625                 for (x = 0; x < B.booksize; x++)
626                   {
627                       write (gfd, (char *)&DATA, sizeof_gdxdata);
628                   }
629
630
631             }
632           if (gfd >= 0)
633             {
634
635
636                 /* setvbuf(fd,buffr,_IOFBF,2048); */
637                 side = black;
638                 xside = white;
639                 hashbd = hashkey = 0;
640                 i = 0;
641
642                 while ((c = Vparse (fd, &mv, &flags, side, i)) >= 0)
643                   {
644                       if (c == 1)
645                         {
646
647                             /*
648                              * if not first move of an opening and first
649                              * time we have seen it save next move as
650                              * hint
651                              */
652                             i++;
653                             if (i < bookmaxply + 2)
654                               {
655                                   if (i > 1 && !(flags & BADMOVE)) {
656                                     DATA.hint = mv;
657                                   }
658                                   if (i < bookmaxply + 1)
659                                     {
660                                         /*
661                                          * see if this position and
662                                          * move already exist from
663                                          * some other opening
664                                          */
665
666                                         WriteData();
667                                         HashOffset(bhashkey,B);
668                                         first = true;
669                                         while (true) {
670                                           if (!ReadData(&DATA)) break; /* corrupted binbook file */
671                                           if (DATA.bmove == 0) break;  /* free entry */
672                                           if (DATA.hashkey == HashValue(bhashkey) && DATA.hashbd == bhashbd) {
673                                             if (DATA.bmove == mv) {
674                                               /*
675                                                * yes so just bump count - count is
676                                                * used to choose opening move in
677                                                * proportion to its presence in the book
678                                                */
679                                               DATA.count++;
680                                               DATA.flags |= flags;
681                                               mustwrite = true;
682                                               break;   
683                                             } else {
684                                               if ( first ) collisions++;
685                                               if (DATA.flags & LASTMOVE) {
686                                                 DATA.flags &= (~LASTMOVE);
687                                                 mustwrite = true;
688                                                 WriteData();
689                                               }
690                                             }
691                                           }
692                                           NextOffset(B);
693                                           first = false;
694                                         }
695
696                                         /*
697                                          * doesn`t exist so add it to
698                                          * the book
699                                          */
700                                         if (!mustwrite)
701                                           {
702                                               B.bookcount++;
703 #if !defined XSHOGI
704 #if defined THINK_C || defined MSDOS
705                                               if (B.bookcount % 100 == 0)
706 #else
707                                               if (B.bookcount % 1000 == 0)
708 #endif
709                                                   printf ("%d rec %d openings processed\n", B.bookcount, games);
710 #endif
711                                               /* initialize a record */
712                                               DATA.hashbd = bhashbd;
713                                               DATA.hashkey = HashValue(bhashkey);
714                                               DATA.bmove = mv;
715                                               DATA.flags = flags | LASTMOVE;
716                                               DATA.count = 1;
717                                               DATA.hint = 0;
718                                               mustwrite = true;
719                                           }
720                                     }
721                               }
722                             computer = opponent;
723                             opponent = computer ^ 1;
724
725                             xside = side;
726                             side = side ^ 1;
727                         }
728                       else if (i > 0)
729                         {
730                             /* reset for next opening */
731                             games++;
732                             WriteData();
733                             RESET ();
734                             i = 0;
735                             side = black;
736                             xside = white;
737
738                         }
739                   }
740                 WriteData();
741                 fclose (fd);
742                 /* write admin rec with counts */
743                 ADMIN.bookcount = B.bookcount;
744                 WriteAdmin();
745
746                 close (gfd);
747             }
748       }
749     if (binbookfile != NULL)
750       {
751           /* open book as reader */
752           gfd = open (binbookfile, O_RDONLY | O_BINARY);
753           if (gfd >= 0)
754             {
755                 if ( ReadAdmin() && (!ADMIN.booksize || ADMIN.maxoffset == MAXOFFSET(ADMIN)) ) 
756                   {
757                     B.bookcount = ADMIN.bookcount;
758                     B.booksize = ADMIN.booksize;
759                     B.maxoffset = ADMIN.maxoffset;
760                   }
761                 else
762                   {
763                     printf ("bad format %s\n", binbookfile);
764                     exit (1);
765                   }
766
767             }
768           else
769             {
770                 B.bookcount = 0;
771                 B.booksize = booksize;
772
773             }
774
775 #if !defined XSHOGI
776           sprintf (msg, CP[213], B.bookcount, B.booksize);
777           ShowMessage (msg);
778           /* printf("%ld collisions\n", collisions); */
779 #endif
780       }
781     /* set every thing back to start game */
782     Book = BOOKFAIL;
783     RESET ();
784     /* now get ready to play */
785     if (!B.bookcount)
786       {
787 #if !defined XSHOGI
788           ShowMessage (CP[212]);
789 #endif
790           Book = 0;
791       }
792 }
793
794
795 int
796 OpeningBook (unsigned short *hint, short int side)
797
798      /*
799       * Go thru each of the opening lines of play and check for a match with the
800       * current game listing. If a match occurs, generate a random number. If this
801       * number is the largest generated so far then the next move in this line
802       * becomes the current "candidate". After all lines are checked, the
803       * candidate move is put at the top of the Tree[] array and will be played by
804       * the program. Note that the program does not handle book transpositions.
805       */
806
807 {
808     unsigned short r, m;
809     int possibles = TrPnt[2] - TrPnt[1];
810
811     gsrand ((unsigned int) time ((long *) 0));
812     m = 0;
813
814     /*
815      * find all the moves for this position  - count them and get their
816      * total count
817      */
818     {
819         USHORT i, x;
820         USHORT rec = 0;
821         USHORT summ = 0;
822         USHORT h = 0, b = 0;
823         struct gdxdata OBB[128];
824         if (B.bookcount == 0)
825           {
826               Book--;
827               return false;
828           }
829         x = 0;
830         HashOffset(hashkey,B);
831 #ifdef BOOKTEST
832         printf("looking for book move, bhashbd = 0x%lx bhashkey = 0x%x\n", (ULONG)hashbd, HashValue(hashkey));
833 #endif
834         while (true)
835           {
836               if (!ReadData(&OBB[x])) break;
837               if (OBB[x].bmove == 0) break;
838 #ifdef BOOKTEST
839               printf("compare with bhashbd = 0x%lx bhashkey = 0x%x\n", OBB[x].hashbd, OBB[x].hashkey);
840 #endif
841               if (OBB[x].hashkey == HashValue(hashkey) && OBB[x].hashbd == (ULONG)hashbd)
842                 {
843                     x++;
844                     if (OBB[x-1].flags & LASTMOVE) break;
845                 }
846               NextOffset(B);
847           }
848 #ifdef BOOKTEST
849         printf("%d book move(s) found.\n",x);
850 #endif
851         if (x == 0)
852           {
853               Book--;
854               return false;
855           }
856         for (i = 0; i < x; i++)
857           {
858               if (OBB[i].flags & BADMOVE)
859                 {
860                     m = OBB[i].bmove;
861                     /* is the move is in the MoveList */
862                     for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
863                       {
864                           if (((Tree[b].f << 8) | Tree[b].t) == m)
865                             {
866
867                                 if (--possibles)
868                                     Tree[b].score = DONTUSE;
869                                 break;
870                             }
871                       }
872                 }
873               else 
874                 {
875 #if defined BOOKTEST
876                   char s[20];
877                   movealgbr(m = OBB[i].bmove,s); 
878                   printf("finding book move: %s\n",s);
879 #endif
880                   summ += OBB[i].count;
881                 }
882           }
883         if (summ == 0)
884           {
885               Book--;
886               return false;
887           }
888
889         r = (urand () % summ);
890         for (i = 0; i < x; i++)
891             if (!(OBB[i].flags & BADMOVE) ){
892                 if( r < OBB[i].count)
893                     {
894                         rec = i;
895                         break;
896                     }
897                   else
898                       r -= OBB[i].count;
899             } 
900
901         h = OBB[rec].hint;
902         m = OBB[rec].bmove;
903         /* make sure the move is in the MoveList */
904         for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
905           {
906               if (((Tree[b].f << 8) | Tree[b].t) == m)
907                 {
908                     Tree[b].flags |= book;
909                     Tree[b].score = 0;
910                     break;
911                 }
912           }
913         /* Make sure its the best */
914
915         pick (TrPnt[1], TrPnt[2] - 1);
916         if (Tree[TrPnt[1]].score)
917           {
918               /* no! */
919               Book--;
920               return false;
921           }
922         /* ok pick up the hint and go */
923         *hint = h;
924         return true;
925     }
926     Book--;
927     return false;
928 }
929
930
931