]> git.sesse.net Git - stockfish/blob - src/syzygy/tbprobe.cpp
Sync with master
[stockfish] / src / syzygy / tbprobe.cpp
1 /*
2   Copyright (c) 2013 Ronald de Man
3   This file may be redistributed and/or modified without restrictions.
4
5   tbprobe.cpp contains the Stockfish-specific routines of the
6   tablebase probing code. It should be relatively easy to adapt
7   this code to other chess engines.
8 */
9
10 #define NOMINMAX
11
12 #include <algorithm>
13
14 #include "../position.h"
15 #include "../movegen.h"
16 #include "../bitboard.h"
17 #include "../search.h"
18 #include "../bitcount.h"
19
20 #include "tbprobe.h"
21 #include "tbcore.h"
22
23 #include "tbcore.cpp"
24
25 namespace Zobrist {
26   extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB];
27 }
28
29 int Tablebases::MaxCardinality = 0;
30
31 // Given a position with 6 or fewer pieces, produce a text string
32 // of the form KQPvKRP, where "KQP" represents the white pieces if
33 // mirror == 0 and the black pieces if mirror == 1.
34 static void prt_str(Position& pos, char *str, int mirror)
35 {
36   Color color;
37   PieceType pt;
38   int i;
39
40   color = !mirror ? WHITE : BLACK;
41   for (pt = KING; pt >= PAWN; --pt)
42     for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
43       *str++ = pchr[6 - pt];
44   *str++ = 'v';
45   color = ~color;
46   for (pt = KING; pt >= PAWN; --pt)
47     for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
48       *str++ = pchr[6 - pt];
49   *str++ = 0;
50 }
51
52 // Given a position, produce a 64-bit material signature key.
53 // If the engine supports such a key, it should equal the engine's key.
54 static uint64 calc_key(Position& pos, int mirror)
55 {
56   Color color;
57   PieceType pt;
58   int i;
59   uint64 key = 0;
60
61   color = !mirror ? WHITE : BLACK;
62   for (pt = PAWN; pt <= KING; ++pt)
63     for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
64       key ^= Zobrist::psq[WHITE][pt][i - 1];
65   color = ~color;
66   for (pt = PAWN; pt <= KING; ++pt)
67     for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
68       key ^= Zobrist::psq[BLACK][pt][i - 1];
69
70   return key;
71 }
72
73 // Produce a 64-bit material key corresponding to the material combination
74 // defined by pcs[16], where pcs[1], ..., pcs[6] is the number of white
75 // pawns, ..., kings and pcs[9], ..., pcs[14] is the number of black
76 // pawns, ..., kings.
77 static uint64 calc_key_from_pcs(int *pcs, int mirror)
78 {
79   int color;
80   PieceType pt;
81   int i;
82   uint64 key = 0;
83
84   color = !mirror ? 0 : 8;
85   for (pt = PAWN; pt <= KING; ++pt)
86     for (i = 0; i < pcs[color + pt]; i++)
87       key ^= Zobrist::psq[WHITE][pt][i];
88   color ^= 8;
89   for (pt = PAWN; pt <= KING; ++pt)
90     for (i = 0; i < pcs[color + pt]; i++)
91       key ^= Zobrist::psq[BLACK][pt][i];
92
93   return key;
94 }
95
96 bool is_little_endian() {
97   union {
98     int i;
99     char c[sizeof(int)];
100   } x;
101   x.i = 1;
102   return x.c[0] == 1;
103 }
104
105 static ubyte decompress_pairs(struct PairsData *d, uint64 idx)
106 {
107   static const bool isLittleEndian = is_little_endian();
108   return isLittleEndian ? decompress_pairs<true >(d, idx)
109                         : decompress_pairs<false>(d, idx);
110 }
111
112 // probe_wdl_table and probe_dtz_table require similar adaptations.
113 static int probe_wdl_table(Position& pos, int *success)
114 {
115   struct TBEntry *ptr;
116   struct TBHashEntry *ptr2;
117   uint64 idx;
118   uint64 key;
119   int i;
120   ubyte res;
121   int p[TBPIECES];
122
123   // Obtain the position's material signature key.
124   key = pos.material_key();
125
126   // Test for KvK.
127   if (key == (Zobrist::psq[WHITE][KING][0] ^ Zobrist::psq[BLACK][KING][0]))
128     return 0;
129
130   ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
131   for (i = 0; i < HSHMAX; i++)
132     if (ptr2[i].key == key) break;
133   if (i == HSHMAX) {
134     *success = 0;
135     return 0;
136   }
137
138   ptr = ptr2[i].ptr;
139   if (!ptr->ready) {
140     LOCK(TB_mutex);
141     if (!ptr->ready) {
142       char str[16];
143       prt_str(pos, str, ptr->key != key);
144       if (!init_table_wdl(ptr, str)) {
145         ptr2[i].key = 0ULL;
146         *success = 0;
147         UNLOCK(TB_mutex);
148         return 0;
149       }
150       // Memory barrier to ensure ptr->ready = 1 is not reordered.
151 #ifdef _MSC_VER
152       _ReadWriteBarrier();
153 #else
154       __asm__ __volatile__ ("" ::: "memory");
155 #endif
156       ptr->ready = 1;
157     }
158     UNLOCK(TB_mutex);
159   }
160
161   int bside, mirror, cmirror;
162   if (!ptr->symmetric) {
163     if (key != ptr->key) {
164       cmirror = 8;
165       mirror = 0x38;
166       bside = (pos.side_to_move() == WHITE);
167     } else {
168       cmirror = mirror = 0;
169       bside = !(pos.side_to_move() == WHITE);
170     }
171   } else {
172     cmirror = pos.side_to_move() == WHITE ? 0 : 8;
173     mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
174     bside = 0;
175   }
176
177   // p[i] is to contain the square 0-63 (A1-H8) for a piece of type
178   // pc[i] ^ cmirror, where 1 = white pawn, ..., 14 = black king.
179   // Pieces of the same type are guaranteed to be consecutive.
180   if (!ptr->has_pawns) {
181     struct TBEntry_piece *entry = (struct TBEntry_piece *)ptr;
182     ubyte *pc = entry->pieces[bside];
183     for (i = 0; i < entry->num;) {
184       Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
185                                       (PieceType)(pc[i] & 0x07));
186       do {
187         p[i++] = pop_lsb(&bb);
188       } while (bb);
189     }
190     idx = encode_piece(entry, entry->norm[bside], p, entry->factor[bside]);
191     res = decompress_pairs(entry->precomp[bside], idx);
192   } else {
193     struct TBEntry_pawn *entry = (struct TBEntry_pawn *)ptr;
194     int k = entry->file[0].pieces[0][0] ^ cmirror;
195     Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
196     i = 0;
197     do {
198       p[i++] = pop_lsb(&bb) ^ mirror;
199     } while (bb);
200     int f = pawn_file(entry, p);
201     ubyte *pc = entry->file[f].pieces[bside];
202     for (; i < entry->num;) {
203       bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
204                                     (PieceType)(pc[i] & 0x07));
205       do {
206         p[i++] = pop_lsb(&bb) ^ mirror;
207       } while (bb);
208     }
209     idx = encode_pawn(entry, entry->file[f].norm[bside], p, entry->file[f].factor[bside]);
210     res = decompress_pairs(entry->file[f].precomp[bside], idx);
211   }
212
213   return ((int)res) - 2;
214 }
215
216 static int probe_dtz_table(Position& pos, int wdl, int *success)
217 {
218   struct TBEntry *ptr;
219   uint64 idx;
220   int i, res;
221   int p[TBPIECES];
222
223   // Obtain the position's material signature key.
224   uint64 key = pos.material_key();
225
226   if (DTZ_table[0].key1 != key && DTZ_table[0].key2 != key) {
227     for (i = 1; i < DTZ_ENTRIES; i++)
228       if (DTZ_table[i].key1 == key) break;
229     if (i < DTZ_ENTRIES) {
230       struct DTZTableEntry table_entry = DTZ_table[i];
231       for (; i > 0; i--)
232         DTZ_table[i] = DTZ_table[i - 1];
233       DTZ_table[0] = table_entry;
234     } else {
235       struct TBHashEntry *ptr2 = TB_hash[key >> (64 - TBHASHBITS)];
236       for (i = 0; i < HSHMAX; i++)
237         if (ptr2[i].key == key) break;
238       if (i == HSHMAX) {
239         *success = 0;
240         return 0;
241       }
242       ptr = ptr2[i].ptr;
243       char str[16];
244       int mirror = (ptr->key != key);
245       prt_str(pos, str, mirror);
246       if (DTZ_table[DTZ_ENTRIES - 1].entry)
247         free_dtz_entry(DTZ_table[DTZ_ENTRIES-1].entry);
248       for (i = DTZ_ENTRIES - 1; i > 0; i--)
249         DTZ_table[i] = DTZ_table[i - 1];
250       load_dtz_table(str, calc_key(pos, mirror), calc_key(pos, !mirror));
251     }
252   }
253
254   ptr = DTZ_table[0].entry;
255   if (!ptr) {
256     *success = 0;
257     return 0;
258   }
259
260   int bside, mirror, cmirror;
261   if (!ptr->symmetric) {
262     if (key != ptr->key) {
263       cmirror = 8;
264       mirror = 0x38;
265       bside = (pos.side_to_move() == WHITE);
266     } else {
267       cmirror = mirror = 0;
268       bside = !(pos.side_to_move() == WHITE);
269     }
270   } else {
271     cmirror = pos.side_to_move() == WHITE ? 0 : 8;
272     mirror = pos.side_to_move() == WHITE ? 0 : 0x38;
273     bside = 0;
274   }
275
276   if (!ptr->has_pawns) {
277     struct DTZEntry_piece *entry = (struct DTZEntry_piece *)ptr;
278     if ((entry->flags & 1) != bside && !entry->symmetric) {
279       *success = -1;
280       return 0;
281     }
282     ubyte *pc = entry->pieces;
283     for (i = 0; i < entry->num;) {
284       Bitboard bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
285                                     (PieceType)(pc[i] & 0x07));
286       do {
287         p[i++] = pop_lsb(&bb);
288       } while (bb);
289     }
290     idx = encode_piece((struct TBEntry_piece *)entry, entry->norm, p, entry->factor);
291     res = decompress_pairs(entry->precomp, idx);
292
293     if (entry->flags & 2)
294       res = entry->map[entry->map_idx[wdl_to_map[wdl + 2]] + res];
295
296     if (!(entry->flags & pa_flags[wdl + 2]) || (wdl & 1))
297       res *= 2;
298   } else {
299     struct DTZEntry_pawn *entry = (struct DTZEntry_pawn *)ptr;
300     int k = entry->file[0].pieces[0] ^ cmirror;
301     Bitboard bb = pos.pieces((Color)(k >> 3), (PieceType)(k & 0x07));
302     i = 0;
303     do {
304       p[i++] = pop_lsb(&bb) ^ mirror;
305     } while (bb);
306     int f = pawn_file((struct TBEntry_pawn *)entry, p);
307     if ((entry->flags[f] & 1) != bside) {
308       *success = -1;
309       return 0;
310     }
311     ubyte *pc = entry->file[f].pieces;
312     for (; i < entry->num;) {
313       bb = pos.pieces((Color)((pc[i] ^ cmirror) >> 3),
314                             (PieceType)(pc[i] & 0x07));
315       do {
316         p[i++] = pop_lsb(&bb) ^ mirror;
317       } while (bb);
318     }
319     idx = encode_pawn((struct TBEntry_pawn *)entry, entry->file[f].norm, p, entry->file[f].factor);
320     res = decompress_pairs(entry->file[f].precomp, idx);
321
322     if (entry->flags[f] & 2)
323       res = entry->map[entry->map_idx[f][wdl_to_map[wdl + 2]] + res];
324
325     if (!(entry->flags[f] & pa_flags[wdl + 2]) || (wdl & 1))
326       res *= 2;
327   }
328
329   return res;
330 }
331
332 // Add underpromotion captures to list of captures.
333 static ExtMove *add_underprom_caps(Position& pos, ExtMove *stack, ExtMove *end)
334 {
335   ExtMove *moves, *extra = end;
336
337   for (moves = stack; moves < end; moves++) {
338     Move move = moves->move;
339     if (type_of(move) == PROMOTION && !pos.empty(to_sq(move))) {
340       (*extra++).move = (Move)(move - (1 << 12));
341       (*extra++).move = (Move)(move - (2 << 12));
342       (*extra++).move = (Move)(move - (3 << 12));
343     }
344   }
345
346   return extra;
347 }
348
349 static int probe_ab(Position& pos, int alpha, int beta, int *success)
350 {
351   int v;
352   ExtMove stack[64];
353   ExtMove *moves, *end;
354   StateInfo st;
355
356   // Generate (at least) all legal non-ep captures including (under)promotions.
357   // It is OK to generate more, as long as they are filtered out below.
358   if (!pos.checkers()) {
359     end = generate<CAPTURES>(pos, stack);
360     // Since underpromotion captures are not included, we need to add them.
361     end = add_underprom_caps(pos, stack, end);
362   } else
363     end = generate<EVASIONS>(pos, stack);
364
365   CheckInfo ci(pos);
366
367   for (moves = stack; moves < end; moves++) {
368     Move capture = moves->move;
369     if (!pos.capture(capture) || type_of(capture) == ENPASSANT
370                         || !pos.legal(capture, ci.pinned))
371       continue;
372     pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
373     v = -probe_ab(pos, -beta, -alpha, success);
374     pos.undo_move(capture);
375     if (*success == 0) return 0;
376     if (v > alpha) {
377       if (v >= beta) {
378         *success = 2;
379         return v;
380       }
381       alpha = v;
382     }
383   }
384
385   v = probe_wdl_table(pos, success);
386   if (*success == 0) return 0;
387   if (alpha >= v) {
388     *success = 1 + (alpha > 0);
389     return alpha;
390   } else {
391     *success = 1;
392     return v;
393   }
394 }
395
396 // Probe the WDL table for a particular position.
397 // If *success != 0, the probe was successful.
398 // The return value is from the point of view of the side to move:
399 // -2 : loss
400 // -1 : loss, but draw under 50-move rule
401 //  0 : draw
402 //  1 : win, but draw under 50-move rule
403 //  2 : win
404 int Tablebases::probe_wdl(Position& pos, int *success)
405 {
406   int v;
407
408   *success = 1;
409   v = probe_ab(pos, -2, 2, success);
410
411   // If en passant is not possible, we are done.
412   if (pos.ep_square() == SQ_NONE)
413     return v;
414   if (!(*success)) return 0;
415
416   // Now handle en passant.
417   int v1 = -3;
418   // Generate (at least) all legal en passant captures.
419   ExtMove stack[192];
420   ExtMove *moves, *end;
421   StateInfo st;
422
423   if (!pos.checkers())
424     end = generate<CAPTURES>(pos, stack);
425   else
426     end = generate<EVASIONS>(pos, stack);
427
428   CheckInfo ci(pos);
429
430   for (moves = stack; moves < end; moves++) {
431     Move capture = moves->move;
432     if (type_of(capture) != ENPASSANT
433           || !pos.legal(capture, ci.pinned))
434       continue;
435     pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
436     int v0 = -probe_ab(pos, -2, 2, success);
437     pos.undo_move(capture);
438     if (*success == 0) return 0;
439     if (v0 > v1) v1 = v0;
440   }
441   if (v1 > -3) {
442     if (v1 >= v) v = v1;
443     else if (v == 0) {
444       // Check whether there is at least one legal non-ep move.
445       for (moves = stack; moves < end; moves++) {
446         Move capture = moves->move;
447         if (type_of(capture) == ENPASSANT) continue;
448         if (pos.legal(capture, ci.pinned)) break;
449       }
450       if (moves == end && !pos.checkers()) {
451         end = generate<QUIETS>(pos, end);
452         for (; moves < end; moves++) {
453           Move move = moves->move;
454           if (pos.legal(move, ci.pinned))
455             break;
456         }
457       }
458       // If not, then we are forced to play the losing ep capture.
459       if (moves == end)
460         v = v1;
461     }
462   }
463
464   return v;
465 }
466
467 // This routine treats a position with en passant captures as one without.
468 static int probe_dtz_no_ep(Position& pos, int *success)
469 {
470   int wdl, dtz;
471
472   wdl = probe_ab(pos, -2, 2, success);
473   if (*success == 0) return 0;
474
475   if (wdl == 0) return 0;
476
477   if (*success == 2)
478     return wdl == 2 ? 1 : 101;
479
480   ExtMove stack[192];
481   ExtMove *moves, *end = NULL;
482   StateInfo st;
483   CheckInfo ci(pos);
484
485   if (wdl > 0) {
486     // Generate at least all legal non-capturing pawn moves
487     // including non-capturing promotions.
488     if (!pos.checkers())
489       end = generate<NON_EVASIONS>(pos, stack);
490     else
491       end = generate<EVASIONS>(pos, stack);
492
493     for (moves = stack; moves < end; moves++) {
494       Move move = moves->move;
495       if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move)
496                 || !pos.legal(move, ci.pinned))
497         continue;
498       pos.do_move(move, st, ci, pos.gives_check(move, ci));
499       int v = -probe_ab(pos, -2, -wdl + 1, success);
500       pos.undo_move(move);
501       if (*success == 0) return 0;
502       if (v == wdl)
503         return v == 2 ? 1 : 101;
504     }
505   }
506
507   dtz = 1 + probe_dtz_table(pos, wdl, success);
508   if (*success >= 0) {
509     if (wdl & 1) dtz += 100;
510     return wdl >= 0 ? dtz : -dtz;
511   }
512
513   if (wdl > 0) {
514     int best = 0xffff;
515     for (moves = stack; moves < end; moves++) {
516       Move move = moves->move;
517       if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN
518                 || !pos.legal(move, ci.pinned))
519         continue;
520       pos.do_move(move, st, ci, pos.gives_check(move, ci));
521       int v = -Tablebases::probe_dtz(pos, success);
522       pos.undo_move(move);
523       if (*success == 0) return 0;
524       if (v > 0 && v + 1 < best)
525         best = v + 1;
526     }
527     return best;
528   } else {
529     int best = -1;
530     if (!pos.checkers())
531       end = generate<NON_EVASIONS>(pos, stack);
532     else
533       end = generate<EVASIONS>(pos, stack);
534     for (moves = stack; moves < end; moves++) {
535       int v;
536       Move move = moves->move;
537       if (!pos.legal(move, ci.pinned))
538         continue;
539       pos.do_move(move, st, ci, pos.gives_check(move, ci));
540       if (st.rule50 == 0) {
541         if (wdl == -2) v = -1;
542         else {
543           v = probe_ab(pos, 1, 2, success);
544           v = (v == 2) ? 0 : -101;
545         }
546       } else {
547         v = -Tablebases::probe_dtz(pos, success) - 1;
548       }
549       pos.undo_move(move);
550       if (*success == 0) return 0;
551       if (v < best)
552         best = v;
553     }
554     return best;
555   }
556 }
557
558 static int wdl_to_dtz[] = {
559   -1, -101, 0, 101, 1
560 };
561
562 // Probe the DTZ table for a particular position.
563 // If *success != 0, the probe was successful.
564 // The return value is from the point of view of the side to move:
565 //         n < -100 : loss, but draw under 50-move rule
566 // -100 <= n < -1   : loss in n ply (assuming 50-move counter == 0)
567 //         0        : draw
568 //     1 < n <= 100 : win in n ply (assuming 50-move counter == 0)
569 //   100 < n        : win, but draw under 50-move rule
570 //
571 // The return value n can be off by 1: a return value -n can mean a loss
572 // in n+1 ply and a return value +n can mean a win in n+1 ply. This
573 // cannot happen for tables with positions exactly on the "edge" of
574 // the 50-move rule.
575 //
576 // This implies that if dtz > 0 is returned, the position is certainly
577 // a win if dtz + 50-move-counter <= 99. Care must be taken that the engine
578 // picks moves that preserve dtz + 50-move-counter <= 99.
579 //
580 // If n = 100 immediately after a capture or pawn move, then the position
581 // is also certainly a win, and during the whole phase until the next
582 // capture or pawn move, the inequality to be preserved is
583 // dtz + 50-movecounter <= 100.
584 //
585 // In short, if a move is available resulting in dtz + 50-move-counter <= 99,
586 // then do not accept moves leading to dtz + 50-move-counter == 100.
587 //
588 int Tablebases::probe_dtz(Position& pos, int *success)
589 {
590   *success = 1;
591   int v = probe_dtz_no_ep(pos, success);
592
593   if (pos.ep_square() == SQ_NONE)
594     return v;
595   if (*success == 0) return 0;
596
597   // Now handle en passant.
598   int v1 = -3;
599
600   ExtMove stack[192];
601   ExtMove *moves, *end;
602   StateInfo st;
603
604   if (!pos.checkers())
605     end = generate<CAPTURES>(pos, stack);
606   else
607     end = generate<EVASIONS>(pos, stack);
608   CheckInfo ci(pos);
609
610   for (moves = stack; moves < end; moves++) {
611     Move capture = moves->move;
612     if (type_of(capture) != ENPASSANT
613                 || !pos.legal(capture, ci.pinned))
614       continue;
615     pos.do_move(capture, st, ci, pos.gives_check(capture, ci));
616     int v0 = -probe_ab(pos, -2, 2, success);
617     pos.undo_move(capture);
618     if (*success == 0) return 0;
619     if (v0 > v1) v1 = v0;
620   }
621   if (v1 > -3) {
622     v1 = wdl_to_dtz[v1 + 2];
623     if (v < -100) {
624       if (v1 >= 0)
625         v = v1;
626     } else if (v < 0) {
627       if (v1 >= 0 || v1 < 100)
628         v = v1;
629     } else if (v > 100) {
630       if (v1 > 0)
631         v = v1;
632     } else if (v > 0) {
633       if (v1 == 1)
634         v = v1;
635     } else if (v1 >= 0) {
636       v = v1;
637     } else {
638       for (moves = stack; moves < end; moves++) {
639         Move move = moves->move;
640         if (type_of(move) == ENPASSANT) continue;
641         if (pos.legal(move, ci.pinned)) break;
642       }
643       if (moves == end && !pos.checkers()) {
644         end = generate<QUIETS>(pos, end);
645         for (; moves < end; moves++) {
646           Move move = moves->move;
647           if (pos.legal(move, ci.pinned))
648             break;
649         }
650       }
651       if (moves == end)
652         v = v1;
653     }
654   }
655
656   return v;
657 }
658
659 // Check whether there has been at least one repetition of positions
660 // since the last capture or pawn move.
661 static int has_repeated(StateInfo *st)
662 {
663   while (1) {
664     int i = 4, e = std::min(st->rule50, st->pliesFromNull);
665     if (e < i)
666       return 0;
667     StateInfo *stp = st->previous->previous;
668     do {
669       stp = stp->previous->previous;
670       if (stp->key == st->key)
671         return 1;
672       i += 2;
673     } while (i <= e);
674     st = st->previous;
675   }
676 }
677
678 static Value wdl_to_Value[5] = {
679   -VALUE_MATE + MAX_PLY + 1,
680   VALUE_DRAW - 2,
681   VALUE_DRAW,
682   VALUE_DRAW + 2,
683   VALUE_MATE - MAX_PLY - 1
684 };
685
686 // Use the DTZ tables to filter out moves that don't preserve the win or draw.
687 // If the position is lost, but DTZ is fairly high, only keep moves that
688 // maximise DTZ.
689 //
690 // A return value false indicates that not all probes were successful and that
691 // no moves were filtered out.
692 bool Tablebases::root_probe(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
693 {
694   int success;
695
696   int dtz = probe_dtz(pos, &success);
697   if (!success) return false;
698
699   StateInfo st;
700   CheckInfo ci(pos);
701
702   // Probe each move.
703   for (size_t i = 0; i < rootMoves.size(); i++) {
704     Move move = rootMoves[i].pv[0];
705     pos.do_move(move, st, ci, pos.gives_check(move, ci));
706     int v = 0;
707     if (pos.checkers() && dtz > 0) {
708       ExtMove s[192];
709       if (generate<LEGAL>(pos, s) == s)
710         v = 1;
711     }
712     if (!v) {
713       if (st.rule50 != 0) {
714         v = -Tablebases::probe_dtz(pos, &success);
715         if (v > 0) v++;
716         else if (v < 0) v--;
717       } else {
718         v = -Tablebases::probe_wdl(pos, &success);
719         v = wdl_to_dtz[v + 2];
720       }
721     }
722     pos.undo_move(move);
723     if (!success) return false;
724     rootMoves[i].score = (Value)v;
725   }
726
727   // Obtain 50-move counter for the root position.
728   // In Stockfish there seems to be no clean way, so we do it like this:
729   int cnt50 = st.previous->rule50;
730
731   // Use 50-move counter to determine whether the root position is
732   // won, lost or drawn.
733   int wdl = 0;
734   if (dtz > 0)
735     wdl = (dtz + cnt50 <= 100) ? 2 : 1;
736   else if (dtz < 0)
737     wdl = (-dtz + cnt50 <= 100) ? -2 : -1;
738
739   // Determine the score to report to the user.
740   score = wdl_to_Value[wdl + 2];
741   // If the position is winning or losing, but too few moves left, adjust the
742   // score to show how close it is to winning or losing.
743   // NOTE: int(PawnValueEg) is used as scaling factor in score_to_uci().
744   if (wdl == 1 && dtz <= 100)
745     score = (Value)(((200 - dtz - cnt50) * int(PawnValueEg)) / 200);
746   else if (wdl == -1 && dtz >= -100)
747     score = -(Value)(((200 + dtz - cnt50) * int(PawnValueEg)) / 200);
748
749   // Now be a bit smart about filtering out moves.
750   size_t j = 0;
751   if (dtz > 0) { // winning (or 50-move rule draw)
752     int best = 0xffff;
753     for (size_t i = 0; i < rootMoves.size(); i++) {
754       int v = rootMoves[i].score;
755       if (v > 0 && v < best)
756         best = v;
757     }
758     int max = best;
759     // If the current phase has not seen repetitions, then try all moves
760     // that stay safely within the 50-move budget, if there are any.
761     if (!has_repeated(st.previous) && best + cnt50 <= 99)
762       max = 99 - cnt50;
763     for (size_t i = 0; i < rootMoves.size(); i++) {
764       int v = rootMoves[i].score;
765       if (v > 0 && v <= max)
766         rootMoves[j++] = rootMoves[i];
767     }
768   } else if (dtz < 0) { // losing (or 50-move rule draw)
769     int best = 0;
770     for (size_t i = 0; i < rootMoves.size(); i++) {
771       int v = rootMoves[i].score;
772       if (v < best)
773         best = v;
774     }
775     // Try all moves, unless we approach or have a 50-move rule draw.
776     if (-best * 2 + cnt50 < 100)
777       return true;
778     for (size_t i = 0; i < rootMoves.size(); i++) {
779       if (rootMoves[i].score == best)
780         rootMoves[j++] = rootMoves[i];
781     }
782   } else { // drawing
783     // Try all moves that preserve the draw.
784     for (size_t i = 0; i < rootMoves.size(); i++) {
785       if (rootMoves[i].score == 0)
786         rootMoves[j++] = rootMoves[i];
787     }
788   }
789   rootMoves.resize(j, Search::RootMove(MOVE_NONE));
790
791   return true;
792 }
793
794 // Use the WDL tables to filter out moves that don't preserve the win or draw.
795 // This is a fallback for the case that some or all DTZ tables are missing.
796 //
797 // A return value false indicates that not all probes were successful and that
798 // no moves were filtered out.
799 bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoveVector& rootMoves, Value& score)
800 {
801   int success;
802
803   int wdl = Tablebases::probe_wdl(pos, &success);
804   if (!success) return false;
805   score = wdl_to_Value[wdl + 2];
806
807   StateInfo st;
808   CheckInfo ci(pos);
809
810   int best = -2;
811
812   // Probe each move.
813   for (size_t i = 0; i < rootMoves.size(); i++) {
814     Move move = rootMoves[i].pv[0];
815     pos.do_move(move, st, ci, pos.gives_check(move, ci));
816     int v = -Tablebases::probe_wdl(pos, &success);
817     pos.undo_move(move);
818     if (!success) return false;
819     rootMoves[i].score = (Value)v;
820     if (v > best)
821       best = v;
822   }
823
824   size_t j = 0;
825   for (size_t i = 0; i < rootMoves.size(); i++) {
826     if (rootMoves[i].score == best)
827       rootMoves[j++] = rootMoves[i];
828   }
829   rootMoves.resize(j, Search::RootMove(MOVE_NONE));
830
831   return true;
832 }
833