Restore previous copyright information that got removed by error.
[gnushogi.git] / gnushogi / book.c
blob08b2c473f0a8ba808571bc3622b2a20c7b945192
1 /*
2 * FILE: book.c
4 * ----------------------------------------------------------------------
5 * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6 * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
8 * GNU SHOGI is based on GNU CHESS
10 * Copyright (c) 1988, 1989, 1990 John Stanback
11 * Copyright (c) 1992 Free Software Foundation
13 * This file is part of GNU SHOGI.
15 * GNU Shogi is free software; you can redistribute it and/or modify it
16 * under the terms of the GNU General Public License as published by the
17 * Free Software Foundation; either version 3 of the License,
18 * or (at your option) any later version.
20 * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
21 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with GNU Shogi; see the file COPYING. If not, see
27 * <http://www.gnu.org/licenses/>.
28 * ----------------------------------------------------------------------
32 #include "gnushogi.h"
34 #define O_BINARY 0
36 #if HAVE_UNISTD_H
37 /* Declarations of read(), write(), close(), and lseek(). */
38 #include <unistd.h>
39 #endif
41 #if HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
45 #include "book.h"
47 unsigned booksize = BOOKSIZE;
48 unsigned short bookmaxply = BOOKMAXPLY;
49 unsigned bookcount = 0;
51 #ifdef BOOK
52 char *bookfile = BOOK;
53 #else
54 char *bookfile = NULL;
55 #endif
57 #ifdef BINBOOK
58 char *binbookfile = BINBOOK;
59 #else
60 char *binbookfile = NULL;
61 #endif
63 static char bmvstr[3][7];
65 static ULONG bhashbd;
66 static ULONG bhashkey;
70 * Balgbr(f, t, flag)
72 * Generate move strings in different formats.
75 void
76 Balgbr(short f, short t, short flag)
78 short promoted = false;
80 if ((f & 0x80) != 0)
82 f &= 0x7f;
83 promoted = true;
86 if (f > NO_SQUARES)
88 short piece;
89 piece = f - NO_SQUARES;
91 if (f > (NO_SQUARES + NO_PIECES))
92 piece -= NO_PIECES;
94 flag = (dropmask | piece);
97 if ((t & 0x80) != 0)
99 flag |= promote;
100 t &= 0x7f;
103 if ((f == t) && ((f != 0) || (t != 0)))
106 * error in algbr: FROM=TO=t
109 bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
111 else
113 if ((flag & dropmask) != 0)
115 /* bmvstr[0]: P*3c bmvstr[1]: P'3c */
116 short piece = flag & pmask;
117 bmvstr[0][0] = pxx[piece];
118 bmvstr[0][1] = '*';
119 bmvstr[0][2] = cxx[column(t)];
120 bmvstr[0][3] = rxx[row(t)];
121 bmvstr[0][4] = bmvstr[2][0] = '\0';
122 strcpy(bmvstr[1], bmvstr[0]);
123 bmvstr[1][1] = '\'';
125 else
127 if ((f != 0) || (t != 0))
129 /* algebraic notation */
130 /* bmvstr[0]: 7g7f bmvstr[1]:
131 * (+)P7g7f(+) bmvstr[2]: (+)P7f(+) */
132 bmvstr[0][0] = cxx[column(f)];
133 bmvstr[0][1] = rxx[row(f)];
134 bmvstr[0][2] = cxx[column(t)];
135 bmvstr[0][3] = rxx[row(t)];
136 bmvstr[0][4] = '\0';
138 if (promoted)
140 bmvstr[1][0] = bmvstr[2][0] = '+';
141 bmvstr[1][1] = bmvstr[2][1] = pxx[board[f]];
142 strcpy(&bmvstr[1][2], &bmvstr[0][0]);
143 strcpy(&bmvstr[2][2], &bmvstr[0][2]);
145 else
147 bmvstr[1][0] = bmvstr[2][0] = pxx[board[f]];
148 strcpy(&bmvstr[1][1], &bmvstr[0][0]);
149 strcpy(&bmvstr[2][1], &bmvstr[0][2]);
152 if (flag & promote)
154 strcat(bmvstr[0], "+");
155 strcat(bmvstr[1], "+");
156 strcat(bmvstr[2], "+");
159 else
161 bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
170 #ifndef QUIETBOOKGEN
171 void
172 bkdisplay(char *s, int cnt, int moveno)
174 static short pnt;
175 struct leaf *node;
176 int r, c, l;
178 pnt = TrPnt[2];
179 printf("matches = %d\n", cnt);
180 printf("inout move is :%s: move number %d side %s\n",
181 s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
183 #ifndef SEMIQUIETBOOKGEN
184 printf("legal moves are \n");
186 while (pnt < TrPnt[3])
188 node = &Tree[pnt++];
190 if (is_promoted[board[node->f]] )
191 Balgbr(node->f | 0x80, node->t, (short) node->flags);
192 else
193 Balgbr(node->f, node->t, (short) node->flags);
195 printf("%s %s %s\n",
196 bmvstr[0], bmvstr[1], bmvstr[2]);
199 printf("\n current board is\n");
201 for (r = (NO_ROWS - 1); r >= 0; r--)
203 for (c = 0; c <= (NO_COLS - 1); c++)
205 char pc;
207 l = locn(r, c);
208 pc = (is_promoted[board[l]] ? '+' : ' ');
210 if (color[l] == neutral)
211 printf(" -");
212 else if (color[l] == black)
213 printf("%c%c", pc, qxx[board[l]]);
214 else
215 printf("%c%c", pc, pxx[board[l]]);
218 printf("\n");
221 printf("\n");
223 short color;
225 for (color = black; color <= white; color++)
227 short piece, c;
229 printf((color == black) ? "black " : "white ");
231 for (piece = pawn; piece <= king; piece++)
233 if ((c = Captured[color][piece]))
234 printf("%i%c ", c, pxx[piece]);
237 printf("\n");
240 #endif /* SEMIQUIETBOOKGEN */
243 #endif /* QUIETBOOKGEN */
248 * BVerifyMove(s, mv, moveno)
250 * Compare the string 's' to the list of legal moves available for the
251 * opponent. If a match is found, make the move on the board.
255 BVerifyMove(char *s, unsigned short *mv, int moveno)
257 static short pnt, tempb, tempc, tempsf, tempst, cnt;
258 static struct leaf xnode;
259 struct leaf *node;
261 *mv = 0;
262 cnt = 0;
263 MoveList(opponent, 2, -2, true);
264 pnt = TrPnt[2];
266 while (pnt < TrPnt[3])
268 node = &Tree[pnt++];
270 if (is_promoted[board[node->f]] )
271 Balgbr(node->f | 0x80, node->t, (short) node->flags);
272 else
273 Balgbr(node->f, node->t, (short) node->flags);
275 if (strcmp(s, bmvstr[0]) == 0 || strcmp(s, bmvstr[1]) == 0 ||
276 strcmp(s, bmvstr[2]) == 0)
278 cnt++;
279 xnode = *node;
283 if (cnt == 1)
285 short blockable;
287 MakeMove(opponent, &xnode, &tempb,
288 &tempc, &tempsf, &tempst, &INCscore);
290 if (SqAttacked(PieceList[opponent][0], computer, &blockable))
292 UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
293 /* Illegal move in check */
294 #if !defined QUIETBOOKGEN
295 /* 077: "Illegal move (in check) %s" */
296 puts(CP[77]);
297 bkdisplay(s, cnt, moveno);
298 #endif
299 return false;
301 else
303 *mv = (xnode.f << 8) | xnode.t;
305 if (is_promoted[board[xnode.t]] )
306 Balgbr(xnode.f | 0x80, xnode.t, false);
307 else
308 Balgbr(xnode.f, xnode.t, false);
310 return true;
314 /* Illegal move */
315 #if !defined QUIETBOOKGEN
316 /* 075: "Illegal move (no match)%s\n" */
317 printf(CP[75], s);
318 bkdisplay(s, cnt, moveno);
319 #endif
320 return false;
327 * RESET()
329 * Reset the board and other variables to start a new game.
333 void
334 RESET(void)
336 short l;
338 flag.illegal = flag.mate = flag.post = flag.quit
339 = flag.reverse = flag.bothsides = flag.onemove = flag.force
340 = false;
342 flag.material = flag.coords = flag.hash = flag.easy
343 = flag.beep = flag.rcptr
344 = true;
346 flag.stars = flag.shade = flag.back = flag.musttimeout = false;
347 flag.gamein = false;
348 GenCnt = 0;
349 GameCnt = 0;
350 CptrFlag[0] = TesujiFlag[0] = false;
351 opponent = black;
352 computer = white;
354 for (l = 0; l < NO_SQUARES; l++)
356 board[l] = Stboard[l];
357 color[l] = Stcolor[l];
358 Mvboard[l] = 0;
361 ClearCaptured();
362 InitializeStats();
363 hashbd = hashkey = 0;
368 static
370 Vparse (FILE * fd, USHORT *mv, USHORT *flags, USHORT side, int moveno)
372 int c, i;
373 char s[255];
375 *flags = 0;
377 while (true)
379 while (((c = getc(fd)) == ' ')
380 || (c == '!') || (c == '/') || (c == '\n'));
382 if (c == '(')
384 /* amount of time spent for the last move */
385 while (((c = getc(fd)) != ')') && (c != EOF));
387 if (c == ')')
389 while (((c = getc(fd)) == ' ') || (c == '\n'));
393 if (c == '[')
395 /* comment for the actual game */
396 while (((c = getc(fd))) != ']' && (c != EOF));
398 if (c == ']')
400 while (((c = getc(fd))) == ' ' || (c == '\n'));
404 if (c == '\r')
405 continue;
407 if (c == '#')
409 /* comment */
412 c = getc(fd);
414 if (c == '\r')
415 continue;
416 /* goes to end of line */
418 if (c == '\n')
419 return 0;
421 if (c == EOF)
422 return -1;
424 while (true);
427 s[i = 0] = (char) c;
429 while ((c >= '0') && (c <= '9'))
431 c = getc(fd);
432 s[++i] = (char) c;
435 if (c == '.')
437 while (((c = getc(fd)) == ' ') || (c == '.') || (c == '\n'));
438 s[i = 0] = (char) c;
441 while (((c = getc(fd)) != '?') && (c != '!') && (c != ' ')
442 && (c != '(') && (c != '\n') && (c != '\t') && (c != EOF))
444 if (c == '\r')
445 continue;
447 if ((c != 'x') && (c != '-') && (c != ',')
448 && (c != ';') && (c != '='))
450 s[++i] = (char) c;
454 s[++i] = '\0';
456 if (c == '(')
458 while (((c = getc(fd)) != ')') && (c != EOF));
460 if (c == ')')
461 c = getc(fd);
464 if (c == EOF)
465 return -1;
467 if (s[0] == '#')
469 while ((c != '\n') && (c != EOF))
470 c = getc(fd);
472 if (c == EOF)
473 return -1;
474 else
475 return 0;
478 if (strcmp(s, "draw") == 0)
479 continue;
480 else if (strcmp(s, "1-0") == 0)
481 continue;
482 else if (strcmp(s, "0-1") == 0)
483 continue;
484 else if (strcmp(s, "Resigns") == 0)
485 continue;
486 else if (strcmp(s, "Resigns.") == 0)
487 continue;
488 else if (strcmp(s, "Sennichite") == 0)
489 continue;
490 else if (strcmp(s, "Sennichite.") == 0)
491 continue;
492 else if (strcmp(s, "Jishogi") == 0)
493 continue;
494 else if (strcmp(s, "Jishogi.") == 0)
495 continue;
497 bhashkey = hashkey;
498 bhashbd = hashbd;
500 i = BVerifyMove(s, mv, moveno);
502 if (c == '?')
504 /* Bad move, not for the program to play */
505 *flags |= BADMOVE; /* Flag it ! */
506 while (((c = getc(fd)) == '?') || (c == '!') || (c == '/'));
508 #ifdef EASY_OPENINGS
509 else if (c == '~')
511 /* Do not use by computer */
512 *flags |= BADMOVE; /* Flag it ! */
514 while (((c = getc(fd)) == '?') || (c == '!') || (c == '/'));
516 #endif
517 else if (c == '!')
519 /* Good move */
520 *flags |= GOODMOVE; /* Flag it ! */
522 while (((c = getc(fd)) == '?') || (c == '!') || (c == '/'));
524 else if (c == '\r')
526 c = getc(fd);
529 if (c == '(' )
530 while (((c = getc(fd)) != ')') && (c != EOF));
532 if (!i)
534 /* flush to start of next */
535 while (((c = getc(fd)) != '#') && (c != EOF));
537 if (c == EOF)
539 return -1;
541 else
543 ungetc(c, fd);
544 return i;
548 return i;
553 static struct gdxadmin ADMIN;
554 struct gdxadmin B;
555 static struct gdxdata DATA;
557 /* lts(l) returns most significant 16 bits of l */
559 #if SIZEOF_LONG == 8 /* 64-bit long i.e. 8 bytes */
560 # define lts(x) (USHORT)(((x >> 48) & 0xfffe) | side)
561 #else
562 # if defined USE_LTSIMP
563 static USHORT ltsimp(long x)
565 USHORT n;
566 n = (((x >> 16) & 0xfffe));
567 return n;
569 # define lts(x) (USHORT)(ltsimp(x) | side)
570 # else
571 # define lts(x) (USHORT)(((x >> 16)&0xfffe) | side)
572 # endif
573 #endif
576 /* #define HashValue(l) lts(l) */
577 #define HashValue(l) (USHORT)(l & 0xffff)
580 static int gfd;
581 static ULONG currentoffset;
584 #define MAXOFFSET(B) ((B.booksize - 1) * sizeof_gdxdata + sizeof_gdxadmin)
586 #define HashOffset(hashkey, B) \
588 currentoffset = ((ULONG)hashkey % B.booksize) \
589 * sizeof_gdxdata + sizeof_gdxadmin; \
593 #define NextOffset(B) \
595 currentoffset += sizeof_gdxdata; \
596 if (currentoffset > B.maxoffset) \
597 currentoffset = sizeof_gdxadmin; \
601 #define WriteAdmin() \
603 lseek(gfd, 0, 0); \
604 write(gfd, (char *)&ADMIN, sizeof_gdxadmin); \
607 #define WriteData() \
609 if (mustwrite ) \
611 lseek(gfd, currentoffset, 0); \
612 write(gfd, (char *)&DATA, sizeof_gdxdata); \
613 mustwrite = false; \
617 static int ReadAdmin(void)
619 lseek(gfd, 0, 0);
620 return (sizeof_gdxadmin == read(gfd, (char *)&ADMIN, sizeof_gdxadmin));
623 static int ReadData(struct gdxdata *DATA)
625 lseek(gfd, currentoffset, 0);
626 return (sizeof_gdxdata == read(gfd, (char *)DATA, sizeof_gdxdata));
631 * GetOpenings()
633 * CHECKME: is this still valid esp. wrt gnushogi.book?
635 * Read in the Opening Book file and parse the algebraic notation for a move
636 * into an unsigned integer format indicating the from and to square. Create
637 * a linked list of opening lines of play, with entry->next pointing to the
638 * next line and entry->move pointing to a chunk of memory containing the
639 * moves. More Opening lines of up to 100 half moves may be added to
640 * gnushogi.book. But now it's a hashed table by position which yields a move
641 * or moves for each position. It no longer knows about openings per se only
642 * positions and recommended moves in those positions.
646 void
647 GetOpenings(void)
649 short i;
650 int mustwrite = false, first;
651 unsigned short xside, side;
652 short c;
653 USHORT mv, flags;
654 unsigned int x;
655 unsigned int games = 0;
656 LONG collisions = 0;
657 char msg[80];
659 FILE *fd;
661 if ((fd = fopen(bookfile, "r")) == NULL)
662 fd = fopen("gnushogi.tbk", "r");
664 if (fd != NULL)
666 /* yes add to book */
667 /* open book as writer */
668 gfd = open(binbookfile, O_RDONLY | O_BINARY);
670 if (gfd >= 0)
672 if (ReadAdmin())
674 B.bookcount = ADMIN.bookcount;
675 B.booksize = ADMIN.booksize;
676 B.maxoffset = ADMIN.maxoffset;
678 if (B.booksize && !(B.maxoffset == MAXOFFSET(B)))
680 printf("bad format %s\n", binbookfile);
681 exit(1);
684 else
686 printf("bad format %s\n", binbookfile);
687 exit(1);
689 close(gfd);
690 gfd = open(binbookfile, O_RDWR | O_BINARY);
693 else
695 gfd = open(binbookfile, O_RDWR | O_CREAT | O_BINARY, 0644);
697 ADMIN.bookcount = B.bookcount = 0;
698 ADMIN.booksize = B.booksize = booksize;
699 B.maxoffset = ADMIN.maxoffset = MAXOFFSET(B);
700 DATA.hashbd = 0;
701 DATA.hashkey = 0;
702 DATA.bmove = 0;
703 DATA.flags = 0;
704 DATA.hint = 0;
705 DATA.count = 0;
706 write(gfd, (char *)&ADMIN, sizeof_gdxadmin);
707 printf("creating bookfile %s %ld %ld\n",
708 binbookfile, B.maxoffset, B.booksize);
710 for (x = 0; x < B.booksize; x++)
712 write(gfd, (char *)&DATA, sizeof_gdxdata);
716 if (gfd >= 0)
718 /* setvbuf(fd, buffr, _IOFBF, 2048); */
719 side = black;
720 xside = white;
721 hashbd = hashkey = 0;
722 i = 0;
724 while ((c = Vparse(fd, &mv, &flags, side, i)) >= 0)
726 if (c == 1)
729 * If this is not the first move of an opening and
730 * if it's the first time we have seen it then
731 * save the next move as a hint.
733 i++;
735 if (i < bookmaxply + 2)
737 if (i > 1 && !(flags & BADMOVE))
738 DATA.hint = mv;
740 if (i < bookmaxply + 1)
743 * See if this position and move already
744 * exist from some other opening.
747 WriteData();
748 HashOffset(bhashkey, B);
749 first = true;
751 while (true)
753 if (!ReadData(&DATA))
754 break; /* corrupted binbook file */
756 if (DATA.bmove == 0)
757 break; /* free entry */
759 if (DATA.hashkey == HashValue(bhashkey)
760 && DATA.hashbd == bhashbd)
762 if (DATA.bmove == mv)
765 * Yes, so just bump count - count
766 * is used to choose the opening
767 * move in proportion to its
768 * presence in the book.
771 DATA.count++;
772 DATA.flags |= flags;
773 mustwrite = true;
774 break;
776 else
778 if (first)
779 collisions++;
781 if (DATA.flags & LASTMOVE)
783 DATA.flags &= (~LASTMOVE);
784 mustwrite = true;
785 WriteData();
790 NextOffset(B);
791 first = false;
795 * Doesn't exist so add it to the book.
798 if (!mustwrite)
800 B.bookcount++;
802 if ((B.bookcount % 1000) == 0)
804 /* CHECKME: may want to get rid of this,
805 * especially for xshogi. */
806 printf("%ld rec %d openings "
807 "processed\n",
808 B.bookcount, games);
811 /* initialize a record */
812 DATA.hashbd = bhashbd;
813 DATA.hashkey = HashValue(bhashkey);
814 DATA.bmove = mv;
815 DATA.flags = flags | LASTMOVE;
816 DATA.count = 1;
817 DATA.hint = 0;
818 mustwrite = true;
823 computer = opponent;
824 opponent = computer ^ 1;
826 xside = side;
827 side = side ^ 1;
829 else if (i > 0)
831 /* reset for next opening */
832 games++;
833 WriteData();
834 RESET();
835 i = 0;
836 side = black;
837 xside = white;
842 WriteData();
843 fclose(fd);
844 /* write admin rec with counts */
845 ADMIN.bookcount = B.bookcount;
846 WriteAdmin();
848 close(gfd);
852 if (binbookfile != NULL)
854 /* open book as reader */
855 gfd = open(binbookfile, O_RDONLY | O_BINARY);
857 if (gfd >= 0)
859 if (ReadAdmin() && (!ADMIN.booksize
860 || (ADMIN.maxoffset == MAXOFFSET(ADMIN))))
862 B.bookcount = ADMIN.bookcount;
863 B.booksize = ADMIN.booksize;
864 B.maxoffset = ADMIN.maxoffset;
866 else
868 printf("bad format %s\n", binbookfile);
869 exit(1);
873 else
875 B.bookcount = 0;
876 B.booksize = booksize;
880 /* 213: "Book used %d(%d)." */
881 sprintf(msg, CP[213], B.bookcount, B.booksize);
882 ShowMessage(msg);
885 /* Set everything back to start the game. */
886 Book = BOOKFAIL;
887 RESET();
889 /* Now get ready to play .*/
890 if (!B.bookcount)
892 /* 212: "Can't find book." */
893 ShowMessage(CP[212]);
894 Book = 0;
901 * OpeningBook(hint, side)
903 * Go through each of the opening lines of play and check for a match with
904 * the current game listing. If a match occurs, generate a random
905 * number. If this number is the largest generated so far then the next
906 * move in this line becomes the current "candidate". After all lines are
907 * checked, the candidate move is put at the top of the Tree[] array and
908 * will be played by the program. Note that the program does not handle
909 * book transpositions.
913 OpeningBook(unsigned short *hint, short side)
915 unsigned short r, m;
916 int possibles = TrPnt[2] - TrPnt[1];
918 gsrand((unsigned int) time((long *) 0));
919 m = 0;
922 * Find all the moves for this position - count them and get their
923 * total count.
927 USHORT i, x;
928 USHORT rec = 0;
929 USHORT summ = 0;
930 USHORT h = 0, b = 0;
931 struct gdxdata OBB[128];
933 if (B.bookcount == 0)
935 Book--;
936 return false;
939 x = 0;
940 HashOffset(hashkey, B);
941 #ifdef BOOKTEST
942 printf("looking for book move, bhashbd = 0x%lx bhashkey = 0x%x\n",
943 (ULONG)hashbd, HashValue(hashkey));
944 #endif
945 while (true)
947 if (!ReadData(&OBB[x]))
948 break;
950 if (OBB[x].bmove == 0)
951 break;
953 #ifdef BOOKTEST
954 printf("compare with bhashbd = 0x%lx bhashkey = 0x%x\n",
955 OBB[x].hashbd, OBB[x].hashkey);
956 #endif
957 if ((OBB[x].hashkey == HashValue(hashkey))
958 && (OBB[x].hashbd == (ULONG)hashbd))
960 x++;
962 if (OBB[x-1].flags & LASTMOVE)
963 break;
966 NextOffset(B);
969 #ifdef BOOKTEST
970 printf("%d book move(s) found.\n", x);
971 #endif
973 if (x == 0)
975 Book--;
976 return false;
979 for (i = 0; i < x; i++)
981 if (OBB[i].flags & BADMOVE)
983 m = OBB[i].bmove;
985 /* Is the move in the MoveList? */
986 for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
988 if (((Tree[b].f << 8) | Tree[b].t) == m)
990 if (--possibles)
991 Tree[b].score = DONTUSE;
992 break;
996 else
998 #if defined BOOKTEST
999 char s[20];
1000 movealgbr(m = OBB[i].bmove, s);
1001 printf("finding book move: %s\n", s);
1002 #endif
1003 summ += OBB[i].count;
1007 if (summ == 0)
1009 Book--;
1010 return false;
1013 r = (urand() % summ);
1015 for (i = 0; i < x; i++)
1017 if (!(OBB[i].flags & BADMOVE))
1019 if (r < OBB[i].count)
1021 rec = i;
1022 break;
1024 else
1026 r -= OBB[i].count;
1031 h = OBB[rec].hint;
1032 m = OBB[rec].bmove;
1034 /* Make sure the move is in the MoveList. */
1035 for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
1037 if (((Tree[b].f << 8) | Tree[b].t) == m)
1039 Tree[b].flags |= book;
1040 Tree[b].score = 0;
1041 break;
1045 /* Make sure it's the best. */
1047 pick(TrPnt[1], TrPnt[2] - 1);
1049 if (Tree[TrPnt[1]].score)
1051 /* no! */
1052 Book--;
1053 return false;
1056 /* Ok, pick up the hint and go. */
1057 *hint = h;
1058 return true;
1061 Book--;
1062 return false;