~ubuntu-branches/ubuntu/warty/gnushogi/warty

« back to all changes in this revision

Viewing changes to gnushogi/book.c

  • Committer: Bazaar Package Importer
  • Author(s): Javier Fernandez-Sanguino Pen~a
  • Date: 2004-01-09 16:06:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040109160659-n26nu7009llm247p
Tags: 1.3-3.1
* NMU
 - Minimal testing done and looks quite OK (even if I don't know
   how to play the game...)
 - Build-Depends move from libxaw-dev to libxaw6-dev (Closes: #169975)
 - Included errno.h in gnushogi which makes the binary build properly
   now (and is usable with xshogi) (Closes: #226319)

Show diffs side-by-side

added added

removed removed

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