1 /*
2  * FILE: util.c
3  *
4  * ----------------------------------------------------------------------
5  * Copyright (c) 1993, 1994, 1995 Matthias Mutz
6  * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
7  * Copyright (c) 2008, 2013, 2014 Yann Dirson and the Free Software Foundation
8  *
9  * GNU SHOGI is based on GNU CHESS
10  *
11  * Copyright (c) 1988, 1989, 1990 John Stanback
12  * Copyright (c) 1992 Free Software Foundation
13  *
14  * This file is part of GNU SHOGI.
15  *
16  * GNU Shogi is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the
18  * Free Software Foundation; either version 3 of the License,
19  * or (at your option) any later version.
20  *
21  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with GNU Shogi; see the file COPYING. If not, see
28  * <http://www.gnu.org/licenses/>.
29  * ----------------------------------------------------------------------
30  *
31  */
32 
33 #include "gnushogi.h"
34 
35 unsigned int TTadd = 0;
36 short recycle;
37 short ISZERO = 1;
38 
39 
40 int
parse(FILE * fd,unsigned short * mv,short side,char * opening)41 parse(FILE * fd, unsigned short *mv, short side, char *opening)
42 {
43     int c, i, r1, r2, c1, c2;
44     char s[128];
45     char *p;
46 
47     while (((c = getc(fd)) == ' ') || (c == '\n'));
48 
49     i = 0;
50     s[0] = (char) c;
51 
52     if (c == '!')
53     {
54         p = opening;
55         do
56         {
57             *p++ = c;
58             c = getc(fd);
59 
60             if ((c == '\n') || (c == EOF))
61             {
62                 *p = '\0';
63                 return 0;
64             }
65         }
66         while (true);
67     }
68 
69     while ((c != '?') && (c != ' ')
70            && (c != '\t') && (c != '\n') && (c != EOF))
71     {
72         s[++i] = (char) (c = getc(fd));
73     }
74 
75     s[++i] = '\0';
76 
77     if (c == EOF)
78         return (-1);
79 
80     if ((s[0] == '!') || (s[0] == ';') || (i < 3))
81     {
82         while ((c != '\n') && (c != EOF))
83             c = getc(fd);
84 
85         return 0;
86     }
87 
88     c1 = COL_NUM(s[0]);
89     r1 = ROW_NUM(s[1]);
90     c2 = COL_NUM(s[2]);
91     r2 = ROW_NUM(s[3]);
92     *mv = (locn(r1, c1) << 8) | locn(r2, c2);
93 
94     if (c == '?')
95     {
96         /* Bad move, not for the program to play */
97         *mv |= 0x8000;      /* Flag it ! */
98         c = getc(fd);
99     }
100 
101     return 1;
102 }
103 
104 
105 /*
106  * The field of a hashtable is computed as follows:
107  *   if sq is on board (< NO_SQUARES) the field gets the value
108  *     of the piece on the square sq;
109  *   if sq is off board (>= NO_SQUARES) it is a catched figure,
110  *     and the field gets the number of catched pieces for
111  *     each side.
112  */
113 
114 inline unsigned char
CB(short sq)115 CB(short sq)
116 {
117     short i = sq;
118 
119     if (i < NO_SQUARES)
120     {
121         return ((color[i] == white) ? (0x80 | board[i]) : board[i]);
122     }
123     else
124     {
125         i -= NO_SQUARES;
126         return ((Captured[black][i] << 4) | Captured[white][i]);
127     }
128 }
129 
130 
131 
132 
133 #if ttblsz
134 
135 /*
136  * Look for the current board position in the transposition table.
137  */
138 
139 int
ProbeTTable(short side,short depth,short ply,short * alpha,short * beta,short * score)140 ProbeTTable (short side,
141              short depth,
142              short ply,
143              short *alpha,
144              short *beta,
145              short *score)
146 {
147     struct hashentry  *ptbl;
148     /*unsigned*/ short i = 0;  /* to match new type of rehash --tpm */
149 
150     ptbl = &ttable[side][hashkey % ttblsize];
151 
152     while (true)
153     {
154         if ((ptbl->depth) == 0)
155             return false;
156 
157         if (ptbl->hashbd == hashbd)
158             break;
159 
160         if (++i > rehash)
161             return false;
162 
163         ptbl++;
164     }
165 
166     /* rehash max rehash times */
167 
168     if (((short)(ptbl->depth) >= (short) depth))
169     {
170 #ifdef HASHTEST
171         for (i = 0; i < PTBLBDSIZE; i++)
172         {
173             if (ptbl->bd[i] != CB(i))
174             {
175                 HashCol++;
176 
177                 if (!barebones)
178                 {
179                     ShowMessage("ttable collision detected");
180                     ShowBD(ptbl->bd);
181                     printf("hashkey = 0x%x, hashbd = 0x%x\n",
182                            hashkey, hashbd);
183                 }
184 
185                 break;
186             }
187         }
188 #endif /* HASHTEST */
189 
190 
191         PV = SwagHt = ptbl->mv;
192 
193         HashCnt++;
194 
195         if (ptbl->flags & truescore)
196         {
197             *score = ptbl->score;
198             /* adjust *score so moves to mate is from root */
199 
200             if (*score > SCORE_LIMIT)
201                 *score -= ply;
202             else if (*score < -SCORE_LIMIT)
203                 *score += ply;
204 
205             *beta = -2 * (SCORE_LIMIT + 1000);
206         }
207         else if (ptbl->flags & lowerbound)
208         {
209             if (ptbl->score > *alpha)
210                 *alpha = ptbl->score - 1;
211         }
212 
213         return true;
214     }
215 
216     return false;
217 }
218 
219 
220 
221 /*
222  * Store the current board position in the transposition table.
223  */
224 
225 int
PutInTTable(short side,short score,short depth,short ply,short alpha,short beta,unsigned short mv)226 PutInTTable(short side,
227             short score,
228             short depth,
229             short ply,
230             short alpha,
231             short beta,
232             unsigned short mv)
233 {
234     struct hashentry  *ptbl;
235     /*unsigned*/ short i = 0;  /* to match new type of rehash --tpm */
236 
237     ptbl = &ttable[side][hashkey % ttblsize];
238 
239     while (true)
240     {
241         if ((ptbl->depth) == 0 || ptbl->hashbd == hashbd)
242             break;
243 
244         if (++i > rehash)
245         {
246             THashCol++;
247             ptbl += recycle;
248 
249             break;
250         }
251 
252         ptbl++;
253     }
254 
255     TTadd++;
256     HashAdd++;
257 
258     /* adjust score so moves to mate is from this ply */
259 
260     if (score > SCORE_LIMIT)
261         score += ply;
262     else if (score < -SCORE_LIMIT)
263         score -= ply;
264 
265     ptbl->hashbd = hashbd;
266     ptbl->depth = (unsigned char) depth;
267     ptbl->score = score;
268     ptbl->mv = mv;
269 
270     if (score > beta)
271     {
272         ptbl->flags = lowerbound;
273         ptbl->score = beta + 1;
274     }
275     else
276     {
277         ptbl->flags = truescore;
278     }
279 
280 #if defined HASHTEST
281     for (i = 0; i < PTBLBDSIZE; i++)
282         ptbl->bd[i] = CB(i);
283 #endif /* HASHTEST */
284 
285     return true;
286 }
287 
288 
289 
290 void
ZeroTTable(void)291 ZeroTTable(void)
292 {
293     array_zero(ttable[black], (ttblsize + rehash));
294     array_zero(ttable[white], (ttblsize + rehash));
295 
296 #ifdef CACHE
297     array_zero(etab[0], sizeof(struct etable)*(size_t)ETABLE);
298     array_zero(etab[1], sizeof(struct etable)*(size_t)ETABLE);
299 #endif
300 
301     TTadd = 0;
302 }
303 
304 
305 
306 
307 #ifdef HASHFILE
308 int
Fbdcmp(unsigned char * a,unsigned char * b)309 Fbdcmp(unsigned char *a, unsigned char *b)
310 {
311     int i;
312 
313     for (i = 0; i < PTBLBDSIZE; i++)
314     {
315         if (a[i] != b[i])
316             return false;
317     }
318 
319     return true;
320 }
321 
322 
323 
324 /*
325  * Look for the current board position in the persistent transposition table.
326  */
327 
328 int
ProbeFTable(short side,short depth,short ply,short * alpha,short * beta,short * score)329 ProbeFTable(short side,
330             short depth,
331             short ply,
332             short *alpha,
333             short *beta,
334             short *score)
335 {
336     short i;
337     unsigned long hashix;
338     struct fileentry new, t;
339 
340     hashix = ((side == black) ? (hashkey & 0xFFFFFFFE)
341               : (hashkey | 1)) % filesz;
342 
343     for (i = 0; i < PTBLBDSIZE; i++)
344         new.bd[i] = CB(i);
345 
346     new.flags = 0;
347 
348     for (i = 0; i < frehash; i++)
349     {
350         fseek(hashfile,
351               sizeof(struct fileentry) * ((hashix + 2 * i) % (filesz)),
352               SEEK_SET);
353         fread(&t, sizeof(struct fileentry), 1, hashfile);
354 
355         if (!t.depth)
356             break;
357 
358         if (!Fbdcmp(t.bd, new.bd))
359             continue;
360 
361         if (((short) t.depth >= depth)
362             && (new.flags == (unsigned short)(t.flags
363                                               & (kingcastle | queencastle))))
364         {
365             FHashCnt++;
366 
367             PV = (t.f << 8) | t.t;
368             *score = (t.sh << 8) | t.sl;
369 
370             /* adjust *score so moves to mate is from root */
371             if (*score > SCORE_LIMIT)
372                 *score -= ply;
373             else if (*score < -SCORE_LIMIT)
374                 *score += ply;
375 
376             if (t.flags & truescore)
377             {
378                 *beta = -((SCORE_LIMIT + 1000)*2);
379             }
380             else if (t.flags & lowerbound)
381             {
382                 if (*score > *alpha)
383                     *alpha = *score - 1;
384             }
385             else if (t.flags & upperbound)
386             {
387                 if (*score < *beta)
388                     *beta = *score + 1;
389             }
390 
391             return (true);
392         }
393     }
394 
395     return (false);
396 }
397 
398 
399 
400 /*
401  * Store the current board position in the persistent transposition table.
402  */
403 
404 void
PutInFTable(short side,short score,short depth,short ply,short alpha,short beta,unsigned short f,unsigned short t)405 PutInFTable(short side,
406             short score,
407             short depth,
408             short ply,
409             short alpha,
410             short beta,
411             unsigned short f,
412             unsigned short t)
413 {
414     unsigned short i;
415     unsigned long hashix;
416     struct fileentry new, tmp;
417 
418     hashix = ((side == black) ? (hashkey & 0xFFFFFFFE)
419               : (hashkey | 1)) % filesz;
420 
421     for (i = 0; i < PTBLBDSIZE; i++)
422         new.bd[i] = CB(i);
423 
424     new.f = (unsigned char) f;
425     new.t = (unsigned char) t;
426 
427     if (score < alpha)
428         new.flags = upperbound;
429     else
430         new.flags = ((score > beta) ? lowerbound : truescore);
431 
432     new.depth = (unsigned char) depth;
433 
434     /* adjust *score so moves to mate is from root */
435     if (score > SCORE_LIMIT)
436         score += ply;
437     else if (score < -SCORE_LIMIT)
438         score -= ply;
439 
440 
441     new.sh = (unsigned char) (score >> 8);
442     new.sl = (unsigned char) (score & 0xFF);
443 
444     for (i = 0; i < frehash; i++)
445     {
446         fseek(hashfile,
447               sizeof(struct fileentry) * ((hashix + 2 * i) % (filesz)),
448               SEEK_SET);
449 
450         if (!fread(&tmp, sizeof(struct fileentry), 1, hashfile) )
451         {
452             perror("hashfile");
453             exit(1);
454         }
455 
456         if (tmp.depth && !Fbdcmp(tmp.bd, new.bd))
457             continue;
458 
459         if (tmp.depth == depth)
460             break;
461 
462         if (!tmp.depth || ((short) tmp.depth < depth))
463         {
464             fseek(hashfile,
465                   sizeof(struct fileentry) * ((hashix + 2 * i) % (filesz)),
466                   SEEK_SET);
467 
468             fwrite(&new, sizeof(struct fileentry), 1, hashfile);
469             FHashAdd++;
470 
471             break;
472         }
473     }
474 }
475 
476 #endif /* HASHFILE */
477 #endif /* ttblsz */
478 
479 
480 
481 void
ZeroRPT(void)482 ZeroRPT(void)
483 {
484     if (ISZERO )
485     {
486         array_zero(rpthash, sizeof(rpthash));
487         ISZERO = 0;
488     }
489 }
490 
491 
492 
493 #if defined CACHE
494 
495 /*
496  * Store the current eval position in the transposition table.
497  */
498 
499 void
PutInEETable(short side,int score)500 PutInEETable(short side, int score)
501 {
502     struct etable  *ptbl;
503 
504     ptbl = &(*etab[side])[hashkey % (ETABLE)];
505     ptbl->ehashbd = hashbd;
506     ptbl->escore[black] = pscore[black];
507     ptbl->escore[white] = pscore[white];
508     ptbl->hung[black] = hung[black];
509     ptbl->hung[white] = hung[white];
510     ptbl->score = score;
511 
512 #if !defined SAVE_SSCORE
513     array_copy(svalue, &(ptbl->sscore), sizeof(svalue));
514 #endif
515 
516     EADD++;
517 
518     return;
519 }
520 
521 
522 
523 /* Get an evaluation from the transposition table */
524 
525 int
CheckEETable(short side)526 CheckEETable(short side)
527 {
528     struct etable  *ptbl;
529 
530     ptbl = &(*etab[side])[hashkey % (ETABLE)];
531 
532     if (hashbd == ptbl->ehashbd)
533         return true;
534 
535     return false;
536 }
537 
538 
539 
540 /* Get an evaluation from the transposition table */
541 
542 int
ProbeEETable(short side,short * score)543 ProbeEETable(short side, short *score)
544 {
545     struct etable  *ptbl;
546 
547     ptbl = &(*etab[side])[hashkey % (ETABLE)];
548 
549     if (hashbd == ptbl->ehashbd)
550     {
551         pscore[black] = ptbl->escore[black];
552         pscore[white] = ptbl->escore[white];
553 
554 #if defined SAVE_SSCORE
555         array_zero(svalue, sizeof(svalue));
556 #else
557         array_copy(&(ptbl->sscore), svalue, sizeof(svalue));
558 #endif
559 
560         *score = ptbl->score;
561         hung[black] = ptbl->hung[black];
562         hung[white] = ptbl->hung[white];
563 
564         EGET++;
565 
566         return true;
567     }
568 
569     return false;
570 }
571 
572 #endif /* CACHE */
573 
574 
575 
576 
577