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) { | 
| 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) |