Rev 169 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 169 | Rev 185 | ||
|---|---|---|---|
| Line 4... | Line 4... | ||
| 4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
| 5 | Copyright (C) 2015- |
5 | Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
| 6 | 6 | ||
| 7 | Stockfish is free software: you can redistribute it and/or modify |
7 | Stockfish is free software: you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation, either version 3 of the License, or |
9 | the Free Software Foundation, either version 3 of the License, or |
| 10 | (at your option) any later version. |
10 | (at your option) any later version. |
| Line 33... | Line 33... | ||
| 33 | #include "tt.h" |
33 | #include "tt.h" |
| 34 | #include "uci.h" |
34 | #include "uci.h" |
| 35 | #include "syzygy/tbprobe.h" |
35 | #include "syzygy/tbprobe.h" |
| 36 | 36 | ||
| 37 | using std::string; |
37 | using std::string; |
| 38 | - | ||
| 39 | namespace PSQT { |
- | |
| 40 | extern Score psq[PIECE_NB][SQUARE_NB]; |
- | |
| 41 | } |
- | |
| 42 | 38 | ||
| 43 | namespace Zobrist { |
39 | namespace Zobrist { |
| 44 | 40 | ||
| 45 | Key psq[PIECE_NB][SQUARE_NB]; |
41 | Key psq[PIECE_NB][SQUARE_NB]; |
| 46 | Key enpassant[FILE_NB]; |
42 | Key enpassant[FILE_NB]; |
| Line 50... | Line 46... | ||
| 50 | 46 | ||
| 51 | namespace { |
47 | namespace { |
| 52 | 48 | ||
| 53 | const string PieceToChar(" PNBRQK pnbrqk"); |
49 | const string PieceToChar(" PNBRQK pnbrqk"); |
| 54 | 50 | ||
| 55 |
|
51 | constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING, |
| 56 | B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING }; |
52 | B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING }; |
| 57 | 53 | ||
| 58 | // min_attacker() is a helper function used by see_ge() to locate the least |
54 | // min_attacker() is a helper function used by see_ge() to locate the least |
| 59 | // valuable attacker for the side to move, remove the attacker we just found |
55 | // valuable attacker for the side to move, remove the attacker we just found |
| 60 | // from the bitboards and scan for new X-ray attacks behind it. |
56 | // from the bitboards and scan for new X-ray attacks behind it. |
| 61 | 57 | ||
| 62 | template<int Pt> |
58 | template<int Pt> |
| 63 | PieceType min_attacker(const Bitboard* |
59 | PieceType min_attacker(const Bitboard* byTypeBB, Square to, Bitboard stmAttackers, |
| 64 | Bitboard& occupied, Bitboard& attackers) { |
60 | Bitboard& occupied, Bitboard& attackers) { |
| 65 | 61 | ||
| 66 | Bitboard b = stmAttackers & |
62 | Bitboard b = stmAttackers & byTypeBB[Pt]; |
| 67 | if (!b) |
63 | if (!b) |
| 68 | return min_attacker<Pt + 1>( |
64 | return min_attacker<Pt + 1>(byTypeBB, to, stmAttackers, occupied, attackers); |
| 69 | 65 | ||
| 70 | occupied ^= |
66 | occupied ^= lsb(b); // Remove the attacker from occupied |
| 71 | 67 | ||
| - | 68 | // Add any X-ray attack behind the just removed piece. For instance with |
|
| - | 69 | // rooks in a8 and a7 attacking a1, after removing a7 we add rook in a8. |
|
| - | 70 | // Note that new added attackers can be of any color. |
|
| 72 | if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) |
71 | if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) |
| 73 | attackers |= attacks_bb<BISHOP>(to, occupied) & ( |
72 | attackers |= attacks_bb<BISHOP>(to, occupied) & (byTypeBB[BISHOP] | byTypeBB[QUEEN]); |
| 74 | 73 | ||
| 75 | if (Pt == ROOK || Pt == QUEEN) |
74 | if (Pt == ROOK || Pt == QUEEN) |
| 76 | attackers |= attacks_bb<ROOK>(to, occupied) & ( |
75 | attackers |= attacks_bb<ROOK>(to, occupied) & (byTypeBB[ROOK] | byTypeBB[QUEEN]); |
| 77 | 76 | ||
| - | 77 | // X-ray may add already processed pieces because byTypeBB[] is constant: in |
|
| 78 |
|
78 | // the rook example, now attackers contains _again_ rook in a7, so remove it. |
| - | 79 | attackers &= occupied; |
|
| 79 | return (PieceType)Pt; |
80 | return (PieceType)Pt; |
| 80 | } |
81 | } |
| 81 | 82 | ||
| 82 | template<> |
83 | template<> |
| 83 | PieceType min_attacker<KING>(const Bitboard*, Square, Bitboard, Bitboard&, Bitboard&) { |
84 | PieceType min_attacker<KING>(const Bitboard*, Square, Bitboard, Bitboard&, Bitboard&) { |
| Line 121... | Line 122... | ||
| 121 | << "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")"; |
122 | << "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")"; |
| 122 | } |
123 | } |
| 123 | 124 | ||
| 124 | return os; |
125 | return os; |
| 125 | } |
126 | } |
| - | 127 | ||
| - | 128 | ||
| - | 129 | // Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition" |
|
| - | 130 | // situations. Description of the algorithm in the following paper: |
|
| - | 131 | // https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf |
|
| - | 132 | ||
| - | 133 | // First and second hash functions for indexing the cuckoo tables |
|
| - | 134 | inline int H1(Key h) { return h & 0x1fff; } |
|
| - | 135 | inline int H2(Key h) { return (h >> 16) & 0x1fff; } |
|
| - | 136 | ||
| - | 137 | // Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves |
|
| - | 138 | Key cuckoo[8192]; |
|
| - | 139 | Move cuckooMove[8192]; |
|
| 126 | 140 | ||
| 127 | 141 | ||
| 128 | /// Position::init() initializes at startup the various arrays used to compute |
142 | /// Position::init() initializes at startup the various arrays used to compute |
| 129 | /// hash keys. |
143 | /// hash keys. |
| 130 | 144 | ||
| Line 150... | Line 164... | ||
| 150 | } |
164 | } |
| 151 | } |
165 | } |
| 152 | 166 | ||
| 153 | Zobrist::side = rng.rand<Key>(); |
167 | Zobrist::side = rng.rand<Key>(); |
| 154 | Zobrist::noPawns = rng.rand<Key>(); |
168 | Zobrist::noPawns = rng.rand<Key>(); |
| - | 169 | ||
| - | 170 | // Prepare the cuckoo tables |
|
| - | 171 | std::memset(cuckoo, 0, sizeof(cuckoo)); |
|
| - | 172 | std::memset(cuckooMove, 0, sizeof(cuckooMove)); |
|
| - | 173 | int count = 0; |
|
| - | 174 | for (Piece pc : Pieces) |
|
| - | 175 | for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) |
|
| - | 176 | for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2) |
|
| - | 177 | if (PseudoAttacks[type_of(pc)][s1] & s2) |
|
| - | 178 | { |
|
| - | 179 | Move move = make_move(s1, s2); |
|
| - | 180 | Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side; |
|
| - | 181 | int i = H1(key); |
|
| - | 182 | while (true) |
|
| - | 183 | { |
|
| - | 184 | std::swap(cuckoo[i], key); |
|
| - | 185 | std::swap(cuckooMove[i], move); |
|
| - | 186 | if (move == 0) // Arrived at empty slot ? |
|
| - | 187 | break; |
|
| - | 188 | i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot |
|
| - | 189 | } |
|
| - | 190 | count++; |
|
| - | 191 | } |
|
| - | 192 | assert(count == 3668); |
|
| 155 | } |
193 | } |
| 156 | 194 | ||
| 157 | 195 | ||
| 158 | /// Position::set() initializes the position object with the given FEN string. |
196 | /// Position::set() initializes the position object with the given FEN string. |
| 159 | /// This function is not very robust - make sure that input FENs are correct, |
197 | /// This function is not very robust - make sure that input FENs are correct, |
| Line 315... | Line 353... | ||
| 315 | 353 | ||
| 316 | /// Position::set_check_info() sets king attacks to detect if a move gives check |
354 | /// Position::set_check_info() sets king attacks to detect if a move gives check |
| 317 | 355 | ||
| 318 | void Position::set_check_info(StateInfo* si) const { |
356 | void Position::set_check_info(StateInfo* si) const { |
| 319 | 357 | ||
| 320 | si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si-> |
358 | si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), si->pinners[BLACK]); |
| 321 | si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si-> |
359 | si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinners[WHITE]); |
| 322 | 360 | ||
| 323 | Square ksq = square<KING>(~sideToMove); |
361 | Square ksq = square<KING>(~sideToMove); |
| 324 | 362 | ||
| 325 | si->checkSquares[PAWN] = attacks_from<PAWN>(ksq, ~sideToMove); |
363 | si->checkSquares[PAWN] = attacks_from<PAWN>(ksq, ~sideToMove); |
| 326 | si->checkSquares[KNIGHT] = attacks_from<KNIGHT>(ksq); |
364 | si->checkSquares[KNIGHT] = attacks_from<KNIGHT>(ksq); |
| Line 339... | Line 377... | ||
| 339 | void Position::set_state(StateInfo* si) const { |
377 | void Position::set_state(StateInfo* si) const { |
| 340 | 378 | ||
| 341 | si->key = si->materialKey = 0; |
379 | si->key = si->materialKey = 0; |
| 342 | si->pawnKey = Zobrist::noPawns; |
380 | si->pawnKey = Zobrist::noPawns; |
| 343 | si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; |
381 | si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; |
| 344 | si->psq = SCORE_ZERO; |
- | |
| 345 | si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); |
382 | si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); |
| 346 | 383 | ||
| 347 | set_check_info(si); |
384 | set_check_info(si); |
| 348 | 385 | ||
| 349 | for (Bitboard b = pieces(); b; ) |
386 | for (Bitboard b = pieces(); b; ) |
| 350 | { |
387 | { |
| 351 | Square s = pop_lsb(&b); |
388 | Square s = pop_lsb(&b); |
| 352 | Piece pc = piece_on(s); |
389 | Piece pc = piece_on(s); |
| 353 | si->key ^= Zobrist::psq[pc][s]; |
390 | si->key ^= Zobrist::psq[pc][s]; |
| 354 | si->psq += PSQT::psq[pc][s]; |
- | |
| 355 | } |
391 | } |
| 356 | 392 | ||
| 357 | if (si->epSquare != SQ_NONE) |
393 | if (si->epSquare != SQ_NONE) |
| 358 | si->key ^= Zobrist::enpassant[file_of(si->epSquare)]; |
394 | si->key ^= Zobrist::enpassant[file_of(si->epSquare)]; |
| 359 | 395 | ||
| Line 457... | Line 493... | ||
| 457 | /// a pinned or a discovered check piece, according if its color is the opposite |
493 | /// a pinned or a discovered check piece, according if its color is the opposite |
| 458 | /// or the same of the color of the slider. |
494 | /// or the same of the color of the slider. |
| 459 | 495 | ||
| 460 | Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const { |
496 | Bitboard Position::slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const { |
| 461 | 497 | ||
| 462 | Bitboard |
498 | Bitboard blockers = 0; |
| 463 | pinners = 0; |
499 | pinners = 0; |
| 464 | 500 | ||
| 465 | // Snipers are sliders that attack 's' when a piece is removed |
501 | // Snipers are sliders that attack 's' when a piece is removed |
| 466 | Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) |
502 | Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) |
| 467 | | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; |
503 | | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; |
| Line 469... | Line 505... | ||
| 469 | while (snipers) |
505 | while (snipers) |
| 470 | { |
506 | { |
| 471 | Square sniperSq = pop_lsb(&snipers); |
507 | Square sniperSq = pop_lsb(&snipers); |
| 472 | Bitboard b = between_bb(s, sniperSq) & pieces(); |
508 | Bitboard b = between_bb(s, sniperSq) & pieces(); |
| 473 | 509 | ||
| 474 | if (!more_than_one(b)) |
510 | if (b && !more_than_one(b)) |
| 475 | { |
511 | { |
| 476 |
|
512 | blockers |= b; |
| 477 | if (b & pieces(color_of(piece_on(s)))) |
513 | if (b & pieces(color_of(piece_on(s)))) |
| 478 | pinners |= sniperSq; |
514 | pinners |= sniperSq; |
| 479 | } |
515 | } |
| 480 | } |
516 | } |
| 481 | return |
517 | return blockers; |
| 482 | } |
518 | } |
| 483 | 519 | ||
| 484 | 520 | ||
| 485 | /// Position::attackers_to() computes a bitboard of all pieces which attack a |
521 | /// Position::attackers_to() computes a bitboard of all pieces which attack a |
| 486 | /// given square. Slider attacks use the occupied bitboard to indicate occupancy. |
522 | /// given square. Slider attacks use the occupied bitboard to indicate occupancy. |
| Line 533... | Line 569... | ||
| 533 | if (type_of(piece_on(from)) == KING) |
569 | if (type_of(piece_on(from)) == KING) |
| 534 | return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us)); |
570 | return type_of(m) == CASTLING || !(attackers_to(to_sq(m)) & pieces(~us)); |
| 535 | 571 | ||
| 536 | // A non-king move is legal if and only if it is not pinned or it |
572 | // A non-king move is legal if and only if it is not pinned or it |
| 537 | // is moving along the ray towards or away from the king. |
573 | // is moving along the ray towards or away from the king. |
| 538 | return !( |
574 | return !(blockers_for_king(us) & from) |
| 539 | || aligned(from, to_sq(m), square<KING>(us)); |
575 | || aligned(from, to_sq(m), square<KING>(us)); |
| 540 | } |
576 | } |
| 541 | 577 | ||
| 542 | 578 | ||
| 543 | /// Position::pseudo_legal() takes a random move and tests whether the move is |
579 | /// Position::pseudo_legal() takes a random move and tests whether the move is |
| Line 625... | Line 661... | ||
| 625 | // Is there a direct check? |
661 | // Is there a direct check? |
| 626 | if (st->checkSquares[type_of(piece_on(from))] & to) |
662 | if (st->checkSquares[type_of(piece_on(from))] & to) |
| 627 | return true; |
663 | return true; |
| 628 | 664 | ||
| 629 | // Is there a discovered check? |
665 | // Is there a discovered check? |
| 630 | if ( ( |
666 | if ( (st->blockersForKing[~sideToMove] & from) |
| 631 | && !aligned(from, to, square<KING>(~sideToMove))) |
667 | && !aligned(from, to, square<KING>(~sideToMove))) |
| 632 | return true; |
668 | return true; |
| 633 | 669 | ||
| 634 | switch (type_of(m)) |
670 | switch (type_of(m)) |
| 635 | { |
671 | { |
| Line 710... | Line 746... | ||
| 710 | assert(captured == make_piece(us, ROOK)); |
746 | assert(captured == make_piece(us, ROOK)); |
| 711 | 747 | ||
| 712 | Square rfrom, rto; |
748 | Square rfrom, rto; |
| 713 | do_castling<true>(us, from, to, rfrom, rto); |
749 | do_castling<true>(us, from, to, rfrom, rto); |
| 714 | 750 | ||
| 715 | st->psq += PSQT::psq[captured][rto] - PSQT::psq[captured][rfrom]; |
- | |
| 716 | k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto]; |
751 | k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto]; |
| 717 | captured = NO_PIECE; |
752 | captured = NO_PIECE; |
| 718 | } |
753 | } |
| 719 | 754 | ||
| 720 | if (captured) |
755 | if (captured) |
| Line 748... | Line 783... | ||
| 748 | 783 | ||
| 749 | // Update material hash key and prefetch access to materialTable |
784 | // Update material hash key and prefetch access to materialTable |
| 750 | k ^= Zobrist::psq[captured][capsq]; |
785 | k ^= Zobrist::psq[captured][capsq]; |
| 751 | st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]]; |
786 | st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]]; |
| 752 | prefetch(thisThread->materialTable[st->materialKey]); |
787 | prefetch(thisThread->materialTable[st->materialKey]); |
| 753 | - | ||
| 754 | // Update incremental scores |
- | |
| 755 | st->psq -= PSQT::psq[captured][capsq]; |
- | |
| 756 | 788 | ||
| 757 | // Reset rule 50 counter |
789 | // Reset rule 50 counter |
| 758 | st->rule50 = 0; |
790 | st->rule50 = 0; |
| 759 | } |
791 | } |
| 760 | 792 | ||
| Line 804... | Line 836... | ||
| 804 | // Update hash keys |
836 | // Update hash keys |
| 805 | k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to]; |
837 | k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to]; |
| 806 | st->pawnKey ^= Zobrist::psq[pc][to]; |
838 | st->pawnKey ^= Zobrist::psq[pc][to]; |
| 807 | st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1] |
839 | st->materialKey ^= Zobrist::psq[promotion][pieceCount[promotion]-1] |
| 808 | ^ Zobrist::psq[pc][pieceCount[pc]]; |
840 | ^ Zobrist::psq[pc][pieceCount[pc]]; |
| 809 | - | ||
| 810 | // Update incremental score |
- | |
| 811 | st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to]; |
- | |
| 812 | 841 | ||
| 813 | // Update material |
842 | // Update material |
| 814 | st->nonPawnMaterial[us] += PieceValue[MG][promotion]; |
843 | st->nonPawnMaterial[us] += PieceValue[MG][promotion]; |
| 815 | } |
844 | } |
| 816 | 845 | ||
| Line 819... | Line 848... | ||
| 819 | prefetch2(thisThread->pawnsTable[st->pawnKey]); |
848 | prefetch2(thisThread->pawnsTable[st->pawnKey]); |
| 820 | 849 | ||
| 821 | // Reset rule 50 draw counter |
850 | // Reset rule 50 draw counter |
| 822 | st->rule50 = 0; |
851 | st->rule50 = 0; |
| 823 | } |
852 | } |
| 824 | - | ||
| 825 | // Update incremental scores |
- | |
| 826 | st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from]; |
- | |
| 827 | 853 | ||
| 828 | // Set capture piece |
854 | // Set capture piece |
| 829 | st->capturedPiece = captured; |
855 | st->capturedPiece = captured; |
| 830 | 856 | ||
| 831 | // Update the key with the final value |
857 | // Update the key with the final value |
| Line 995... | Line 1021... | ||
| 995 | 1021 | ||
| 996 | // Only deal with normal moves, assume others pass a simple see |
1022 | // Only deal with normal moves, assume others pass a simple see |
| 997 | if (type_of(m) != NORMAL) |
1023 | if (type_of(m) != NORMAL) |
| 998 | return VALUE_ZERO >= threshold; |
1024 | return VALUE_ZERO >= threshold; |
| 999 | 1025 | ||
| - | 1026 | Bitboard stmAttackers; |
|
| 1000 | Square from = from_sq(m), to = to_sq(m); |
1027 | Square from = from_sq(m), to = to_sq(m); |
| 1001 | PieceType nextVictim = type_of(piece_on(from)); |
1028 | PieceType nextVictim = type_of(piece_on(from)); |
| - | 1029 | Color us = color_of(piece_on(from)); |
|
| 1002 | Color stm = |
1030 | Color stm = ~us; // First consider opponent's move |
| 1003 | Value balance; // Values of the pieces taken by us minus opponent's ones |
1031 | Value balance; // Values of the pieces taken by us minus opponent's ones |
| 1004 | Bitboard occupied, stmAttackers; |
- | |
| 1005 | 1032 | ||
| 1006 | // The opponent may be able to recapture so this is the best result |
1033 | // The opponent may be able to recapture so this is the best result |
| 1007 | // we can hope for. |
1034 | // we can hope for. |
| 1008 | balance = PieceValue[MG][piece_on(to)] - threshold; |
1035 | balance = PieceValue[MG][piece_on(to)] - threshold; |
| 1009 | 1036 | ||
| Line 1012... | Line 1039... | ||
| 1012 | 1039 | ||
| 1013 | // Now assume the worst possible result: that the opponent can |
1040 | // Now assume the worst possible result: that the opponent can |
| 1014 | // capture our piece for free. |
1041 | // capture our piece for free. |
| 1015 | balance -= PieceValue[MG][nextVictim]; |
1042 | balance -= PieceValue[MG][nextVictim]; |
| 1016 | 1043 | ||
| - | 1044 | // If it is enough (like in PxQ) then return immediately. Note that |
|
| 1017 |
|
1045 | // in case nextVictim == KING we always return here, this is ok |
| - | 1046 | // if the given move is legal. |
|
| - | 1047 | if (balance >= VALUE_ZERO) |
|
| 1018 | return true; |
1048 | return true; |
| 1019 | 1049 | ||
| 1020 | bool opponentToMove = true; |
- | |
| 1021 | occupied = pieces() ^ from ^ to; |
- | |
| 1022 | - | ||
| 1023 | // Find all attackers to the destination square, with the moving piece |
1050 | // Find all attackers to the destination square, with the moving piece |
| 1024 | // but possibly an X-ray attacker added behind it. |
1051 | // removed, but possibly an X-ray attacker added behind it. |
| - | 1052 | Bitboard occupied = pieces() ^ from ^ to; |
|
| 1025 | Bitboard attackers = attackers_to(to, occupied) & occupied; |
1053 | Bitboard attackers = attackers_to(to, occupied) & occupied; |
| 1026 | 1054 | ||
| 1027 | while (true) |
1055 | while (true) |
| 1028 | { |
1056 | { |
| 1029 | // The balance is negative only because we assumed we could win |
- | |
| 1030 | // the last piece for free. We are truly winning only if we can |
- | |
| 1031 | // win the last piece _cheaply enough_. Test if we can actually |
- | |
| 1032 | // do this otherwise "give up". |
- | |
| 1033 | assert(balance < VALUE_ZERO); |
- | |
| 1034 | - | ||
| 1035 | stmAttackers = attackers & pieces(stm); |
1057 | stmAttackers = attackers & pieces(stm); |
| 1036 | 1058 | ||
| 1037 | // Don't allow pinned pieces to attack |
1059 | // Don't allow pinned pieces to attack (except the king) as long as |
| 1038 | // pinners are on their original square. |
1060 | // all pinners are on their original square. |
| 1039 | if (!(st-> |
1061 | if (!(st->pinners[~stm] & ~occupied)) |
| 1040 | stmAttackers &= ~st->blockersForKing[stm]; |
1062 | stmAttackers &= ~st->blockersForKing[stm]; |
| 1041 | 1063 | ||
| 1042 | // If |
1064 | // If stm has no more attackers then give up: stm loses |
| 1043 | if (!stmAttackers) |
1065 | if (!stmAttackers) |
| 1044 | break; |
1066 | break; |
| 1045 | 1067 | ||
| 1046 | // Locate and remove the next least valuable |
1068 | // Locate and remove the next least valuable attacker, and add to |
| - | 1069 | // the bitboard 'attackers' the possibly X-ray attackers behind it. |
|
| 1047 | nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers); |
1070 | nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers); |
| 1048 | 1071 | ||
| 1049 | if (nextVictim == KING) |
- | |
| 1050 | { |
- | |
| 1051 | // Our only attacker is the king. If the opponent still has |
- | |
| 1052 | // attackers we must give up. Otherwise we make the move and |
- | |
| 1053 | // (having no more attackers) the opponent must give up. |
- | |
| 1054 |
|
1072 | stm = ~stm; // Switch side to move |
| 1055 | opponentToMove = !opponentToMove; |
- | |
| 1056 | break; |
- | |
| 1057 | } |
- | |
| 1058 | 1073 | ||
| 1059 | // |
1074 | // Negamax the balance with alpha = balance, beta = balance+1 and |
| - | 1075 | // add nextVictim's value. |
|
| - | 1076 | // |
|
| 1060 |
|
1077 | // (balance, balance+1) -> (-balance-1, -balance) |
| - | 1078 | // |
|
| 1061 |
|
1079 | assert(balance < VALUE_ZERO); |
| 1062 | 1080 | ||
| 1063 |
|
1081 | balance = -balance - 1 - PieceValue[MG][nextVictim]; |
| 1064 | if (balance < VALUE_ZERO) |
- | |
| 1065 | break; |
- | |
| 1066 | 1082 | ||
| 1067 | // |
1083 | // If balance is still non-negative after giving away nextVictim then we |
| 1068 | // |
1084 | // win. The only thing to be careful about it is that we should revert |
| 1069 | // |
1085 | // stm if we captured with the king when the opponent still has attackers. |
| 1070 |
|
1086 | if (balance >= VALUE_ZERO) |
| - | 1087 | { |
|
| - | 1088 | if (nextVictim == KING && (attackers & pieces(stm))) |
|
| 1071 | stm = ~stm; |
1089 | stm = ~stm; |
| - | 1090 | break; |
|
| - | 1091 | } |
|
| - | 1092 | assert(nextVictim != KING); |
|
| 1072 | } |
1093 | } |
| 1073 | - | ||
| 1074 | // |
1094 | return us != stm; // We break the above loop when stm loses |
| 1075 | return opponentToMove; |
- | |
| 1076 | } |
1095 | } |
| 1077 | 1096 | ||
| 1078 | 1097 | ||
| 1079 | /// Position::is_draw() tests whether the position is drawn by 50-move rule |
1098 | /// Position::is_draw() tests whether the position is drawn by 50-move rule |
| 1080 | /// or by repetition. It does not detect stalemates. |
1099 | /// or by repetition. It does not detect stalemates. |
| Line 1101... | Line 1120... | ||
| 1101 | if ( stp->key == st->key |
1120 | if ( stp->key == st->key |
| 1102 | && ++cnt + (ply > i) == 2) |
1121 | && ++cnt + (ply > i) == 2) |
| 1103 | return true; |
1122 | return true; |
| 1104 | } |
1123 | } |
| 1105 | 1124 | ||
| - | 1125 | return false; |
|
| - | 1126 | } |
|
| - | 1127 | ||
| - | 1128 | ||
| - | 1129 | // Position::has_repeated() tests whether there has been at least one repetition |
|
| - | 1130 | // of positions since the last capture or pawn move. |
|
| - | 1131 | ||
| - | 1132 | bool Position::has_repeated() const { |
|
| - | 1133 | ||
| - | 1134 | StateInfo* stc = st; |
|
| - | 1135 | while (true) |
|
| - | 1136 | { |
|
| - | 1137 | int i = 4, end = std::min(stc->rule50, stc->pliesFromNull); |
|
| - | 1138 | ||
| - | 1139 | if (end < i) |
|
| - | 1140 | return false; |
|
| - | 1141 | ||
| - | 1142 | StateInfo* stp = stc->previous->previous; |
|
| - | 1143 | ||
| - | 1144 | do { |
|
| - | 1145 | stp = stp->previous->previous; |
|
| - | 1146 | ||
| - | 1147 | if (stp->key == stc->key) |
|
| - | 1148 | return true; |
|
| - | 1149 | ||
| - | 1150 | i += 2; |
|
| - | 1151 | } while (i <= end); |
|
| - | 1152 | ||
| - | 1153 | stc = stc->previous; |
|
| - | 1154 | } |
|
| - | 1155 | } |
|
| - | 1156 | ||
| - | 1157 | ||
| - | 1158 | /// Position::has_game_cycle() tests if the position has a move which draws by repetition, |
|
| - | 1159 | /// or an earlier position has a move that directly reaches the current position. |
|
| - | 1160 | ||
| - | 1161 | bool Position::has_game_cycle(int ply) const { |
|
| - | 1162 | ||
| - | 1163 | int j; |
|
| - | 1164 | ||
| - | 1165 | int end = std::min(st->rule50, st->pliesFromNull); |
|
| - | 1166 | ||
| - | 1167 | if (end < 3) |
|
| - | 1168 | return false; |
|
| - | 1169 | ||
| - | 1170 | Key originalKey = st->key; |
|
| - | 1171 | StateInfo* stp = st->previous; |
|
| - | 1172 | ||
| - | 1173 | for (int i = 3; i <= end; i += 2) |
|
| - | 1174 | { |
|
| - | 1175 | stp = stp->previous->previous; |
|
| - | 1176 | ||
| - | 1177 | Key moveKey = originalKey ^ stp->key; |
|
| - | 1178 | if ( (j = H1(moveKey), cuckoo[j] == moveKey) |
|
| - | 1179 | || (j = H2(moveKey), cuckoo[j] == moveKey)) |
|
| - | 1180 | { |
|
| - | 1181 | Move move = cuckooMove[j]; |
|
| - | 1182 | Square s1 = from_sq(move); |
|
| - | 1183 | Square s2 = to_sq(move); |
|
| - | 1184 | ||
| - | 1185 | if (!(between_bb(s1, s2) & pieces())) |
|
| - | 1186 | { |
|
| - | 1187 | // In the cuckoo table, both moves Rc1c5 and Rc5c1 are stored in the same |
|
| - | 1188 | // location. We select the legal one by reversing the move variable if necessary. |
|
| - | 1189 | if (empty(s1)) |
|
| - | 1190 | move = make_move(s2, s1); |
|
| - | 1191 | ||
| - | 1192 | if (ply > i) |
|
| - | 1193 | return true; |
|
| - | 1194 | ||
| - | 1195 | // For repetitions before or at the root, require one more |
|
| - | 1196 | StateInfo* next_stp = stp; |
|
| - | 1197 | for (int k = i + 2; k <= end; k += 2) |
|
| - | 1198 | { |
|
| - | 1199 | next_stp = next_stp->previous->previous; |
|
| - | 1200 | if (next_stp->key == stp->key) |
|
| - | 1201 | return true; |
|
| - | 1202 | } |
|
| - | 1203 | } |
|
| - | 1204 | } |
|
| - | 1205 | } |
|
| 1106 | return false; |
1206 | return false; |
| 1107 | } |
1207 | } |
| 1108 | 1208 | ||
| 1109 | 1209 | ||
| 1110 | /// Position::flip() flips position with the white and black sides reversed. This |
1210 | /// Position::flip() flips position with the white and black sides reversed. This |
| Line 1146... | Line 1246... | ||
| 1146 | /// position object and raises an asserts if something wrong is detected. |
1246 | /// position object and raises an asserts if something wrong is detected. |
| 1147 | /// This is meant to be helpful when debugging. |
1247 | /// This is meant to be helpful when debugging. |
| 1148 | 1248 | ||
| 1149 | bool Position::pos_is_ok() const { |
1249 | bool Position::pos_is_ok() const { |
| 1150 | 1250 | ||
| 1151 |
|
1251 | constexpr bool Fast = true; // Quick (default) or full check? |
| 1152 | 1252 | ||
| 1153 | if ( (sideToMove != WHITE && sideToMove != BLACK) |
1253 | if ( (sideToMove != WHITE && sideToMove != BLACK) |
| 1154 | || piece_on(square<KING>(WHITE)) != W_KING |
1254 | || piece_on(square<KING>(WHITE)) != W_KING |
| 1155 | || piece_on(square<KING>(BLACK)) != B_KING |
1255 | || piece_on(square<KING>(BLACK)) != B_KING |
| 1156 | || ( ep_square() != SQ_NONE |
1256 | || ( ep_square() != SQ_NONE |