Initial commit based on GNU Shogi 1.2 patchlevel 3.
[gnushogi.git] / src / book.c
blobc0c2686f4c60d55b31d8e4f5483826dab2d0f612
1 /*
2 * book.c - C source for GNU SHOGI
4 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * GNU SHOGI is based on GNU CHESS
8 * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
9 * Foundation
11 * This file is part of GNU SHOGI.
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.
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.
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.
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
42 #include "book.h"
46 unsigned booksize = BOOKSIZE;
47 unsigned short bookmaxply = BOOKMAXPLY;
48 unsigned bookcount = 0;
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
63 static char bmvstr[3][7];
65 static ULONG bhashbd;
66 static ULONG bhashkey;
69 void
70 Balgbr (short int f, short int t, short int flag)
74 * Generate move strings in different formats.
78 short promoted = false;
80 if ( (f & 0x80) != 0)
82 f &= 0x7f;
83 promoted = true;
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);
93 if ( (t & 0x80) != 0 )
95 flag |= promote;
96 t &= 0x7f;
98 if ( f == t && (f != 0 || t != 0) )
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';
107 else
108 if ( (flag & dropmask) != 0 )
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] = '\'';
120 else
121 if (f != 0 || t != 0)
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)
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]);
137 else
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]);
143 if (flag & promote)
145 strcat(bmvstr[0], "+");
146 strcat(bmvstr[1], "+");
147 strcat(bmvstr[2], "+");
150 else
151 bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
157 #ifndef QUIETBOOKGEN
158 void
159 bkdisplay (s, cnt, moveno)
160 char *s;
161 int cnt;
162 int moveno;
164 static short pnt;
165 struct leaf far *node;
166 int r, c, l;
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])
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]);
184 printf ("\n current board is\n");
185 for (r = (NO_ROWS-1); r >= 0; r--)
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]]);
198 printf ("\n");
200 printf ("\n");
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");
212 #endif /* SEMIQUIETBOOKGEN */
215 #endif /* QUIETBOOKGEN */
218 BVerifyMove (char *s, short unsigned int *mv, int moveno)
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.
226 static short pnt, tempb, tempc, tempsf, tempst, cnt;
227 static struct leaf xnode;
228 struct leaf far *node;
230 *mv = 0;
231 cnt = 0;
232 MoveList (opponent, 2, -2, true);
233 pnt = TrPnt[2];
234 while (pnt < TrPnt[3])
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)
244 cnt++;
245 xnode = *node;
248 if (cnt == 1)
249 { short blockable;
250 MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
251 if (SqAtakd (PieceList[opponent][0], computer, &blockable))
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);
266 else
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);
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);
288 void
289 RESET (void)
292 * Reset the board and other variables to start a new game.
296 short int l;
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++)
309 board[l] = Stboard[l];
310 color[l] = Stcolor[l];
311 Mvboard[l] = 0;
313 ClearCaptured ();
314 InitializeStats ();
315 hashbd = hashkey = 0;
318 static
320 Vparse (FILE * fd, USHORT *mv, USHORT *flags, USHORT side, int moveno)
322 int c, i;
323 char s[255];
325 *flags = 0;
327 while (true)
330 while ((c = getc (fd)) == ' ' || c == '!' || c == '/' || c == '\n');
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');
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');
346 if (c == '\r')
347 continue;
349 if (c == '#')
350 { /* comment */
353 c = getc (fd);
354 if (c == '\r')
355 continue;
356 /* goes to end of line */
357 if (c == '\n')
359 return 0;
361 if (c == EOF)
362 return -1;
364 while (true);
367 s[i = 0] = (char) c;
369 while ( c >= '0' && c <= '9' )
371 c = getc(fd);
372 s[++i] = (char) c;
375 if ( c == '.' )
377 while ((c = getc (fd)) == ' ' || c == '.' || c == '\n');
378 s[i = 0] = (char) c;
381 while ((c = getc (fd)) != '?' && c != '!' && c != ' ' && c != '(' && c != '\n' && c != '\t' && c != EOF)
383 if (c == '\r')
384 continue;
385 if (c != 'x' && c != '-' && c != ',' && c != ';' && c != '=')
386 s[++i] = (char) c;
388 s[++i] = '\0';
390 if ( c == '(' )
392 while ((c = getc(fd)) != ')' && c != EOF);
393 if ( c == ')' )
394 c = getc(fd);
397 if (c == EOF)
398 return (-1);
400 if (s[0] == '#')
402 while (c != '\n' && c != EOF)
403 c = getc (fd);
404 if (c == EOF)
405 return -1;
406 else
407 return (0);
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;
429 bhashkey = hashkey;
430 bhashbd = hashbd;
432 i = BVerifyMove (s, mv, moveno);
434 if (c == '?')
435 { /* Bad move, not for the program to play */
436 *flags |= BADMOVE; /* Flag it ! */
437 while ((c = getc (fd)) == '?' || c == '!' || c == '/');
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 == '/');
445 #endif
446 else if (c == '!')
447 { /* Good move */
448 *flags |= GOODMOVE; /* Flag it ! */
449 while ((c = getc (fd)) == '?' || c == '!' || c == '/');
451 else if (c == '\r')
452 c = getc (fd);
454 if ( c == '(' )
455 while ((c = getc(fd)) != ')' && c != EOF);
457 if (!i)
459 /* flush to start of next */
460 while ((c = getc (fd)) != '#' && c != EOF);
461 if (c == EOF)
462 return -1;
463 else
465 ungetc (c, fd);
466 return i;
470 return (i);
475 static struct gdxadmin ADMIN;
476 struct gdxadmin B;
478 static struct gdxdata DATA;
482 /* lts(l) returns most significant 16 bits of l */
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);
496 #define lts(x) (USHORT)(ltsimp(x) | side)
497 #else
498 #define lts(x) (USHORT)(((x>>16)&0xfffe) | side)
499 #endif
500 #endif
503 /* #define HashValue(l) lts(l) */
504 #define HashValue(l) (USHORT)(l & 0xffff)
507 static int gfd;
510 static ULONG currentoffset;
513 #define MAXOFFSET(B) ((B.booksize-1)*sizeof_gdxdata + sizeof_gdxadmin)
515 #define HashOffset(hashkey,B) { \
516 currentoffset = ((ULONG)hashkey % B.booksize)*sizeof_gdxdata + sizeof_gdxadmin; \
519 #define NextOffset(B) { \
520 currentoffset += sizeof_gdxdata; \
521 if (currentoffset > B.maxoffset) \
522 currentoffset = sizeof_gdxadmin; \
528 #define WriteAdmin() { \
529 lseek (gfd, 0, 0); \
530 write (gfd, (char *)&ADMIN, sizeof_gdxadmin); \
533 #define WriteData() { \
534 if ( mustwrite ) { \
535 lseek (gfd, currentoffset, 0); \
536 write (gfd, (char *)&DATA, sizeof_gdxdata); \
537 mustwrite = false; \
541 static int ReadAdmin(void) {
542 lseek (gfd, 0, 0);
543 return (sizeof_gdxadmin == read (gfd, (char *)&ADMIN, sizeof_gdxadmin));
546 static int ReadData(struct gdxdata *DATA) {
547 lseek (gfd, currentoffset, 0);
548 return (sizeof_gdxdata == read (gfd, (char *)DATA, sizeof_gdxdata));
552 void
553 GetOpenings (void)
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.
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;
576 FILE *fd;
578 if ((fd = fopen (bookfile, "r")) == NULL)
579 fd = fopen ("gnushogi.tbk", "r");
580 if (fd != NULL)
582 /* yes add to book */
583 /* open book as writer */
584 gfd = open (binbookfile, O_RDONLY | O_BINARY);
585 if (gfd >= 0)
587 if ( ReadAdmin() )
589 B.bookcount = ADMIN.bookcount;
590 B.booksize = ADMIN.booksize;
591 B.maxoffset = ADMIN.maxoffset;
592 if (B.booksize && !(B.maxoffset == MAXOFFSET(B)))
594 printf ("bad format %s\n", binbookfile);
595 exit (1);
598 else
600 printf ("bad format %s\n", binbookfile);
601 exit (1);
603 close (gfd);
604 gfd = open (binbookfile, O_RDWR | O_BINARY);
607 else
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++)
627 write (gfd, (char *)&DATA, sizeof_gdxdata);
632 if (gfd >= 0)
636 /* setvbuf(fd,buffr,_IOFBF,2048); */
637 side = black;
638 xside = white;
639 hashbd = hashkey = 0;
640 i = 0;
642 while ((c = Vparse (fd, &mv, &flags, side, i)) >= 0)
644 if (c == 1)
648 * if not first move of an opening and first
649 * time we have seen it save next move as
650 * hint
652 i++;
653 if (i < bookmaxply + 2)
655 if (i > 1 && !(flags & BADMOVE)) {
656 DATA.hint = mv;
658 if (i < bookmaxply + 1)
661 * see if this position and
662 * move already exist from
663 * some other opening
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) {
675 * yes so just bump count - count is
676 * used to choose opening move in
677 * proportion to its presence in the book
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();
692 NextOffset(B);
693 first = false;
697 * doesn`t exist so add it to
698 * the book
700 if (!mustwrite)
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;
722 computer = opponent;
723 opponent = computer ^ 1;
725 xside = side;
726 side = side ^ 1;
728 else if (i > 0)
730 /* reset for next opening */
731 games++;
732 WriteData();
733 RESET ();
734 i = 0;
735 side = black;
736 xside = white;
740 WriteData();
741 fclose (fd);
742 /* write admin rec with counts */
743 ADMIN.bookcount = B.bookcount;
744 WriteAdmin();
746 close (gfd);
749 if (binbookfile != NULL)
751 /* open book as reader */
752 gfd = open (binbookfile, O_RDONLY | O_BINARY);
753 if (gfd >= 0)
755 if ( ReadAdmin() && (!ADMIN.booksize || ADMIN.maxoffset == MAXOFFSET(ADMIN)) )
757 B.bookcount = ADMIN.bookcount;
758 B.booksize = ADMIN.booksize;
759 B.maxoffset = ADMIN.maxoffset;
761 else
763 printf ("bad format %s\n", binbookfile);
764 exit (1);
768 else
770 B.bookcount = 0;
771 B.booksize = booksize;
775 #if !defined XSHOGI
776 sprintf (msg, CP[213], B.bookcount, B.booksize);
777 ShowMessage (msg);
778 /* printf("%ld collisions\n", collisions); */
779 #endif
781 /* set every thing back to start game */
782 Book = BOOKFAIL;
783 RESET ();
784 /* now get ready to play */
785 if (!B.bookcount)
787 #if !defined XSHOGI
788 ShowMessage (CP[212]);
789 #endif
790 Book = 0;
796 OpeningBook (unsigned short *hint, short int side)
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.
808 unsigned short r, m;
809 int possibles = TrPnt[2] - TrPnt[1];
811 gsrand ((unsigned int) time ((long *) 0));
812 m = 0;
815 * find all the moves for this position - count them and get their
816 * total count
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)
826 Book--;
827 return false;
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)
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)
843 x++;
844 if (OBB[x-1].flags & LASTMOVE) break;
846 NextOffset(B);
848 #ifdef BOOKTEST
849 printf("%d book move(s) found.\n",x);
850 #endif
851 if (x == 0)
853 Book--;
854 return false;
856 for (i = 0; i < x; i++)
858 if (OBB[i].flags & BADMOVE)
860 m = OBB[i].bmove;
861 /* is the move is in the MoveList */
862 for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
864 if (((Tree[b].f << 8) | Tree[b].t) == m)
867 if (--possibles)
868 Tree[b].score = DONTUSE;
869 break;
873 else
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;
883 if (summ == 0)
885 Book--;
886 return false;
889 r = (urand () % summ);
890 for (i = 0; i < x; i++)
891 if (!(OBB[i].flags & BADMOVE) ){
892 if( r < OBB[i].count)
894 rec = i;
895 break;
897 else
898 r -= OBB[i].count;
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++)
906 if (((Tree[b].f << 8) | Tree[b].t) == m)
908 Tree[b].flags |= book;
909 Tree[b].score = 0;
910 break;
913 /* Make sure its the best */
915 pick (TrPnt[1], TrPnt[2] - 1);
916 if (Tree[TrPnt[1]].score)
918 /* no! */
919 Book--;
920 return false;
922 /* ok pick up the hint and go */
923 *hint = h;
924 return true;
926 Book--;
927 return false;