Rev 96 | Rev 169 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 96 | Rev 154 | ||
---|---|---|---|
Line 13... | Line 13... | ||
13 | 13 | ||
14 | #include "../position.h" |
14 | #include "../position.h" |
15 | #include "../movegen.h" |
15 | #include "../movegen.h" |
16 | #include "../bitboard.h" |
16 | #include "../bitboard.h" |
17 | #include "../search.h" |
17 | #include "../search.h" |
18 | #include "../bitcount.h" |
- | |
19 | 18 | ||
20 | #include "tbprobe.h" |
19 | #include "tbprobe.h" |
21 | #include "tbcore.h" |
20 | #include "tbcore.h" |
22 | 21 | ||
23 | #include "tbcore.cpp" |
22 | #include "tbcore.cpp" |
24 | 23 | ||
25 | namespace Zobrist { |
24 | namespace Zobrist { |
26 | extern Key psq[ |
25 | extern Key psq[PIECE_NB][SQUARE_NB]; |
27 | } |
26 | } |
28 | 27 | ||
29 | int Tablebases::MaxCardinality = 0; |
28 | int Tablebases::MaxCardinality = 0; |
30 | 29 | ||
31 | // Given a position with 6 or fewer pieces, produce a text string |
30 | // Given a position with 6 or fewer pieces, produce a text string |
Line 37... | Line 36... | ||
37 | PieceType pt; |
36 | PieceType pt; |
38 | int i; |
37 | int i; |
39 | 38 | ||
40 | color = !mirror ? WHITE : BLACK; |
39 | color = !mirror ? WHITE : BLACK; |
41 | for (pt = KING; pt >= PAWN; --pt) |
40 | for (pt = KING; pt >= PAWN; --pt) |
42 | for (i = popcount |
41 | for (i = popcount(pos.pieces(color, pt)); i > 0; i--) |
43 | *str++ = pchr[6 - pt]; |
42 | *str++ = pchr[6 - pt]; |
44 | *str++ = 'v'; |
43 | *str++ = 'v'; |
45 | color = ~color; |
44 | color = ~color; |
46 | for (pt = KING; pt >= PAWN; --pt) |
45 | for (pt = KING; pt >= PAWN; --pt) |
47 | for (i = popcount |
46 | for (i = popcount(pos.pieces(color, pt)); i > 0; i--) |
48 | *str++ = pchr[6 - pt]; |
47 | *str++ = pchr[6 - pt]; |
49 | *str++ = 0; |
48 | *str++ = 0; |
50 | } |
49 | } |
51 | 50 | ||
52 | // Given a position, produce a 64-bit material signature key. |
51 | // Given a position, produce a 64-bit material signature key. |
Line 58... | Line 57... | ||
58 | int i; |
57 | int i; |
59 | uint64 key = 0; |
58 | uint64 key = 0; |
60 | 59 | ||
61 | color = !mirror ? WHITE : BLACK; |
60 | color = !mirror ? WHITE : BLACK; |
62 | for (pt = PAWN; pt <= KING; ++pt) |
61 | for (pt = PAWN; pt <= KING; ++pt) |
63 | for (i = popcount |
62 | for (i = popcount(pos.pieces(color, pt)); i > 0; i--) |
64 | key ^= Zobrist::psq[ |
63 | key ^= Zobrist::psq[make_piece(WHITE, pt)][i - 1]; |
65 | color = ~color; |
64 | color = ~color; |
66 | for (pt = PAWN; pt <= KING; ++pt) |
65 | for (pt = PAWN; pt <= KING; ++pt) |
67 | for (i = popcount |
66 | for (i = popcount(pos.pieces(color, pt)); i > 0; i--) |
68 | key ^= Zobrist::psq[ |
67 | key ^= Zobrist::psq[make_piece(BLACK, pt)][i - 1]; |
69 | 68 | ||
70 | return key; |
69 | return key; |
71 | } |
70 | } |
72 | 71 | ||
73 | // Produce a 64-bit material key corresponding to the material combination |
72 | // Produce a 64-bit material key corresponding to the material combination |
Line 82... | Line 81... | ||
82 | uint64 key = 0; |
81 | uint64 key = 0; |
83 | 82 | ||
84 | color = !mirror ? 0 : 8; |
83 | color = !mirror ? 0 : 8; |
85 | for (pt = PAWN; pt <= KING; ++pt) |
84 | for (pt = PAWN; pt <= KING; ++pt) |
86 | for (i = 0; i < pcs[color + pt]; i++) |
85 | for (i = 0; i < pcs[color + pt]; i++) |
87 | key ^= Zobrist::psq[ |
86 | key ^= Zobrist::psq[make_piece(WHITE, pt)][i]; |
88 | color ^= 8; |
87 | color ^= 8; |
89 | for (pt = PAWN; pt <= KING; ++pt) |
88 | for (pt = PAWN; pt <= KING; ++pt) |
90 | for (i = 0; i < pcs[color + pt]; i++) |
89 | for (i = 0; i < pcs[color + pt]; i++) |
91 | key ^= Zobrist::psq[ |
90 | key ^= Zobrist::psq[make_piece(BLACK, pt)][i]; |
92 | 91 | ||
93 | return key; |
92 | return key; |
94 | } |
93 | } |
95 | 94 | ||
96 | bool is_little_endian() { |
95 | bool is_little_endian() { |
Line 122... | Line 121... | ||
122 | 121 | ||
123 | // Obtain the position's material signature key. |
122 | // Obtain the position's material signature key. |
124 | key = pos.material_key(); |
123 | key = pos.material_key(); |
125 | 124 | ||
126 | // Test for KvK. |
125 | // Test for KvK. |
127 | if (key == (Zobrist::psq[ |
126 | if (key == (Zobrist::psq[W_KING][0] ^ Zobrist::psq[B_KING][0])) |
128 | return 0; |
127 | return 0; |
129 | 128 | ||
130 | ptr2 = TB_hash[key >> (64 - TBHASHBITS)]; |
129 | ptr2 = TB_hash[key >> (64 - TBHASHBITS)]; |
131 | for (i = 0; i < HSHMAX; i++) |
130 | for (i = 0; i < HSHMAX; i++) |
132 | if (ptr2[i].key == key) break; |
131 | if (ptr2[i].key == key) break; |
Line 359... | Line 358... | ||
359 | end = generate<CAPTURES>(pos, stack); |
358 | end = generate<CAPTURES>(pos, stack); |
360 | // Since underpromotion captures are not included, we need to add them. |
359 | // Since underpromotion captures are not included, we need to add them. |
361 | end = add_underprom_caps(pos, stack, end); |
360 | end = add_underprom_caps(pos, stack, end); |
362 | } else |
361 | } else |
363 | end = generate<EVASIONS>(pos, stack); |
362 | end = generate<EVASIONS>(pos, stack); |
364 | - | ||
365 | CheckInfo ci(pos); |
- | |
366 | 363 | ||
367 | for (moves = stack; moves < end; moves++) { |
364 | for (moves = stack; moves < end; moves++) { |
368 | Move capture = moves->move; |
365 | Move capture = moves->move; |
369 | if (!pos.capture(capture) || type_of(capture) == ENPASSANT |
366 | if (!pos.capture(capture) || type_of(capture) == ENPASSANT |
370 | || !pos.legal( |
367 | || !pos.legal(capture)) |
371 | continue; |
368 | continue; |
372 | pos.do_move(capture, st, pos.gives_check( |
369 | pos.do_move(capture, st, pos.gives_check(capture)); |
373 | v = -probe_ab(pos, -beta, -alpha, success); |
370 | v = -probe_ab(pos, -beta, -alpha, success); |
374 | pos.undo_move(capture); |
371 | pos.undo_move(capture); |
375 | if (*success == 0) return 0; |
372 | if (*success == 0) return 0; |
376 | if (v > alpha) { |
373 | if (v > alpha) { |
377 | if (v >= beta) { |
374 | if (v >= beta) { |
378 | *success = 2; |
375 | *success = 2; |
379 | return v; |
376 | return v; |
380 | } |
377 | } |
381 | alpha = v; |
378 | alpha = v; |
382 | } |
379 | } |
383 | } |
380 | } |
384 | 381 | ||
385 | v = probe_wdl_table(pos, success); |
382 | v = probe_wdl_table(pos, success); |
386 | if (*success == 0) return 0; |
383 | if (*success == 0) return 0; |
387 | if (alpha >= v) { |
384 | if (alpha >= v) { |
388 | *success = 1 + (alpha > 0); |
385 | *success = 1 + (alpha > 0); |
Line 422... | Line 419... | ||
422 | 419 | ||
423 | if (!pos.checkers()) |
420 | if (!pos.checkers()) |
424 | end = generate<CAPTURES>(pos, stack); |
421 | end = generate<CAPTURES>(pos, stack); |
425 | else |
422 | else |
426 | end = generate<EVASIONS>(pos, stack); |
423 | end = generate<EVASIONS>(pos, stack); |
427 | - | ||
428 | CheckInfo ci(pos); |
- | |
429 | 424 | ||
430 | for (moves = stack; moves < end; moves++) { |
425 | for (moves = stack; moves < end; moves++) { |
431 | Move capture = moves->move; |
426 | Move capture = moves->move; |
432 | if (type_of(capture) != ENPASSANT |
427 | if (type_of(capture) != ENPASSANT |
433 | || !pos.legal( |
428 | || !pos.legal(capture)) |
434 | continue; |
429 | continue; |
435 | pos.do_move(capture, st, pos.gives_check( |
430 | pos.do_move(capture, st, pos.gives_check(capture)); |
436 | int v0 = -probe_ab(pos, -2, 2, success); |
431 | int v0 = -probe_ab(pos, -2, 2, success); |
437 | pos.undo_move(capture); |
432 | pos.undo_move(capture); |
438 | if (*success == 0) return 0; |
433 | if (*success == 0) return 0; |
439 | if (v0 > v1) v1 = v0; |
434 | if (v0 > v1) v1 = v0; |
440 | } |
435 | } |
Line 443... | Line 438... | ||
443 | else if (v == 0) { |
438 | else if (v == 0) { |
444 | // Check whether there is at least one legal non-ep move. |
439 | // Check whether there is at least one legal non-ep move. |
445 | for (moves = stack; moves < end; moves++) { |
440 | for (moves = stack; moves < end; moves++) { |
446 | Move capture = moves->move; |
441 | Move capture = moves->move; |
447 | if (type_of(capture) == ENPASSANT) continue; |
442 | if (type_of(capture) == ENPASSANT) continue; |
448 | if (pos.legal( |
443 | if (pos.legal(capture)) break; |
449 | } |
444 | } |
450 | if (moves == end && !pos.checkers()) { |
445 | if (moves == end && !pos.checkers()) { |
451 | end = generate<QUIETS>(pos, end); |
446 | end = generate<QUIETS>(pos, end); |
452 | for (; moves < end; moves++) { |
447 | for (; moves < end; moves++) { |
453 | Move move = moves->move; |
448 | Move move = moves->move; |
454 | if (pos.legal( |
449 | if (pos.legal(move)) |
455 | break; |
450 | break; |
456 | } |
451 | } |
457 | } |
452 | } |
458 | // If not, then we are forced to play the losing ep capture. |
453 | // If not, then we are forced to play the losing ep capture. |
459 | if (moves == end) |
454 | if (moves == end) |
Line 478... | Line 473... | ||
478 | return wdl == 2 ? 1 : 101; |
473 | return wdl == 2 ? 1 : 101; |
479 | 474 | ||
480 | ExtMove stack[192]; |
475 | ExtMove stack[192]; |
481 | ExtMove *moves, *end = NULL; |
476 | ExtMove *moves, *end = NULL; |
482 | StateInfo st; |
477 | StateInfo st; |
483 | CheckInfo ci(pos); |
- | |
484 | 478 | ||
485 | if (wdl > 0) { |
479 | if (wdl > 0) { |
486 | // Generate at least all legal non-capturing pawn moves |
480 | // Generate at least all legal non-capturing pawn moves |
487 | // including non-capturing promotions. |
481 | // including non-capturing promotions. |
488 | if (!pos.checkers()) |
482 | if (!pos.checkers()) |
Line 491... | Line 485... | ||
491 | end = generate<EVASIONS>(pos, stack); |
485 | end = generate<EVASIONS>(pos, stack); |
492 | 486 | ||
493 | for (moves = stack; moves < end; moves++) { |
487 | for (moves = stack; moves < end; moves++) { |
494 | Move move = moves->move; |
488 | Move move = moves->move; |
495 | if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move) |
489 | if (type_of(pos.moved_piece(move)) != PAWN || pos.capture(move) |
496 | || !pos.legal( |
490 | || !pos.legal(move)) |
497 | continue; |
491 | continue; |
498 | pos.do_move(move, st, pos.gives_check( |
492 | pos.do_move(move, st, pos.gives_check(move)); |
499 | int v = - |
493 | int v = -Tablebases::probe_wdl(pos, success); |
500 | pos.undo_move(move); |
494 | pos.undo_move(move); |
501 | if (*success == 0) return 0; |
495 | if (*success == 0) return 0; |
502 | if (v == wdl) |
496 | if (v == wdl) |
503 | return v == 2 ? 1 : 101; |
497 | return v == 2 ? 1 : 101; |
504 | } |
498 | } |
Line 513... | Line 507... | ||
513 | if (wdl > 0) { |
507 | if (wdl > 0) { |
514 | int best = 0xffff; |
508 | int best = 0xffff; |
515 | for (moves = stack; moves < end; moves++) { |
509 | for (moves = stack; moves < end; moves++) { |
516 | Move move = moves->move; |
510 | Move move = moves->move; |
517 | if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN |
511 | if (pos.capture(move) || type_of(pos.moved_piece(move)) == PAWN |
518 | || !pos.legal( |
512 | || !pos.legal(move)) |
519 | continue; |
513 | continue; |
520 | pos.do_move(move, st, pos.gives_check( |
514 | pos.do_move(move, st, pos.gives_check(move)); |
521 | int v = -Tablebases::probe_dtz(pos, success); |
515 | int v = -Tablebases::probe_dtz(pos, success); |
522 | pos.undo_move(move); |
516 | pos.undo_move(move); |
523 | if (*success == 0) return 0; |
517 | if (*success == 0) return 0; |
524 | if (v > 0 && v + 1 < best) |
518 | if (v > 0 && v + 1 < best) |
525 | best = v + 1; |
519 | best = v + 1; |
Line 532... | Line 526... | ||
532 | else |
526 | else |
533 | end = generate<EVASIONS>(pos, stack); |
527 | end = generate<EVASIONS>(pos, stack); |
534 | for (moves = stack; moves < end; moves++) { |
528 | for (moves = stack; moves < end; moves++) { |
535 | int v; |
529 | int v; |
536 | Move move = moves->move; |
530 | Move move = moves->move; |
537 | if (!pos.legal( |
531 | if (!pos.legal(move)) |
538 | continue; |
532 | continue; |
539 | pos.do_move(move, st, pos.gives_check( |
533 | pos.do_move(move, st, pos.gives_check(move)); |
540 | if (st.rule50 == 0) { |
534 | if (st.rule50 == 0) { |
541 | if (wdl == -2) v = -1; |
535 | if (wdl == -2) v = -1; |
542 | else { |
536 | else { |
543 | v = probe_ab(pos, 1, 2, success); |
537 | v = probe_ab(pos, 1, 2, success); |
544 | v = (v == 2) ? 0 : -101; |
538 | v = (v == 2) ? 0 : -101; |
Line 603... | Line 597... | ||
603 | 597 | ||
604 | if (!pos.checkers()) |
598 | if (!pos.checkers()) |
605 | end = generate<CAPTURES>(pos, stack); |
599 | end = generate<CAPTURES>(pos, stack); |
606 | else |
600 | else |
607 | end = generate<EVASIONS>(pos, stack); |
601 | end = generate<EVASIONS>(pos, stack); |
608 | CheckInfo ci(pos); |
- | |
609 | 602 | ||
610 | for (moves = stack; moves < end; moves++) { |
603 | for (moves = stack; moves < end; moves++) { |
611 | Move capture = moves->move; |
604 | Move capture = moves->move; |
612 | if (type_of(capture) != ENPASSANT |
605 | if (type_of(capture) != ENPASSANT |
613 | || !pos.legal( |
606 | || !pos.legal(capture)) |
614 | continue; |
607 | continue; |
615 | pos.do_move(capture, st, pos.gives_check( |
608 | pos.do_move(capture, st, pos.gives_check(capture)); |
616 | int v0 = -probe_ab(pos, -2, 2, success); |
609 | int v0 = -probe_ab(pos, -2, 2, success); |
617 | pos.undo_move(capture); |
610 | pos.undo_move(capture); |
618 | if (*success == 0) return 0; |
611 | if (*success == 0) return 0; |
619 | if (v0 > v1) v1 = v0; |
612 | if (v0 > v1) v1 = v0; |
620 | } |
613 | } |
Line 636... | Line 629... | ||
636 | v = v1; |
629 | v = v1; |
637 | } else { |
630 | } else { |
638 | for (moves = stack; moves < end; moves++) { |
631 | for (moves = stack; moves < end; moves++) { |
639 | Move move = moves->move; |
632 | Move move = moves->move; |
640 | if (type_of(move) == ENPASSANT) continue; |
633 | if (type_of(move) == ENPASSANT) continue; |
641 | if (pos.legal( |
634 | if (pos.legal(move)) break; |
642 | } |
635 | } |
643 | if (moves == end && !pos.checkers()) { |
636 | if (moves == end && !pos.checkers()) { |
644 | end = generate<QUIETS>(pos, end); |
637 | end = generate<QUIETS>(pos, end); |
645 | for (; moves < end; moves++) { |
638 | for (; moves < end; moves++) { |
646 | Move move = moves->move; |
639 | Move move = moves->move; |
647 | if (pos.legal( |
640 | if (pos.legal(move)) |
648 | break; |
641 | break; |
649 | } |
642 | } |
650 | } |
643 | } |
651 | if (moves == end) |
644 | if (moves == end) |
652 | v = v1; |
645 | v = v1; |
Line 687... | Line 680... | ||
687 | // If the position is lost, but DTZ is fairly high, only keep moves that |
680 | // If the position is lost, but DTZ is fairly high, only keep moves that |
688 | // maximise DTZ. |
681 | // maximise DTZ. |
689 | // |
682 | // |
690 | // A return value false indicates that not all probes were successful and that |
683 | // A return value false indicates that not all probes were successful and that |
691 | // no moves were filtered out. |
684 | // no moves were filtered out. |
692 | bool Tablebases::root_probe(Position& pos, Search:: |
685 | bool Tablebases::root_probe(Position& pos, Search::RootMoves& rootMoves, Value& score) |
693 | { |
686 | { |
694 | int success; |
687 | int success; |
695 | 688 | ||
696 | int dtz = probe_dtz(pos, &success); |
689 | int dtz = probe_dtz(pos, &success); |
697 | if (!success) return false; |
690 | if (!success) return false; |
698 | 691 | ||
699 | StateInfo st; |
692 | StateInfo st; |
700 | CheckInfo ci(pos); |
- | |
701 | 693 | ||
702 | // Probe each move. |
694 | // Probe each move. |
703 | for (size_t i = 0; i < rootMoves.size(); i++) { |
695 | for (size_t i = 0; i < rootMoves.size(); i++) { |
704 | Move move = rootMoves[i].pv[0]; |
696 | Move move = rootMoves[i].pv[0]; |
705 | pos.do_move(move, st, pos.gives_check( |
697 | pos.do_move(move, st, pos.gives_check(move)); |
706 | int v = 0; |
698 | int v = 0; |
707 | if (pos.checkers() && dtz > 0) { |
699 | if (pos.checkers() && dtz > 0) { |
708 | ExtMove s[192]; |
700 | ExtMove s[192]; |
709 | if (generate<LEGAL>(pos, s) == s) |
701 | if (generate<LEGAL>(pos, s) == s) |
710 | v = 1; |
702 | v = 1; |
Line 794... | Line 786... | ||
794 | // Use the WDL tables to filter out moves that don't preserve the win or draw. |
786 | // 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. |
787 | // This is a fallback for the case that some or all DTZ tables are missing. |
796 | // |
788 | // |
797 | // A return value false indicates that not all probes were successful and that |
789 | // A return value false indicates that not all probes were successful and that |
798 | // no moves were filtered out. |
790 | // no moves were filtered out. |
799 | bool Tablebases::root_probe_wdl(Position& pos, Search:: |
791 | bool Tablebases::root_probe_wdl(Position& pos, Search::RootMoves& rootMoves, Value& score) |
800 | { |
792 | { |
801 | int success; |
793 | int success; |
802 | 794 | ||
803 | int wdl = Tablebases::probe_wdl(pos, &success); |
795 | int wdl = Tablebases::probe_wdl(pos, &success); |
804 | if (!success) return false; |
796 | if (!success) return false; |
805 | score = wdl_to_Value[wdl + 2]; |
797 | score = wdl_to_Value[wdl + 2]; |
806 | 798 | ||
807 | StateInfo st; |
799 | StateInfo st; |
808 | CheckInfo ci(pos); |
- | |
809 | 800 | ||
810 | int best = -2; |
801 | int best = -2; |
811 | 802 | ||
812 | // Probe each move. |
803 | // Probe each move. |
813 | for (size_t i = 0; i < rootMoves.size(); i++) { |
804 | for (size_t i = 0; i < rootMoves.size(); i++) { |
814 | Move move = rootMoves[i].pv[0]; |
805 | Move move = rootMoves[i].pv[0]; |
815 | pos.do_move(move, st, pos.gives_check( |
806 | pos.do_move(move, st, pos.gives_check(move)); |
816 | int v = -Tablebases::probe_wdl(pos, &success); |
807 | int v = -Tablebases::probe_wdl(pos, &success); |
817 | pos.undo_move(move); |
808 | pos.undo_move(move); |
818 | if (!success) return false; |
809 | if (!success) return false; |
819 | rootMoves[i].score = (Value)v; |
810 | rootMoves[i].score = (Value)v; |
820 | if (v > best) |
811 | if (v > best) |