Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 154 | Rev 169 | ||
---|---|---|---|
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-2018 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 30... | Line 30... | ||
30 | #include "movegen.h" |
30 | #include "movegen.h" |
31 | #include "position.h" |
31 | #include "position.h" |
32 | #include "thread.h" |
32 | #include "thread.h" |
33 | #include "tt.h" |
33 | #include "tt.h" |
34 | #include "uci.h" |
34 | #include "uci.h" |
- | 35 | #include "syzygy/tbprobe.h" |
|
35 | 36 | ||
36 | using std::string; |
37 | using std::string; |
37 | 38 | ||
38 | namespace PSQT { |
39 | namespace PSQT { |
39 | extern Score psq[PIECE_NB][SQUARE_NB]; |
40 | extern Score psq[PIECE_NB][SQUARE_NB]; |
Line 42... | Line 43... | ||
42 | namespace Zobrist { |
43 | namespace Zobrist { |
43 | 44 | ||
44 | Key psq[PIECE_NB][SQUARE_NB]; |
45 | Key psq[PIECE_NB][SQUARE_NB]; |
45 | Key enpassant[FILE_NB]; |
46 | Key enpassant[FILE_NB]; |
46 | Key castling[CASTLING_RIGHT_NB]; |
47 | Key castling[CASTLING_RIGHT_NB]; |
47 | Key |
48 | Key side, noPawns; |
48 | } |
49 | } |
49 | 50 | ||
50 | namespace { |
51 | namespace { |
51 | 52 | ||
52 | const string PieceToChar(" PNBRQK pnbrqk"); |
53 | const string PieceToChar(" PNBRQK pnbrqk"); |
53 | 54 | ||
- | 55 | const 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 }; |
|
- | 57 | ||
54 | // min_attacker() is a helper function used by |
58 | // min_attacker() is a helper function used by see_ge() to locate the least |
55 | // valuable attacker for the side to move, remove the attacker we just found |
59 | // valuable attacker for the side to move, remove the attacker we just found |
56 | // from the bitboards and scan for new X-ray attacks behind it. |
60 | // from the bitboards and scan for new X-ray attacks behind it. |
57 | 61 | ||
58 | template<int Pt> |
62 | template<int Pt> |
59 | PieceType min_attacker(const Bitboard* bb, Square to, Bitboard stmAttackers, |
63 | PieceType min_attacker(const Bitboard* bb, Square to, Bitboard stmAttackers, |
60 | Bitboard& occupied, Bitboard& attackers) { |
64 | Bitboard& occupied, Bitboard& attackers) { |
61 | 65 | ||
62 | Bitboard b = stmAttackers & bb[Pt]; |
66 | Bitboard b = stmAttackers & bb[Pt]; |
63 | if (!b) |
67 | if (!b) |
64 | return min_attacker<Pt+1>(bb, to, stmAttackers, occupied, attackers); |
68 | return min_attacker<Pt + 1>(bb, to, stmAttackers, occupied, attackers); |
65 | 69 | ||
66 | occupied ^= b & ~(b - 1); |
70 | occupied ^= b & ~(b - 1); |
67 | 71 | ||
68 | if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) |
72 | if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) |
69 | attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]); |
73 | attackers |= attacks_bb<BISHOP>(to, occupied) & (bb[BISHOP] | bb[QUEEN]); |
Line 96... | Line 100... | ||
96 | 100 | ||
97 | os << " |\n +---+---+---+---+---+---+---+---+\n"; |
101 | os << " |\n +---+---+---+---+---+---+---+---+\n"; |
98 | } |
102 | } |
99 | 103 | ||
100 | os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase |
104 | os << "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase |
- | 105 | << std::setfill('0') << std::setw(16) << pos.key() |
|
101 | << std::setfill( |
106 | << std::setfill(' ') << std::dec << "\nCheckers: "; |
102 | 107 | ||
103 | for (Bitboard b = pos.checkers(); b; ) |
108 | for (Bitboard b = pos.checkers(); b; ) |
104 | os << UCI::square(pop_lsb(&b)) << " "; |
109 | os << UCI::square(pop_lsb(&b)) << " "; |
- | 110 | ||
- | 111 | if ( int(Tablebases::MaxCardinality) >= popcount(pos.pieces()) |
|
- | 112 | && !pos.can_castle(ANY_CASTLING)) |
|
- | 113 | { |
|
- | 114 | StateInfo st; |
|
- | 115 | Position p; |
|
- | 116 | p.set(pos.fen(), pos.is_chess960(), &st, pos.this_thread()); |
|
- | 117 | Tablebases::ProbeState s1, s2; |
|
- | 118 | Tablebases::WDLScore wdl = Tablebases::probe_wdl(p, &s1); |
|
- | 119 | int dtz = Tablebases::probe_dtz(p, &s2); |
|
- | 120 | os << "\nTablebases WDL: " << std::setw(4) << wdl << " (" << s1 << ")" |
|
- | 121 | << "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")"; |
|
- | 122 | } |
|
105 | 123 | ||
106 | return os; |
124 | return os; |
107 | } |
125 | } |
108 | 126 | ||
109 | 127 | ||
Line 131... | Line 149... | ||
131 | Zobrist::castling[cr] ^= k ? k : rng.rand<Key>(); |
149 | Zobrist::castling[cr] ^= k ? k : rng.rand<Key>(); |
132 | } |
150 | } |
133 | } |
151 | } |
134 | 152 | ||
135 | Zobrist::side = rng.rand<Key>(); |
153 | Zobrist::side = rng.rand<Key>(); |
- | 154 | Zobrist::noPawns = rng.rand<Key>(); |
|
136 | } |
155 | } |
137 | 156 | ||
138 | 157 | ||
139 | /// Position::set() initializes the position object with the given FEN string. |
158 | /// Position::set() initializes the position object with the given FEN string. |
140 | /// This function is not very robust - make sure that input FENs are correct, |
159 | /// This function is not very robust - make sure that input FENs are correct, |
Line 162... | Line 181... | ||
162 | can castle queenside), "k" (Black can castle kingside), and/or "q" (Black |
181 | can castle queenside), "k" (Black can castle kingside), and/or "q" (Black |
163 | can castle queenside). |
182 | can castle queenside). |
164 | 183 | ||
165 | 4) En passant target square (in algebraic notation). If there's no en passant |
184 | 4) En passant target square (in algebraic notation). If there's no en passant |
166 | target square, this is "-". If a pawn has just made a 2-square move, this |
185 | target square, this is "-". If a pawn has just made a 2-square move, this |
167 | is the position "behind" the pawn. This is recorded |
186 | is the position "behind" the pawn. This is recorded only if there is a pawn |
168 | |
187 | in position to make an en passant capture, and if there really is a pawn |
- | 188 | that might have advanced two squares. |
|
169 | 189 | ||
170 | 5) Halfmove clock. This is the number of halfmoves since the last pawn advance |
190 | 5) Halfmove clock. This is the number of halfmoves since the last pawn advance |
171 | or capture. This is used to determine if a draw can be claimed under the |
191 | or capture. This is used to determine if a draw can be claimed under the |
172 | fifty-move rule. |
192 | fifty-move rule. |
173 | 193 | ||
Line 189... | Line 209... | ||
189 | 209 | ||
190 | // 1. Piece placement |
210 | // 1. Piece placement |
191 | while ((ss >> token) && !isspace(token)) |
211 | while ((ss >> token) && !isspace(token)) |
192 | { |
212 | { |
193 | if (isdigit(token)) |
213 | if (isdigit(token)) |
194 | sq += |
214 | sq += (token - '0') * EAST; // Advance the given number of files |
195 | 215 | ||
196 | else if (token == '/') |
216 | else if (token == '/') |
197 | sq |
217 | sq += 2 * SOUTH; |
198 | 218 | ||
199 | else if ((idx = PieceToChar.find(token)) != string::npos) |
219 | else if ((idx = PieceToChar.find(token)) != string::npos) |
200 | { |
220 | { |
201 | put_piece(Piece(idx), sq); |
221 | put_piece(Piece(idx), sq); |
202 | ++sq; |
222 | ++sq; |
Line 240... | Line 260... | ||
240 | if ( ((ss >> col) && (col >= 'a' && col <= 'h')) |
260 | if ( ((ss >> col) && (col >= 'a' && col <= 'h')) |
241 | && ((ss >> row) && (row == '3' || row == '6'))) |
261 | && ((ss >> row) && (row == '3' || row == '6'))) |
242 | { |
262 | { |
243 | st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); |
263 | st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); |
244 | 264 | ||
245 | if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN |
265 | if ( !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN)) |
- | 266 | || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)))) |
|
246 | st->epSquare = SQ_NONE; |
267 | st->epSquare = SQ_NONE; |
247 | } |
268 | } |
248 | else |
269 | else |
249 | st->epSquare = SQ_NONE; |
270 | st->epSquare = SQ_NONE; |
250 | 271 | ||
251 | // 5-6. Halfmove clock and fullmove number |
272 | // 5-6. Halfmove clock and fullmove number |
252 | ss >> std::skipws >> st->rule50 >> gamePly; |
273 | ss >> std::skipws >> st->rule50 >> gamePly; |
253 | 274 | ||
254 | // Convert from fullmove starting from 1 to |
275 | // Convert from fullmove starting from 1 to gamePly starting from 0, |
255 | // handle also common incorrect FEN with fullmove = 0. |
276 | // handle also common incorrect FEN with fullmove = 0. |
256 | gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); |
277 | gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK); |
257 | 278 | ||
258 | chess960 = isChess960; |
279 | chess960 = isChess960; |
259 | thisThread = th; |
280 | thisThread = th; |
Line 315... | Line 336... | ||
315 | /// The function is only used when a new position is set up, and to verify |
336 | /// The function is only used when a new position is set up, and to verify |
316 | /// the correctness of the StateInfo data when running in debug mode. |
337 | /// the correctness of the StateInfo data when running in debug mode. |
317 | 338 | ||
318 | void Position::set_state(StateInfo* si) const { |
339 | void Position::set_state(StateInfo* si) const { |
319 | 340 | ||
320 | si->key |
341 | si->key = si->materialKey = 0; |
- | 342 | si->pawnKey = Zobrist::noPawns; |
|
321 | si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; |
343 | si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; |
322 | si->psq = SCORE_ZERO; |
344 | si->psq = SCORE_ZERO; |
323 | si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); |
345 | si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove); |
324 | 346 | ||
325 | set_check_info(si); |
347 | set_check_info(si); |
Line 352... | Line 374... | ||
352 | si->nonPawnMaterial[color_of(pc)] += pieceCount[pc] * PieceValue[MG][pc]; |
374 | si->nonPawnMaterial[color_of(pc)] += pieceCount[pc] * PieceValue[MG][pc]; |
353 | 375 | ||
354 | for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) |
376 | for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) |
355 | si->materialKey ^= Zobrist::psq[pc][cnt]; |
377 | si->materialKey ^= Zobrist::psq[pc][cnt]; |
356 | } |
378 | } |
- | 379 | } |
|
- | 380 | ||
- | 381 | ||
- | 382 | /// Position::set() is an overload to initialize the position object with |
|
- | 383 | /// the given endgame code string like "KBPKN". It is mainly a helper to |
|
- | 384 | /// get the material key out of an endgame code. |
|
- | 385 | ||
- | 386 | Position& Position::set(const string& code, Color c, StateInfo* si) { |
|
- | 387 | ||
- | 388 | assert(code.length() > 0 && code.length() < 8); |
|
- | 389 | assert(code[0] == 'K'); |
|
- | 390 | ||
- | 391 | string sides[] = { code.substr(code.find('K', 1)), // Weak |
|
- | 392 | code.substr(0, code.find('K', 1)) }; // Strong |
|
- | 393 | ||
- | 394 | std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); |
|
- | 395 | ||
- | 396 | string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/" |
|
- | 397 | + sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10"; |
|
- | 398 | ||
- | 399 | return set(fenStr, false, si, nullptr); |
|
357 | } |
400 | } |
358 | 401 | ||
359 | 402 | ||
360 | /// Position::fen() returns a FEN representation of the position. In case of |
403 | /// Position::fen() returns a FEN representation of the position. In case of |
361 | /// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function. |
404 | /// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function. |
Line 402... | Line 445... | ||
402 | 445 | ||
403 | ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ") |
446 | ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ") |
404 | << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2; |
447 | << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2; |
405 | 448 | ||
406 | return ss.str(); |
449 | return ss.str(); |
407 | } |
- | |
408 | - | ||
409 | - | ||
410 | /// Position::game_phase() calculates the game phase interpolating total non-pawn |
- | |
411 | /// material between endgame and midgame limits. |
- | |
412 | - | ||
413 | Phase Position::game_phase() const { |
- | |
414 | - | ||
415 | Value npm = st->nonPawnMaterial[WHITE] + st->nonPawnMaterial[BLACK]; |
- | |
416 | - | ||
417 | npm = std::max(EndgameLimit, std::min(npm, MidgameLimit)); |
- | |
418 | - | ||
419 | return Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit)); |
- | |
420 | } |
450 | } |
421 | 451 | ||
422 | 452 | ||
423 | /// Position::slider_blockers() returns a bitboard of all the pieces (both colors) |
453 | /// Position::slider_blockers() returns a bitboard of all the pieces (both colors) |
424 | /// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a |
454 | /// that are blocking attacks on the square 's' from 'sliders'. A piece blocks a |
Line 431... | Line 461... | ||
431 | 461 | ||
432 | Bitboard result = 0; |
462 | Bitboard result = 0; |
433 | pinners = 0; |
463 | pinners = 0; |
434 | 464 | ||
435 | // Snipers are sliders that attack 's' when a piece is removed |
465 | // Snipers are sliders that attack 's' when a piece is removed |
436 | Bitboard snipers = ( (PseudoAttacks[ |
466 | Bitboard snipers = ( (PseudoAttacks[ ROOK][s] & pieces(QUEEN, ROOK)) |
437 | | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; |
467 | | (PseudoAttacks[BISHOP][s] & pieces(QUEEN, BISHOP))) & sliders; |
438 | 468 | ||
439 | while (snipers) |
469 | while (snipers) |
440 | { |
470 | { |
441 | Square sniperSq = pop_lsb(&snipers); |
471 | Square sniperSq = pop_lsb(&snipers); |
Line 458... | Line 488... | ||
458 | Bitboard Position::attackers_to(Square s, Bitboard occupied) const { |
488 | Bitboard Position::attackers_to(Square s, Bitboard occupied) const { |
459 | 489 | ||
460 | return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN)) |
490 | return (attacks_from<PAWN>(s, BLACK) & pieces(WHITE, PAWN)) |
461 | | (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN)) |
491 | | (attacks_from<PAWN>(s, WHITE) & pieces(BLACK, PAWN)) |
462 | | (attacks_from<KNIGHT>(s) & pieces(KNIGHT)) |
492 | | (attacks_from<KNIGHT>(s) & pieces(KNIGHT)) |
463 | | (attacks_bb< |
493 | | (attacks_bb< ROOK>(s, occupied) & pieces( ROOK, QUEEN)) |
464 | | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN)) |
494 | | (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN)) |
465 | | (attacks_from<KING>(s) & pieces(KING)); |
495 | | (attacks_from<KING>(s) & pieces(KING)); |
466 | } |
496 | } |
467 | 497 | ||
468 | 498 | ||
Line 552... | Line 582... | ||
552 | && (rank_of(from) == relative_rank(us, RANK_2)) |
582 | && (rank_of(from) == relative_rank(us, RANK_2)) |
553 | && empty(to) |
583 | && empty(to) |
554 | && empty(to - pawn_push(us)))) |
584 | && empty(to - pawn_push(us)))) |
555 | return false; |
585 | return false; |
556 | } |
586 | } |
557 | else if (!(attacks_from( |
587 | else if (!(attacks_from(type_of(pc), from) & to)) |
558 | return false; |
588 | return false; |
559 | 589 | ||
560 | // Evasions generator already takes care to avoid some kind of illegal moves |
590 | // Evasions generator already takes care to avoid some kind of illegal moves |
561 | // and legal() relies on this. We therefore have to take care that the same |
591 | // and legal() relies on this. We therefore have to take care that the same |
562 | // kind of moves are filtered out here. |
592 | // kind of moves are filtered out here. |
Line 605... | Line 635... | ||
605 | { |
635 | { |
606 | case NORMAL: |
636 | case NORMAL: |
607 | return false; |
637 | return false; |
608 | 638 | ||
609 | case PROMOTION: |
639 | case PROMOTION: |
610 | return attacks_bb |
640 | return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove); |
611 | 641 | ||
612 | // En passant capture with check? We have already handled the case |
642 | // En passant capture with check? We have already handled the case |
613 | // of direct checks and ordinary discovered check, so the only case we |
643 | // of direct checks and ordinary discovered check, so the only case we |
614 | // need to handle is the unusual case of a discovered check through |
644 | // need to handle is the unusual case of a discovered check through |
615 | // the captured pawn. |
645 | // the captured pawn. |
Line 645... | Line 675... | ||
645 | void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { |
675 | void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { |
646 | 676 | ||
647 | assert(is_ok(m)); |
677 | assert(is_ok(m)); |
648 | assert(&newSt != st); |
678 | assert(&newSt != st); |
649 | 679 | ||
650 |
|
680 | thisThread->nodes.fetch_add(1, std::memory_order_relaxed); |
651 | Key k = st->key ^ Zobrist::side; |
681 | Key k = st->key ^ Zobrist::side; |
652 | 682 | ||
653 | // Copy some fields of the old state to our new StateInfo object except the |
683 | // Copy some fields of the old state to our new StateInfo object except the |
654 | // ones which are going to be recalculated from scratch anyway and then switch |
684 | // ones which are going to be recalculated from scratch anyway and then switch |
655 | // our state pointer to point to the new (ready to be updated) state. |
685 | // our state pointer to point to the new (ready to be updated) state. |
Line 755... | Line 785... | ||
755 | { |
785 | { |
756 | // Set en-passant square if the moved pawn can be captured |
786 | // Set en-passant square if the moved pawn can be captured |
757 | if ( (int(to) ^ int(from)) == 16 |
787 | if ( (int(to) ^ int(from)) == 16 |
758 | && (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN))) |
788 | && (attacks_from<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN))) |
759 | { |
789 | { |
760 | st->epSquare = |
790 | st->epSquare = to - pawn_push(us); |
761 | k ^= Zobrist::enpassant[file_of(st->epSquare)]; |
791 | k ^= Zobrist::enpassant[file_of(st->epSquare)]; |
762 | } |
792 | } |
763 | 793 | ||
764 | else if (type_of(m) == PROMOTION) |
794 | else if (type_of(m) == PROMOTION) |
765 | { |
795 | { |
Line 784... | Line 814... | ||
784 | st->nonPawnMaterial[us] += PieceValue[MG][promotion]; |
814 | st->nonPawnMaterial[us] += PieceValue[MG][promotion]; |
785 | } |
815 | } |
786 | 816 | ||
787 | // Update pawn hash key and prefetch access to pawnsTable |
817 | // Update pawn hash key and prefetch access to pawnsTable |
788 | st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; |
818 | st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; |
789 |
|
819 | prefetch2(thisThread->pawnsTable[st->pawnKey]); |
790 | 820 | ||
791 | // Reset rule 50 draw counter |
821 | // Reset rule 50 draw counter |
792 | st->rule50 = 0; |
822 | st->rule50 = 0; |
793 | } |
823 | } |
794 | 824 | ||
Line 954... | Line 984... | ||
954 | return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from]; |
984 | return k ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from]; |
955 | } |
985 | } |
956 | 986 | ||
957 | 987 | ||
958 | /// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the |
988 | /// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the |
959 | /// SEE value of move is greater or equal to the given |
989 | /// SEE value of move is greater or equal to the given threshold. We'll use an |
960 | /// algorithm similar to alpha-beta pruning with a null window. |
990 | /// algorithm similar to alpha-beta pruning with a null window. |
961 | 991 | ||
962 | bool Position::see_ge(Move m, Value |
992 | bool Position::see_ge(Move m, Value threshold) const { |
963 | 993 | ||
964 | assert(is_ok(m)); |
994 | assert(is_ok(m)); |
965 | 995 | ||
966 | // Castling moves are implemented as king capturing the rook so cannot be |
- | |
967 | // handled correctly. Simply assume the SEE value is VALUE_ZERO that is always |
- | |
968 | // |
996 | // Only deal with normal moves, assume others pass a simple see |
969 | if (type_of(m) |
997 | if (type_of(m) != NORMAL) |
970 | return VALUE_ZERO >= |
998 | return VALUE_ZERO >= threshold; |
971 | 999 | ||
972 | Square from = from_sq(m), to = to_sq(m); |
1000 | Square from = from_sq(m), to = to_sq(m); |
973 | PieceType nextVictim = type_of(piece_on(from)); |
1001 | PieceType nextVictim = type_of(piece_on(from)); |
974 | Color stm = ~color_of(piece_on(from)); // First consider opponent's move |
1002 | Color stm = ~color_of(piece_on(from)); // First consider opponent's move |
975 | Value balance; // Values of the pieces taken by us minus opponent's ones |
1003 | Value balance; // Values of the pieces taken by us minus opponent's ones |
976 | Bitboard occupied, stmAttackers; |
1004 | Bitboard occupied, stmAttackers; |
977 | 1005 | ||
978 | if (type_of(m) == ENPASSANT) |
- | |
979 | { |
- | |
980 |
|
1006 | // The opponent may be able to recapture so this is the best result |
981 |
|
1007 | // we can hope for. |
982 | } |
- | |
983 | else |
- | |
984 | { |
- | |
985 |
|
1008 | balance = PieceValue[MG][piece_on(to)] - threshold; |
986 | occupied = 0; |
- | |
987 | } |
- | |
988 | 1009 | ||
989 | if (balance < |
1010 | if (balance < VALUE_ZERO) |
990 | return false; |
1011 | return false; |
991 | 1012 | ||
992 |
|
1013 | // Now assume the worst possible result: that the opponent can |
993 |
|
1014 | // capture our piece for free. |
994 | - | ||
995 | balance -= PieceValue[MG][nextVictim]; |
1015 | balance -= PieceValue[MG][nextVictim]; |
996 | 1016 | ||
997 | if (balance >= |
1017 | if (balance >= VALUE_ZERO) // Always true if nextVictim == KING |
998 | return true; |
1018 | return true; |
999 | 1019 | ||
1000 | bool |
1020 | bool opponentToMove = true; |
1001 | occupied |
1021 | occupied = pieces() ^ from ^ to; |
1002 | 1022 | ||
1003 | // Find all attackers to the destination square, with the moving piece removed, |
1023 | // Find all attackers to the destination square, with the moving piece removed, |
1004 | // but possibly an X-ray attacker added behind it. |
1024 | // but possibly an X-ray attacker added behind it. |
1005 | Bitboard attackers = attackers_to(to, occupied) & occupied; |
1025 | Bitboard attackers = attackers_to(to, occupied) & occupied; |
1006 | 1026 | ||
1007 | while (true) |
1027 | while (true) |
1008 | { |
1028 | { |
- | 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 | ||
1009 | stmAttackers = attackers & pieces(stm); |
1035 | stmAttackers = attackers & pieces(stm); |
1010 | 1036 | ||
1011 | // Don't allow pinned pieces to attack pieces except the king as long all |
1037 | // Don't allow pinned pieces to attack pieces except the king as long all |
1012 | // pinners are on their original square. |
1038 | // pinners are on their original square. |
1013 | if (!(st->pinnersForKing[stm] & ~occupied)) |
1039 | if (!(st->pinnersForKing[stm] & ~occupied)) |
1014 | stmAttackers &= ~st->blockersForKing[stm]; |
1040 | stmAttackers &= ~st->blockersForKing[stm]; |
1015 | 1041 | ||
- | 1042 | // If we have no more attackers we must give up |
|
1016 | if (!stmAttackers) |
1043 | if (!stmAttackers) |
1017 |
|
1044 | break; |
1018 | 1045 | ||
1019 | // Locate and remove the next least valuable attacker |
1046 | // Locate and remove the next least valuable attacker |
1020 | nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers); |
1047 | nextVictim = min_attacker<PAWN>(byTypeBB, to, stmAttackers, occupied, attackers); |
1021 | 1048 | ||
1022 | if (nextVictim == KING) |
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. |
|
1023 |
|
1054 | if (!(attackers & pieces(~stm))) |
- | 1055 | opponentToMove = !opponentToMove; |
|
- | 1056 | break; |
|
- | 1057 | } |
|
1024 | 1058 | ||
- | 1059 | // Assume the opponent can win the next piece for free and switch sides |
|
1025 | balance += |
1060 | balance += PieceValue[MG][nextVictim]; |
1026 |
|
1061 | opponentToMove = !opponentToMove; |
1027 | 1062 | ||
1028 |
|
1063 | // If balance is negative after receiving a free piece then give up |
1029 | - | ||
1030 | if |
1064 | if (balance < VALUE_ZERO) |
1031 |
|
1065 | break; |
1032 | 1066 | ||
- | 1067 | // Complete the process of switching sides. The first line swaps |
|
- | 1068 | // all negative numbers with non-negative numbers. The compiler |
|
- | 1069 | // probably knows that it is just the bitwise negation ~balance. |
|
- | 1070 | balance = -balance-1; |
|
1033 | stm = ~stm; |
1071 | stm = ~stm; |
1034 | } |
1072 | } |
- | 1073 | ||
- | 1074 | // If the opponent gave up we win, otherwise we lose. |
|
- | 1075 | return opponentToMove; |
|
1035 | } |
1076 | } |
1036 | 1077 | ||
1037 | 1078 | ||
1038 | /// Position::is_draw() tests whether the position is drawn by 50-move rule |
1079 | /// Position::is_draw() tests whether the position is drawn by 50-move rule |
1039 | /// or by repetition. It does not detect stalemates. |
1080 | /// or by repetition. It does not detect stalemates. |
1040 | 1081 | ||
1041 | bool Position::is_draw() const { |
1082 | bool Position::is_draw(int ply) const { |
1042 | 1083 | ||
1043 | if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size())) |
1084 | if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size())) |
1044 | return true; |
1085 | return true; |
1045 | 1086 | ||
- | 1087 | int end = std::min(st->rule50, st->pliesFromNull); |
|
- | 1088 | ||
- | 1089 | if (end < 4) |
|
- | 1090 | return false; |
|
- | 1091 | ||
1046 | StateInfo* stp = st; |
1092 | StateInfo* stp = st->previous->previous; |
- | 1093 | int cnt = 0; |
|
- | 1094 | ||
1047 | for (int i = |
1095 | for (int i = 4; i <= end; i += 2) |
1048 | { |
1096 | { |
1049 | stp = stp->previous->previous; |
1097 | stp = stp->previous->previous; |
1050 | 1098 | ||
- | 1099 | // Return a draw score if a position repeats once earlier but strictly |
|
- | 1100 | // after the root, or repeats twice before or at the root. |
|
1051 | if (stp->key == st->key |
1101 | if ( stp->key == st->key |
1052 |
|
1102 | && ++cnt + (ply > i) == 2) |
- | 1103 | return true; |
|
1053 | } |
1104 | } |
1054 | 1105 | ||
1055 | return false; |
1106 | return false; |
1056 | } |
1107 | } |
1057 | 1108 | ||
Line 1089... | Line 1140... | ||
1089 | 1140 | ||
1090 | assert(pos_is_ok()); |
1141 | assert(pos_is_ok()); |
1091 | } |
1142 | } |
1092 | 1143 | ||
1093 | 1144 | ||
1094 | /// Position::pos_is_ok() performs some consistency checks for the |
1145 | /// Position::pos_is_ok() performs some consistency checks for the |
- | 1146 | /// position object and raises an asserts if something wrong is detected. |
|
1095 | /// This is meant to be helpful when debugging. |
1147 | /// This is meant to be helpful when debugging. |
1096 | 1148 | ||
1097 | bool Position::pos_is_ok( |
1149 | bool Position::pos_is_ok() const { |
1098 | 1150 | ||
1099 | const bool Fast = true; // Quick (default) or full check? |
1151 | const bool Fast = true; // Quick (default) or full check? |
1100 | 1152 | ||
- | 1153 | if ( (sideToMove != WHITE && sideToMove != BLACK) |
|
- | 1154 | || piece_on(square<KING>(WHITE)) != W_KING |
|
- | 1155 | || piece_on(square<KING>(BLACK)) != B_KING |
|
- | 1156 | || ( ep_square() != SQ_NONE |
|
1101 |
|
1157 | && relative_rank(sideToMove, ep_square()) != RANK_6)) |
- | 1158 | assert(0 && "pos_is_ok: Default"); |
|
1102 | 1159 | ||
1103 | for (int step = Default; step <= (Fast ? Default : Castling); step++) |
- | |
1104 | { |
- | |
1105 |
|
1160 | if (Fast) |
1106 |
|
1161 | return true; |
1107 | 1162 | ||
1108 | if (step == Default) |
- | |
1109 | if ( (sideToMove != WHITE && sideToMove != BLACK) |
- | |
1110 |
|
1163 | if ( pieceCount[W_KING] != 1 |
1111 |
|
1164 | || pieceCount[B_KING] != 1 |
1112 | || ( ep_square() != SQ_NONE |
- | |
1113 |
|
1165 | || attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove)) |
1114 |
|
1166 | assert(0 && "pos_is_ok: Kings"); |
1115 | 1167 | ||
1116 |
|
1168 | if ( (pieces(PAWN) & (Rank1BB | Rank8BB)) |
1117 |
|
1169 | || pieceCount[W_PAWN] > 8 |
1118 |
|
1170 | || pieceCount[B_PAWN] > 8) |
1119 | || attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove)) |
- | |
1120 |
|
1171 | assert(0 && "pos_is_ok: Pawns"); |
1121 | 1172 | ||
1122 |
|
1173 | if ( (pieces(WHITE) & pieces(BLACK)) |
1123 | { |
- | |
1124 |
|
1174 | || (pieces(WHITE) | pieces(BLACK)) != pieces() |
- | 1175 | || popcount(pieces(WHITE)) > 16 |
|
1125 |
|
1176 | || popcount(pieces(BLACK)) > 16) |
1126 |
|
1177 | assert(0 && "pos_is_ok: Bitboards"); |
1127 | 1178 | ||
1128 |
|
1179 | for (PieceType p1 = PAWN; p1 <= KING; ++p1) |
1129 |
|
1180 | for (PieceType p2 = PAWN; p2 <= KING; ++p2) |
1130 |
|
1181 | if (p1 != p2 && (pieces(p1) & pieces(p2))) |
1131 |
|
1182 | assert(0 && "pos_is_ok: Bitboards"); |
1132 | } |
- | |
1133 | 1183 | ||
1134 | if (step == State) |
- | |
1135 | { |
- | |
1136 |
|
1184 | StateInfo si = *st; |
1137 |
|
1185 | set_state(&si); |
1138 |
|
1186 | if (std::memcmp(&si, st, sizeof(StateInfo))) |
1139 |
|
1187 | assert(0 && "pos_is_ok: State"); |
1140 | } |
- | |
1141 | 1188 | ||
1142 | if (step == Lists) |
- | |
1143 |
|
1189 | for (Piece pc : Pieces) |
1144 |
|
1190 | { |
1145 |
|
1191 | if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))) |
- | 1192 | || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc)) |
|
1146 |
|
1193 | assert(0 && "pos_is_ok: Pieces"); |
1147 | 1194 | ||
1148 |
|
1195 | for (int i = 0; i < pieceCount[pc]; ++i) |
1149 |
|
1196 | if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) |
1150 |
|
1197 | assert(0 && "pos_is_ok: Index"); |
1151 |
|
1198 | } |
1152 | 1199 | ||
1153 | if (step == Castling) |
- | |
1154 |
|
1200 | for (Color c = WHITE; c <= BLACK; ++c) |
1155 |
|
1201 | for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1)) |
1156 |
|
1202 | { |
1157 |
|
1203 | if (!can_castle(c | s)) |
1158 |
|
1204 | continue; |
1159 | 1205 | ||
1160 |
|
1206 | if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK) |
1161 |
|
1207 | || castlingRightsMask[castlingRookSquare[c | s]] != (c | s) |
1162 |
|
1208 | || (castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s)) |
1163 |
|
1209 | assert(0 && "pos_is_ok: Castling"); |
1164 | } |
- | |
1165 | } |
1210 | } |
1166 | 1211 | ||
1167 | return true; |
1212 | return true; |
1168 | } |
1213 | } |