Subversion Repositories Games.Chess Giants

Rev

Rev 96 | Rev 169 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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