Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/stockfish
Path: blob/master/src/position.cpp
507 views
1
/*
2
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3
Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file)
4
5
Stockfish is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
Stockfish is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
14
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "position.h"
20
21
#include <algorithm>
22
#include <array>
23
#include <cassert>
24
#include <cctype>
25
#include <cstddef>
26
#include <cstring>
27
#include <initializer_list>
28
#include <iomanip>
29
#include <iostream>
30
#include <sstream>
31
#include <string_view>
32
#include <utility>
33
34
#include "bitboard.h"
35
#include "history.h"
36
#include "misc.h"
37
#include "movegen.h"
38
#include "syzygy/tbprobe.h"
39
#include "tt.h"
40
#include "uci.h"
41
42
using std::string;
43
44
namespace Stockfish {
45
46
namespace Zobrist {
47
48
Key psq[PIECE_NB][SQUARE_NB];
49
Key enpassant[FILE_NB];
50
Key castling[CASTLING_RIGHT_NB];
51
Key side, noPawns;
52
53
}
54
55
namespace {
56
57
constexpr std::string_view PieceToChar(" PNBRQK pnbrqk");
58
59
static constexpr Piece Pieces[] = {W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
60
B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING};
61
} // namespace
62
63
64
// Returns an ASCII representation of the position
65
std::ostream& operator<<(std::ostream& os, const Position& pos) {
66
67
os << "\n +---+---+---+---+---+---+---+---+\n";
68
69
for (Rank r = RANK_8;; --r)
70
{
71
for (File f = FILE_A; f <= FILE_H; ++f)
72
os << " | " << PieceToChar[pos.piece_on(make_square(f, r))];
73
74
os << " | " << (1 + r) << "\n +---+---+---+---+---+---+---+---+\n";
75
76
if (r == RANK_1)
77
break;
78
}
79
80
os << " a b c d e f g h\n"
81
<< "\nFen: " << pos.fen() << "\nKey: " << std::hex << std::uppercase << std::setfill('0')
82
<< std::setw(16) << pos.key() << std::setfill(' ') << std::dec << "\nCheckers: ";
83
84
for (Bitboard b = pos.checkers(); b;)
85
os << UCIEngine::square(pop_lsb(b)) << " ";
86
87
if (Tablebases::MaxCardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING))
88
{
89
StateInfo st;
90
91
Position p;
92
p.set(pos.fen(), pos.is_chess960(), &st);
93
Tablebases::ProbeState s1, s2;
94
Tablebases::WDLScore wdl = Tablebases::probe_wdl(p, &s1);
95
int dtz = Tablebases::probe_dtz(p, &s2);
96
os << "\nTablebases WDL: " << std::setw(4) << wdl << " (" << s1 << ")"
97
<< "\nTablebases DTZ: " << std::setw(4) << dtz << " (" << s2 << ")";
98
}
99
100
return os;
101
}
102
103
104
// Implements Marcel van Kervinck's cuckoo algorithm to detect repetition of positions
105
// for 3-fold repetition draws. The algorithm uses two hash tables with Zobrist hashes
106
// to allow fast detection of recurring positions. For details see:
107
// http://web.archive.org/web/20201107002606/https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf
108
109
// First and second hash functions for indexing the cuckoo tables
110
inline int H1(Key h) { return h & 0x1fff; }
111
inline int H2(Key h) { return (h >> 16) & 0x1fff; }
112
113
// Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves
114
std::array<Key, 8192> cuckoo;
115
std::array<Move, 8192> cuckooMove;
116
117
// Initializes at startup the various arrays used to compute hash keys
118
void Position::init() {
119
120
PRNG rng(1070372);
121
122
for (Piece pc : Pieces)
123
for (Square s = SQ_A1; s <= SQ_H8; ++s)
124
Zobrist::psq[pc][s] = rng.rand<Key>();
125
// pawns on these squares will promote
126
std::fill_n(Zobrist::psq[W_PAWN] + SQ_A8, 8, 0);
127
std::fill_n(Zobrist::psq[B_PAWN], 8, 0);
128
129
for (File f = FILE_A; f <= FILE_H; ++f)
130
Zobrist::enpassant[f] = rng.rand<Key>();
131
132
for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr)
133
Zobrist::castling[cr] = rng.rand<Key>();
134
135
Zobrist::side = rng.rand<Key>();
136
Zobrist::noPawns = rng.rand<Key>();
137
138
// Prepare the cuckoo tables
139
cuckoo.fill(0);
140
cuckooMove.fill(Move::none());
141
[[maybe_unused]] int count = 0;
142
for (Piece pc : Pieces)
143
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
144
for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
145
if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
146
{
147
Move move = Move(s1, s2);
148
Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
149
int i = H1(key);
150
while (true)
151
{
152
std::swap(cuckoo[i], key);
153
std::swap(cuckooMove[i], move);
154
if (move == Move::none()) // Arrived at empty slot?
155
break;
156
i = (i == H1(key)) ? H2(key) : H1(key); // Push victim to alternative slot
157
}
158
count++;
159
}
160
assert(count == 3668);
161
}
162
163
164
// Initializes the position object with the given FEN string.
165
// This function is not very robust - make sure that input FENs are correct,
166
// this is assumed to be the responsibility of the GUI.
167
Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si) {
168
/*
169
A FEN string defines a particular position using only the ASCII character set.
170
171
A FEN string contains six fields separated by a space. The fields are:
172
173
1) Piece placement (from white's perspective). Each rank is described, starting
174
with rank 8 and ending with rank 1. Within each rank, the contents of each
175
square are described from file A through file H. Following the Standard
176
Algebraic Notation (SAN), each piece is identified by a single letter taken
177
from the standard English names. White pieces are designated using upper-case
178
letters ("PNBRQK") whilst Black uses lowercase ("pnbrqk"). Blank squares are
179
noted using digits 1 through 8 (the number of blank squares), and "/"
180
separates ranks.
181
182
2) Active color. "w" means white moves next, "b" means black.
183
184
3) Castling availability. If neither side can castle, this is "-". Otherwise,
185
this has one or more letters: "K" (White can castle kingside), "Q" (White
186
can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
187
can castle queenside).
188
189
4) En passant target square (in algebraic notation). If there's no en passant
190
target square, this is "-". If a pawn has just made a 2-square move, this
191
is the position "behind" the pawn. Following X-FEN standard, this is recorded
192
only if there is a pawn in position to make an en passant capture, and if
193
there really is a pawn that might have advanced two squares.
194
195
5) Halfmove clock. This is the number of halfmoves since the last pawn advance
196
or capture. This is used to determine if a draw can be claimed under the
197
fifty-move rule.
198
199
6) Fullmove number. The number of the full move. It starts at 1, and is
200
incremented after Black's move.
201
*/
202
203
unsigned char col, row, token;
204
size_t idx;
205
Square sq = SQ_A8;
206
std::istringstream ss(fenStr);
207
208
std::memset(reinterpret_cast<char*>(this), 0, sizeof(Position));
209
std::memset(si, 0, sizeof(StateInfo));
210
st = si;
211
212
ss >> std::noskipws;
213
214
// 1. Piece placement
215
while ((ss >> token) && !isspace(token))
216
{
217
if (isdigit(token))
218
sq += (token - '0') * EAST; // Advance the given number of files
219
220
else if (token == '/')
221
sq += 2 * SOUTH;
222
223
else if ((idx = PieceToChar.find(token)) != string::npos)
224
{
225
put_piece(Piece(idx), sq);
226
++sq;
227
}
228
}
229
230
// 2. Active color
231
ss >> token;
232
sideToMove = (token == 'w' ? WHITE : BLACK);
233
ss >> token;
234
235
// 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
236
// Shredder-FEN that uses the letters of the columns on which the rooks began
237
// the game instead of KQkq and also X-FEN standard that, in case of Chess960,
238
// if an inner rook is associated with the castling right, the castling tag is
239
// replaced by the file letter of the involved rook, as for the Shredder-FEN.
240
while ((ss >> token) && !isspace(token))
241
{
242
Square rsq;
243
Color c = islower(token) ? BLACK : WHITE;
244
Piece rook = make_piece(c, ROOK);
245
246
token = char(toupper(token));
247
248
if (token == 'K')
249
for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq)
250
{}
251
252
else if (token == 'Q')
253
for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq)
254
{}
255
256
else if (token >= 'A' && token <= 'H')
257
rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
258
259
else
260
continue;
261
262
set_castling_right(c, rsq);
263
}
264
265
// 4. En passant square.
266
// Ignore if square is invalid or not on side to move relative rank 6.
267
bool enpassant = false, legalEP = false;
268
269
if (((ss >> col) && (col >= 'a' && col <= 'h'))
270
&& ((ss >> row) && (row == (sideToMove == WHITE ? '6' : '3'))))
271
{
272
st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
273
274
Bitboard pawns = attacks_bb<PAWN>(st->epSquare, ~sideToMove) & pieces(sideToMove, PAWN);
275
Bitboard target = (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)));
276
Bitboard occ = pieces() ^ target ^ st->epSquare;
277
278
// En passant square will be considered only if
279
// a) side to move have a pawn threatening epSquare
280
// b) there is an enemy pawn in front of epSquare
281
// c) there is no piece on epSquare or behind epSquare
282
enpassant =
283
pawns && target && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
284
285
// If no pawn can execute the en passant capture without leaving the king in check, don't record the epSquare
286
while (pawns)
287
legalEP |= !(attackers_to(square<KING>(sideToMove), occ ^ pop_lsb(pawns))
288
& pieces(~sideToMove) & ~target);
289
}
290
291
if (!enpassant || !legalEP)
292
st->epSquare = SQ_NONE;
293
294
// 5-6. Halfmove clock and fullmove number
295
ss >> std::skipws >> st->rule50 >> gamePly;
296
297
// Convert from fullmove starting from 1 to gamePly starting from 0,
298
// handle also common incorrect FEN with fullmove = 0.
299
gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
300
301
chess960 = isChess960;
302
set_state();
303
304
assert(pos_is_ok());
305
306
return *this;
307
}
308
309
310
// Helper function used to set castling
311
// rights given the corresponding color and the rook starting square.
312
void Position::set_castling_right(Color c, Square rfrom) {
313
314
Square kfrom = square<KING>(c);
315
CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE : QUEEN_SIDE);
316
317
st->castlingRights |= cr;
318
castlingRightsMask[kfrom] |= cr;
319
castlingRightsMask[rfrom] |= cr;
320
castlingRookSquare[cr] = rfrom;
321
322
Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1);
323
Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1);
324
325
castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto)) & ~(kfrom | rfrom);
326
}
327
328
329
// Sets king attacks to detect if a move gives check
330
void Position::set_check_info() const {
331
332
update_slider_blockers(WHITE);
333
update_slider_blockers(BLACK);
334
335
Square ksq = square<KING>(~sideToMove);
336
337
st->checkSquares[PAWN] = attacks_bb<PAWN>(ksq, ~sideToMove);
338
st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
339
st->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
340
st->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces());
341
st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
342
st->checkSquares[KING] = 0;
343
}
344
345
346
// Computes the hash keys of the position, and other
347
// data that once computed is updated incrementally as moves are made.
348
// The function is only used when a new position is set up
349
void Position::set_state() const {
350
351
st->key = 0;
352
st->minorPieceKey = 0;
353
st->nonPawnKey[WHITE] = st->nonPawnKey[BLACK] = 0;
354
st->pawnKey = Zobrist::noPawns;
355
st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO;
356
st->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
357
358
set_check_info();
359
360
for (Bitboard b = pieces(); b;)
361
{
362
Square s = pop_lsb(b);
363
Piece pc = piece_on(s);
364
st->key ^= Zobrist::psq[pc][s];
365
366
if (type_of(pc) == PAWN)
367
st->pawnKey ^= Zobrist::psq[pc][s];
368
369
else
370
{
371
st->nonPawnKey[color_of(pc)] ^= Zobrist::psq[pc][s];
372
373
if (type_of(pc) != KING)
374
{
375
st->nonPawnMaterial[color_of(pc)] += PieceValue[pc];
376
377
if (type_of(pc) <= BISHOP)
378
st->minorPieceKey ^= Zobrist::psq[pc][s];
379
}
380
}
381
}
382
383
if (st->epSquare != SQ_NONE)
384
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
385
386
if (sideToMove == BLACK)
387
st->key ^= Zobrist::side;
388
389
st->key ^= Zobrist::castling[st->castlingRights];
390
st->materialKey = compute_material_key();
391
}
392
393
Key Position::compute_material_key() const {
394
Key k = 0;
395
for (Piece pc : Pieces)
396
for (int cnt = 0; cnt < pieceCount[pc]; ++cnt)
397
k ^= Zobrist::psq[pc][8 + cnt];
398
return k;
399
}
400
401
402
// Overload to initialize the position object with the given endgame code string
403
// like "KBPKN". It's mainly a helper to get the material key out of an endgame code.
404
Position& Position::set(const string& code, Color c, StateInfo* si) {
405
406
assert(code[0] == 'K');
407
408
string sides[] = {code.substr(code.find('K', 1)), // Weak
409
code.substr(0, std::min(code.find('v'), code.find('K', 1)))}; // Strong
410
411
assert(sides[0].length() > 0 && sides[0].length() < 8);
412
assert(sides[1].length() > 0 && sides[1].length() < 8);
413
414
std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);
415
416
string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/" + sides[1]
417
+ char(8 - sides[1].length() + '0') + "/8 w - - 0 10";
418
419
return set(fenStr, false, si);
420
}
421
422
423
// Returns a FEN representation of the position. In case of
424
// Chess960 the Shredder-FEN notation is used. This is mainly a debugging function.
425
string Position::fen() const {
426
427
int emptyCnt;
428
std::ostringstream ss;
429
430
for (Rank r = RANK_8;; --r)
431
{
432
for (File f = FILE_A; f <= FILE_H; ++f)
433
{
434
for (emptyCnt = 0; f <= FILE_H && empty(make_square(f, r)); ++f)
435
++emptyCnt;
436
437
if (emptyCnt)
438
ss << emptyCnt;
439
440
if (f <= FILE_H)
441
ss << PieceToChar[piece_on(make_square(f, r))];
442
}
443
444
if (r == RANK_1)
445
break;
446
ss << '/';
447
}
448
449
ss << (sideToMove == WHITE ? " w " : " b ");
450
451
if (can_castle(WHITE_OO))
452
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OO))) : 'K');
453
454
if (can_castle(WHITE_OOO))
455
ss << (chess960 ? char('A' + file_of(castling_rook_square(WHITE_OOO))) : 'Q');
456
457
if (can_castle(BLACK_OO))
458
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OO))) : 'k');
459
460
if (can_castle(BLACK_OOO))
461
ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK_OOO))) : 'q');
462
463
if (!can_castle(ANY_CASTLING))
464
ss << '-';
465
466
ss << (ep_square() == SQ_NONE ? " - " : " " + UCIEngine::square(ep_square()) + " ")
467
<< st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
468
469
return ss.str();
470
}
471
472
// Calculates st->blockersForKing[c] and st->pinners[~c],
473
// which store respectively the pieces preventing king of color c from being in check
474
// and the slider pieces of color ~c pinning pieces of color c to the king.
475
void Position::update_slider_blockers(Color c) const {
476
477
Square ksq = square<KING>(c);
478
479
st->blockersForKing[c] = 0;
480
st->pinners[~c] = 0;
481
482
// Snipers are sliders that attack 's' when a piece and other snipers are removed
483
Bitboard snipers = ((attacks_bb<ROOK>(ksq) & pieces(QUEEN, ROOK))
484
| (attacks_bb<BISHOP>(ksq) & pieces(QUEEN, BISHOP)))
485
& pieces(~c);
486
Bitboard occupancy = pieces() ^ snipers;
487
488
while (snipers)
489
{
490
Square sniperSq = pop_lsb(snipers);
491
Bitboard b = between_bb(ksq, sniperSq) & occupancy;
492
493
if (b && !more_than_one(b))
494
{
495
st->blockersForKing[c] |= b;
496
if (b & pieces(c))
497
st->pinners[~c] |= sniperSq;
498
}
499
}
500
}
501
502
503
// Computes a bitboard of all pieces which attack a given square.
504
// Slider attacks use the occupied bitboard to indicate occupancy.
505
Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
506
507
return (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN))
508
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
509
| (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
510
| (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
511
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
512
}
513
514
bool Position::attackers_to_exist(Square s, Bitboard occupied, Color c) const {
515
516
return ((attacks_bb<ROOK>(s) & pieces(c, ROOK, QUEEN))
517
&& (attacks_bb<ROOK>(s, occupied) & pieces(c, ROOK, QUEEN)))
518
|| ((attacks_bb<BISHOP>(s) & pieces(c, BISHOP, QUEEN))
519
&& (attacks_bb<BISHOP>(s, occupied) & pieces(c, BISHOP, QUEEN)))
520
|| (((attacks_bb<PAWN>(s, ~c) & pieces(PAWN)) | (attacks_bb<KNIGHT>(s) & pieces(KNIGHT))
521
| (attacks_bb<KING>(s) & pieces(KING)))
522
& pieces(c));
523
}
524
525
// Tests whether a pseudo-legal move is legal
526
bool Position::legal(Move m) const {
527
528
assert(m.is_ok());
529
530
Color us = sideToMove;
531
Square from = m.from_sq();
532
Square to = m.to_sq();
533
534
assert(color_of(moved_piece(m)) == us);
535
assert(piece_on(square<KING>(us)) == make_piece(us, KING));
536
537
// En passant captures are a tricky special case. Because they are rather
538
// uncommon, we do it simply by testing whether the king is attacked after
539
// the move is made.
540
if (m.type_of() == EN_PASSANT)
541
{
542
Square ksq = square<KING>(us);
543
Square capsq = to - pawn_push(us);
544
Bitboard occupied = (pieces() ^ from ^ capsq) | to;
545
546
assert(to == ep_square());
547
assert(moved_piece(m) == make_piece(us, PAWN));
548
assert(piece_on(capsq) == make_piece(~us, PAWN));
549
assert(piece_on(to) == NO_PIECE);
550
551
return !(attacks_bb<ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
552
&& !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
553
}
554
555
// Castling moves generation does not check if the castling path is clear of
556
// enemy attacks, it is delayed at a later time: now!
557
if (m.type_of() == CASTLING)
558
{
559
// After castling, the rook and king final positions are the same in
560
// Chess960 as they would be in standard chess.
561
to = relative_square(us, to > from ? SQ_G1 : SQ_C1);
562
Direction step = to > from ? WEST : EAST;
563
564
for (Square s = to; s != from; s += step)
565
if (attackers_to_exist(s, pieces(), ~us))
566
return false;
567
568
// In case of Chess960, verify if the Rook blocks some checks.
569
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
570
return !chess960 || !(blockers_for_king(us) & m.to_sq());
571
}
572
573
// If the moving piece is a king, check whether the destination square is
574
// attacked by the opponent.
575
if (type_of(piece_on(from)) == KING)
576
return !(attackers_to_exist(to, pieces() ^ from, ~us));
577
578
// A non-king move is legal if and only if it is not pinned or it
579
// is moving along the ray towards or away from the king.
580
return !(blockers_for_king(us) & from) || line_bb(from, to) & pieces(us, KING);
581
}
582
583
584
// Takes a random move and tests whether the move is
585
// pseudo-legal. It is used to validate moves from TT that can be corrupted
586
// due to SMP concurrent access or hash position key aliasing.
587
bool Position::pseudo_legal(const Move m) const {
588
589
Color us = sideToMove;
590
Square from = m.from_sq();
591
Square to = m.to_sq();
592
Piece pc = moved_piece(m);
593
594
// Use a slower but simpler function for uncommon cases
595
// yet we skip the legality check of MoveList<LEGAL>().
596
if (m.type_of() != NORMAL)
597
return checkers() ? MoveList<EVASIONS>(*this).contains(m)
598
: MoveList<NON_EVASIONS>(*this).contains(m);
599
600
// Is not a promotion, so the promotion piece must be empty
601
assert(m.promotion_type() - KNIGHT == NO_PIECE_TYPE);
602
603
// If the 'from' square is not occupied by a piece belonging to the side to
604
// move, the move is obviously not legal.
605
if (pc == NO_PIECE || color_of(pc) != us)
606
return false;
607
608
// The destination square cannot be occupied by a friendly piece
609
if (pieces(us) & to)
610
return false;
611
612
// Handle the special case of a pawn move
613
if (type_of(pc) == PAWN)
614
{
615
// We have already handled promotion moves, so destination cannot be on the 8th/1st rank
616
if ((Rank8BB | Rank1BB) & to)
617
return false;
618
619
// Check if it's a valid capture, single push, or double push
620
const bool isCapture = bool(attacks_bb<PAWN>(from, us) & pieces(~us) & to);
621
const bool isSinglePush = (from + pawn_push(us) == to) && empty(to);
622
const bool isDoublePush = (from + 2 * pawn_push(us) == to)
623
&& (relative_rank(us, from) == RANK_2) && empty(to)
624
&& empty(to - pawn_push(us));
625
626
if (!(isCapture || isSinglePush || isDoublePush))
627
return false;
628
}
629
else if (!(attacks_bb(type_of(pc), from, pieces()) & to))
630
return false;
631
632
// Evasions generator already takes care to avoid some kind of illegal moves
633
// and legal() relies on this. We therefore have to take care that the same
634
// kind of moves are filtered out here.
635
if (checkers())
636
{
637
if (type_of(pc) != KING)
638
{
639
// Double check? In this case, a king move is required
640
if (more_than_one(checkers()))
641
return false;
642
643
// Our move must be a blocking interposition or a capture of the checking piece
644
if (!(between_bb(square<KING>(us), lsb(checkers())) & to))
645
return false;
646
}
647
// In case of king moves under check we have to remove the king so as to catch
648
// invalid moves like b1a1 when opposite queen is on c1.
649
else if (attackers_to_exist(to, pieces() ^ from, ~us))
650
return false;
651
}
652
653
return true;
654
}
655
656
657
// Tests whether a pseudo-legal move gives a check
658
bool Position::gives_check(Move m) const {
659
660
assert(m.is_ok());
661
assert(color_of(moved_piece(m)) == sideToMove);
662
663
Square from = m.from_sq();
664
Square to = m.to_sq();
665
666
// Is there a direct check?
667
if (check_squares(type_of(piece_on(from))) & to)
668
return true;
669
670
// Is there a discovered check?
671
if (blockers_for_king(~sideToMove) & from)
672
return !(line_bb(from, to) & pieces(~sideToMove, KING)) || m.type_of() == CASTLING;
673
674
switch (m.type_of())
675
{
676
case NORMAL :
677
return false;
678
679
case PROMOTION :
680
return attacks_bb(m.promotion_type(), to, pieces() ^ from) & pieces(~sideToMove, KING);
681
682
// En passant capture with check? We have already handled the case of direct
683
// checks and ordinary discovered check, so the only case we need to handle
684
// is the unusual case of a discovered check through the captured pawn.
685
case EN_PASSANT : {
686
Square capsq = make_square(file_of(to), rank_of(from));
687
Bitboard b = (pieces() ^ from ^ capsq) | to;
688
689
return (attacks_bb<ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK))
690
| (attacks_bb<BISHOP>(square<KING>(~sideToMove), b)
691
& pieces(sideToMove, QUEEN, BISHOP));
692
}
693
default : //CASTLING
694
{
695
// Castling is encoded as 'king captures the rook'
696
Square rto = relative_square(sideToMove, to > from ? SQ_F1 : SQ_D1);
697
698
return check_squares(ROOK) & rto;
699
}
700
}
701
}
702
703
704
// Makes a move, and saves all information necessary
705
// to a StateInfo object. The move is assumed to be legal. Pseudo-legal
706
// moves should be filtered out before this function is called.
707
// If a pointer to the TT table is passed, the entry for the new position
708
// will be prefetched, and likewise for shared history.
709
void Position::do_move(Move m,
710
StateInfo& newSt,
711
bool givesCheck,
712
DirtyPiece& dp,
713
DirtyThreats& dts,
714
const TranspositionTable* tt = nullptr,
715
const SharedHistories* history = nullptr) {
716
717
assert(m.is_ok());
718
assert(&newSt != st);
719
720
Key k = st->key ^ Zobrist::side;
721
722
// Copy some fields of the old state to our new StateInfo object except the
723
// ones which are going to be recalculated from scratch anyway and then switch
724
// our state pointer to point to the new (ready to be updated) state.
725
std::memcpy(&newSt, st, offsetof(StateInfo, key));
726
newSt.previous = st;
727
st = &newSt;
728
729
// Increment ply counters. In particular, rule50 will be reset to zero later on
730
// in case of a capture or a pawn move.
731
++gamePly;
732
++st->rule50;
733
++st->pliesFromNull;
734
735
Color us = sideToMove;
736
Color them = ~us;
737
Square from = m.from_sq();
738
Square to = m.to_sq();
739
Piece pc = piece_on(from);
740
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
741
742
dp.pc = pc;
743
dp.from = from;
744
dp.to = to;
745
dp.add_sq = SQ_NONE;
746
dts.us = us;
747
dts.prevKsq = square<KING>(us);
748
dts.threatenedSqs = dts.threateningSqs = 0;
749
750
assert(color_of(pc) == us);
751
assert(captured == NO_PIECE || color_of(captured) == (m.type_of() != CASTLING ? them : us));
752
assert(type_of(captured) != KING);
753
754
if (m.type_of() == CASTLING)
755
{
756
assert(pc == make_piece(us, KING));
757
assert(captured == make_piece(us, ROOK));
758
759
Square rfrom, rto;
760
do_castling<true>(us, from, to, rfrom, rto, &dts, &dp);
761
762
k ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
763
st->nonPawnKey[us] ^= Zobrist::psq[captured][rfrom] ^ Zobrist::psq[captured][rto];
764
captured = NO_PIECE;
765
}
766
else if (captured)
767
{
768
Square capsq = to;
769
770
// If the captured piece is a pawn, update pawn hash key, otherwise
771
// update non-pawn material.
772
if (type_of(captured) == PAWN)
773
{
774
if (m.type_of() == EN_PASSANT)
775
{
776
capsq -= pawn_push(us);
777
778
assert(pc == make_piece(us, PAWN));
779
assert(to == st->epSquare);
780
assert(relative_rank(us, to) == RANK_6);
781
assert(piece_on(to) == NO_PIECE);
782
assert(piece_on(capsq) == make_piece(them, PAWN));
783
784
// Update board and piece lists in ep case, normal captures are updated later
785
remove_piece(capsq, &dts);
786
}
787
788
st->pawnKey ^= Zobrist::psq[captured][capsq];
789
}
790
else
791
{
792
st->nonPawnMaterial[them] -= PieceValue[captured];
793
st->nonPawnKey[them] ^= Zobrist::psq[captured][capsq];
794
795
if (type_of(captured) <= BISHOP)
796
st->minorPieceKey ^= Zobrist::psq[captured][capsq];
797
}
798
799
dp.remove_pc = captured;
800
dp.remove_sq = capsq;
801
802
k ^= Zobrist::psq[captured][capsq];
803
st->materialKey ^=
804
Zobrist::psq[captured][8 + pieceCount[captured] - (m.type_of() != EN_PASSANT)];
805
806
// Reset rule 50 counter
807
st->rule50 = 0;
808
}
809
else
810
dp.remove_sq = SQ_NONE;
811
812
// Update hash key
813
k ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
814
815
// Reset en passant square
816
if (st->epSquare != SQ_NONE)
817
{
818
k ^= Zobrist::enpassant[file_of(st->epSquare)];
819
st->epSquare = SQ_NONE;
820
}
821
822
// Update castling rights.
823
k ^= Zobrist::castling[st->castlingRights];
824
st->castlingRights &= ~(castlingRightsMask[from] | castlingRightsMask[to]);
825
k ^= Zobrist::castling[st->castlingRights];
826
827
// Move the piece. The tricky Chess960 castling is handled earlier
828
if (m.type_of() != CASTLING)
829
{
830
if (captured && m.type_of() != EN_PASSANT)
831
{
832
remove_piece(from, &dts);
833
swap_piece(to, pc, &dts);
834
}
835
else
836
move_piece(from, to, &dts);
837
}
838
839
// If the moving piece is a pawn do some special extra work
840
if (type_of(pc) == PAWN)
841
{
842
// Check if the en passant square needs to be set. Accurate e.p. info is needed
843
// for correct zobrist key generation and 3-fold checking.
844
if ((int(to) ^ int(from)) == 16)
845
{
846
Square epSquare = to - pawn_push(us);
847
Bitboard pawns = attacks_bb<PAWN>(epSquare, us) & pieces(them, PAWN);
848
849
// If there are no pawns attacking the ep square, ep is not possible.
850
if (pawns)
851
{
852
Square ksq = square<KING>(them);
853
Bitboard notBlockers = ~st->previous->blockersForKing[them];
854
bool noDiscovery = (from & notBlockers) || file_of(from) == file_of(ksq);
855
856
// If the pawn gives discovered check, ep is never legal. Else, if at least one
857
// pawn was not a blocker for the enemy king or lies on the same line as the
858
// enemy king and en passant square, a legal capture exists.
859
if (noDiscovery && (pawns & (notBlockers | line_bb(epSquare, ksq))))
860
{
861
st->epSquare = epSquare;
862
k ^= Zobrist::enpassant[file_of(epSquare)];
863
}
864
}
865
}
866
867
else if (m.type_of() == PROMOTION)
868
{
869
Piece promotion = make_piece(us, m.promotion_type());
870
PieceType promotionType = type_of(promotion);
871
872
assert(relative_rank(us, to) == RANK_8);
873
assert(type_of(promotion) >= KNIGHT && type_of(promotion) <= QUEEN);
874
875
swap_piece(to, promotion, &dts);
876
877
dp.add_pc = promotion;
878
dp.add_sq = to;
879
dp.to = SQ_NONE;
880
881
// Update hash keys
882
// Zobrist::psq[pc][to] is zero, so we don't need to clear it
883
k ^= Zobrist::psq[promotion][to];
884
st->materialKey ^= Zobrist::psq[promotion][8 + pieceCount[promotion] - 1]
885
^ Zobrist::psq[pc][8 + pieceCount[pc]];
886
st->nonPawnKey[us] ^= Zobrist::psq[promotion][to];
887
888
if (promotionType <= BISHOP)
889
st->minorPieceKey ^= Zobrist::psq[promotion][to];
890
891
// Update material
892
st->nonPawnMaterial[us] += PieceValue[promotion];
893
}
894
895
// Update pawn hash key
896
st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
897
898
// Reset rule 50 draw counter
899
st->rule50 = 0;
900
}
901
902
else
903
{
904
st->nonPawnKey[us] ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
905
906
if (type_of(pc) <= BISHOP)
907
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
908
}
909
910
// Update the key with the final value
911
st->key = k;
912
if (tt)
913
prefetch(tt->first_entry(key()));
914
915
if (history)
916
{
917
prefetch(&history->pawn_entry(*this)[pc][to]);
918
prefetch(&history->pawn_correction_entry(*this));
919
prefetch(&history->minor_piece_correction_entry(*this));
920
prefetch(&history->nonpawn_correction_entry<WHITE>(*this));
921
prefetch(&history->nonpawn_correction_entry<BLACK>(*this));
922
}
923
924
// Set capture piece
925
st->capturedPiece = captured;
926
927
// Calculate checkers bitboard (if move gives check)
928
st->checkersBB = givesCheck ? attackers_to(square<KING>(them)) & pieces(us) : 0;
929
930
sideToMove = ~sideToMove;
931
932
// Update king attacks used for fast check detection
933
set_check_info();
934
935
// Calculate the repetition info. It is the ply distance from the previous
936
// occurrence of the same position, negative in the 3-fold case, or zero
937
// if the position was not repeated.
938
st->repetition = 0;
939
int end = std::min(st->rule50, st->pliesFromNull);
940
if (end >= 4)
941
{
942
StateInfo* stp = st->previous->previous;
943
for (int i = 4; i <= end; i += 2)
944
{
945
stp = stp->previous->previous;
946
if (stp->key == st->key)
947
{
948
st->repetition = stp->repetition ? -i : i;
949
break;
950
}
951
}
952
}
953
954
dts.ksq = square<KING>(us);
955
956
assert(pos_is_ok());
957
958
assert(dp.pc != NO_PIECE);
959
assert(!(bool(captured) || m.type_of() == CASTLING) ^ (dp.remove_sq != SQ_NONE));
960
assert(dp.from != SQ_NONE);
961
assert(!(dp.add_sq != SQ_NONE) ^ (m.type_of() == PROMOTION || m.type_of() == CASTLING));
962
}
963
964
965
// Unmakes a move. When it returns, the position should
966
// be restored to exactly the same state as before the move was made.
967
void Position::undo_move(Move m) {
968
969
assert(m.is_ok());
970
971
sideToMove = ~sideToMove;
972
973
Color us = sideToMove;
974
Square from = m.from_sq();
975
Square to = m.to_sq();
976
Piece pc = piece_on(to);
977
978
assert(empty(from) || m.type_of() == CASTLING);
979
assert(type_of(st->capturedPiece) != KING);
980
981
if (m.type_of() == PROMOTION)
982
{
983
assert(relative_rank(us, to) == RANK_8);
984
assert(type_of(pc) == m.promotion_type());
985
assert(type_of(pc) >= KNIGHT && type_of(pc) <= QUEEN);
986
987
remove_piece(to);
988
pc = make_piece(us, PAWN);
989
put_piece(pc, to);
990
}
991
992
if (m.type_of() == CASTLING)
993
{
994
Square rfrom, rto;
995
do_castling<false>(us, from, to, rfrom, rto);
996
}
997
else
998
{
999
move_piece(to, from); // Put the piece back at the source square
1000
1001
if (st->capturedPiece)
1002
{
1003
Square capsq = to;
1004
1005
if (m.type_of() == EN_PASSANT)
1006
{
1007
capsq -= pawn_push(us);
1008
1009
assert(type_of(pc) == PAWN);
1010
assert(to == st->previous->epSquare);
1011
assert(relative_rank(us, to) == RANK_6);
1012
assert(piece_on(capsq) == NO_PIECE);
1013
assert(st->capturedPiece == make_piece(~us, PAWN));
1014
}
1015
1016
put_piece(st->capturedPiece, capsq); // Restore the captured piece
1017
}
1018
}
1019
1020
// Finally point our state pointer back to the previous state
1021
st = st->previous;
1022
--gamePly;
1023
1024
assert(pos_is_ok());
1025
}
1026
1027
template<bool PutPiece>
1028
inline void add_dirty_threat(
1029
DirtyThreats* const dts, Piece pc, Piece threatened, Square s, Square threatenedSq) {
1030
if (PutPiece)
1031
{
1032
dts->threatenedSqs |= threatenedSq;
1033
dts->threateningSqs |= s;
1034
}
1035
1036
dts->list.push_back({pc, threatened, s, threatenedSq, PutPiece});
1037
}
1038
1039
#ifdef USE_AVX512ICL
1040
// Given a DirtyThreat template and bit offsets to insert the piece type and square, write the threats
1041
// present at the given bitboard.
1042
template<int SqShift, int PcShift>
1043
void write_multiple_dirties(const Position& p,
1044
Bitboard mask,
1045
DirtyThreat dt_template,
1046
DirtyThreats* dts) {
1047
static_assert(sizeof(DirtyThreat) == 4);
1048
1049
const __m512i board = _mm512_loadu_si512(p.piece_array().data());
1050
const __m512i AllSquares = _mm512_set_epi8(
1051
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41,
1052
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
1053
17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
1054
1055
const int dt_count = popcount(mask);
1056
assert(dt_count <= 16);
1057
1058
const __m512i template_v = _mm512_set1_epi32(dt_template.raw());
1059
auto* write = dts->list.make_space(dt_count);
1060
1061
// Extract the list of squares and upconvert to 32 bits. There are never more than 16
1062
// incoming threats so this is sufficient.
1063
__m512i threat_squares = _mm512_maskz_compress_epi8(mask, AllSquares);
1064
threat_squares = _mm512_cvtepi8_epi32(_mm512_castsi512_si128(threat_squares));
1065
1066
__m512i threat_pieces =
1067
_mm512_maskz_permutexvar_epi8(0x1111111111111111ULL, threat_squares, board);
1068
1069
// Shift the piece and square into place
1070
threat_squares = _mm512_slli_epi32(threat_squares, SqShift);
1071
threat_pieces = _mm512_slli_epi32(threat_pieces, PcShift);
1072
1073
const __m512i dirties =
1074
_mm512_ternarylogic_epi32(template_v, threat_squares, threat_pieces, 254 /* A | B | C */);
1075
_mm512_storeu_si512(reinterpret_cast<__m512i*>(write), dirties);
1076
}
1077
#endif
1078
1079
template<bool PutPiece, bool ComputeRay>
1080
void Position::update_piece_threats(Piece pc,
1081
Square s,
1082
DirtyThreats* const dts,
1083
[[maybe_unused]] Bitboard noRaysContaining) const {
1084
const Bitboard occupied = pieces();
1085
const Bitboard rookQueens = pieces(ROOK, QUEEN);
1086
const Bitboard bishopQueens = pieces(BISHOP, QUEEN);
1087
const Bitboard knights = pieces(KNIGHT);
1088
const Bitboard kings = pieces(KING);
1089
const Bitboard whitePawns = pieces(WHITE, PAWN);
1090
const Bitboard blackPawns = pieces(BLACK, PAWN);
1091
1092
const Bitboard rAttacks = attacks_bb<ROOK>(s, occupied);
1093
const Bitboard bAttacks = attacks_bb<BISHOP>(s, occupied);
1094
1095
Bitboard threatened = attacks_bb(pc, s, occupied) & occupied;
1096
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
1097
Bitboard incoming_threats =
1098
(PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb<PAWN>(s, WHITE) & blackPawns)
1099
| (attacks_bb<PAWN>(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings);
1100
1101
#ifdef USE_AVX512ICL
1102
if constexpr (PutPiece)
1103
{
1104
dts->threatenedSqs |= threatened;
1105
dts->threateningSqs |= s;
1106
}
1107
1108
DirtyThreat dt_template{pc, NO_PIECE, s, Square(0), PutPiece};
1109
write_multiple_dirties<DirtyThreat::ThreatenedSqOffset, DirtyThreat::ThreatenedPcOffset>(
1110
*this, threatened, dt_template, dts);
1111
1112
Bitboard all_attackers = sliders | incoming_threats;
1113
1114
if constexpr (PutPiece)
1115
{
1116
dts->threatenedSqs |= s;
1117
dts->threateningSqs |= all_attackers;
1118
}
1119
1120
dt_template = {NO_PIECE, pc, Square(0), s, PutPiece};
1121
write_multiple_dirties<DirtyThreat::PcSqOffset, DirtyThreat::PcOffset>(*this, all_attackers,
1122
dt_template, dts);
1123
#else
1124
while (threatened)
1125
{
1126
Square threatenedSq = pop_lsb(threatened);
1127
Piece threatenedPc = piece_on(threatenedSq);
1128
1129
assert(threatenedSq != s);
1130
assert(threatenedPc);
1131
1132
add_dirty_threat<PutPiece>(dts, pc, threatenedPc, s, threatenedSq);
1133
}
1134
#endif
1135
1136
if constexpr (ComputeRay)
1137
{
1138
while (sliders)
1139
{
1140
Square sliderSq = pop_lsb(sliders);
1141
Piece slider = piece_on(sliderSq);
1142
1143
const Bitboard ray = RayPassBB[sliderSq][s] & ~BetweenBB[sliderSq][s];
1144
const Bitboard discovered = ray & (rAttacks | bAttacks) & occupied;
1145
1146
assert(!more_than_one(discovered));
1147
if (discovered && (RayPassBB[sliderSq][s] & noRaysContaining) != noRaysContaining)
1148
{
1149
const Square threatenedSq = lsb(discovered);
1150
const Piece threatenedPc = piece_on(threatenedSq);
1151
add_dirty_threat<!PutPiece>(dts, slider, threatenedPc, sliderSq, threatenedSq);
1152
}
1153
1154
#ifndef USE_AVX512ICL // for ICL, direct threats were processed earlier (all_attackers)
1155
add_dirty_threat<PutPiece>(dts, slider, pc, sliderSq, s);
1156
#endif
1157
}
1158
}
1159
else
1160
{
1161
incoming_threats |= sliders;
1162
}
1163
1164
#ifndef USE_AVX512ICL
1165
while (incoming_threats)
1166
{
1167
Square srcSq = pop_lsb(incoming_threats);
1168
Piece srcPc = piece_on(srcSq);
1169
1170
assert(srcSq != s);
1171
assert(srcPc != NO_PIECE);
1172
1173
add_dirty_threat<PutPiece>(dts, srcPc, pc, srcSq, s);
1174
}
1175
#endif
1176
}
1177
1178
// Helper used to do/undo a castling move. This is a bit
1179
// tricky in Chess960 where from/to squares can overlap.
1180
template<bool Do>
1181
void Position::do_castling(Color us,
1182
Square from,
1183
Square& to,
1184
Square& rfrom,
1185
Square& rto,
1186
DirtyThreats* const dts,
1187
DirtyPiece* const dp) {
1188
1189
bool kingSide = to > from;
1190
rfrom = to; // Castling is encoded as "king captures friendly rook"
1191
rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
1192
to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
1193
1194
assert(!Do || dp);
1195
1196
if (Do)
1197
{
1198
dp->to = to;
1199
dp->remove_pc = dp->add_pc = make_piece(us, ROOK);
1200
dp->remove_sq = rfrom;
1201
dp->add_sq = rto;
1202
}
1203
1204
// Remove both pieces first since squares could overlap in Chess960
1205
remove_piece(Do ? from : to, dts);
1206
remove_piece(Do ? rfrom : rto, dts);
1207
put_piece(make_piece(us, KING), Do ? to : from, dts);
1208
put_piece(make_piece(us, ROOK), Do ? rto : rfrom, dts);
1209
}
1210
1211
1212
// Used to do a "null move": it flips
1213
// the side to move without executing any move on the board.
1214
void Position::do_null_move(StateInfo& newSt) {
1215
1216
assert(!checkers());
1217
assert(&newSt != st);
1218
1219
std::memcpy(&newSt, st, sizeof(StateInfo));
1220
1221
newSt.previous = st;
1222
st = &newSt;
1223
1224
if (st->epSquare != SQ_NONE)
1225
{
1226
st->key ^= Zobrist::enpassant[file_of(st->epSquare)];
1227
st->epSquare = SQ_NONE;
1228
}
1229
1230
st->key ^= Zobrist::side;
1231
1232
st->pliesFromNull = 0;
1233
1234
sideToMove = ~sideToMove;
1235
1236
set_check_info();
1237
1238
st->repetition = 0;
1239
1240
assert(pos_is_ok());
1241
}
1242
1243
1244
// Must be used to undo a "null move"
1245
void Position::undo_null_move() {
1246
1247
assert(!checkers());
1248
1249
st = st->previous;
1250
sideToMove = ~sideToMove;
1251
}
1252
1253
1254
// Tests if the SEE (Static Exchange Evaluation)
1255
// value of move is greater or equal to the given threshold. We'll use an
1256
// algorithm similar to alpha-beta pruning with a null window.
1257
bool Position::see_ge(Move m, int threshold) const {
1258
1259
assert(m.is_ok());
1260
1261
// Only deal with normal moves, assume others pass a simple SEE
1262
if (m.type_of() != NORMAL)
1263
return VALUE_ZERO >= threshold;
1264
1265
Square from = m.from_sq(), to = m.to_sq();
1266
1267
assert(piece_on(from) != NO_PIECE);
1268
1269
int swap = PieceValue[piece_on(to)] - threshold;
1270
if (swap < 0)
1271
return false;
1272
1273
swap = PieceValue[piece_on(from)] - swap;
1274
if (swap <= 0)
1275
return true;
1276
1277
assert(color_of(piece_on(from)) == sideToMove);
1278
Bitboard occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic
1279
Color stm = sideToMove;
1280
Bitboard attackers = attackers_to(to, occupied);
1281
Bitboard stmAttackers, bb;
1282
int res = 1;
1283
1284
while (true)
1285
{
1286
stm = ~stm;
1287
attackers &= occupied;
1288
1289
// If stm has no more attackers then give up: stm loses
1290
if (!(stmAttackers = attackers & pieces(stm)))
1291
break;
1292
1293
// Don't allow pinned pieces to attack as long as there are
1294
// pinners on their original square.
1295
if (pinners(~stm) & occupied)
1296
{
1297
stmAttackers &= ~blockers_for_king(stm);
1298
1299
if (!stmAttackers)
1300
break;
1301
}
1302
1303
res ^= 1;
1304
1305
// Locate and remove the next least valuable attacker, and add to
1306
// the bitboard 'attackers' any X-ray attackers behind it.
1307
if ((bb = stmAttackers & pieces(PAWN)))
1308
{
1309
if ((swap = PawnValue - swap) < res)
1310
break;
1311
occupied ^= least_significant_square_bb(bb);
1312
1313
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
1314
}
1315
1316
else if ((bb = stmAttackers & pieces(KNIGHT)))
1317
{
1318
if ((swap = KnightValue - swap) < res)
1319
break;
1320
occupied ^= least_significant_square_bb(bb);
1321
}
1322
1323
else if ((bb = stmAttackers & pieces(BISHOP)))
1324
{
1325
if ((swap = BishopValue - swap) < res)
1326
break;
1327
occupied ^= least_significant_square_bb(bb);
1328
1329
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
1330
}
1331
1332
else if ((bb = stmAttackers & pieces(ROOK)))
1333
{
1334
if ((swap = RookValue - swap) < res)
1335
break;
1336
occupied ^= least_significant_square_bb(bb);
1337
1338
attackers |= attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN);
1339
}
1340
1341
else if ((bb = stmAttackers & pieces(QUEEN)))
1342
{
1343
swap = QueenValue - swap;
1344
// implies that the previous recapture was done by a higher rated piece than a Queen (King is excluded)
1345
assert(swap >= res);
1346
occupied ^= least_significant_square_bb(bb);
1347
1348
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
1349
| (attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN));
1350
}
1351
1352
else // KING
1353
// If we "capture" with the king but the opponent still has attackers,
1354
// reverse the result.
1355
return (attackers & ~pieces(stm)) ? res ^ 1 : res;
1356
}
1357
1358
return bool(res);
1359
}
1360
1361
// Tests whether the position is drawn by 50-move rule
1362
// or by repetition. It does not detect stalemates.
1363
bool Position::is_draw(int ply) const {
1364
1365
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
1366
return true;
1367
1368
return is_repetition(ply);
1369
}
1370
1371
// Return a draw score if a position repeats once earlier but strictly
1372
// after the root, or repeats twice before or at the root.
1373
bool Position::is_repetition(int ply) const { return st->repetition && st->repetition < ply; }
1374
1375
// Tests whether there has been at least one repetition
1376
// of positions since the last capture or pawn move.
1377
bool Position::has_repeated() const {
1378
1379
StateInfo* stc = st;
1380
int end = std::min(st->rule50, st->pliesFromNull);
1381
while (end-- >= 4)
1382
{
1383
if (stc->repetition)
1384
return true;
1385
1386
stc = stc->previous;
1387
}
1388
return false;
1389
}
1390
1391
1392
// Tests if the position has a move which draws by repetition.
1393
// This function accurately matches the outcome of is_draw() over all legal moves.
1394
bool Position::upcoming_repetition(int ply) const {
1395
1396
int j;
1397
1398
int end = std::min(st->rule50, st->pliesFromNull);
1399
1400
if (end < 3)
1401
return false;
1402
1403
Key originalKey = st->key;
1404
StateInfo* stp = st->previous;
1405
Key other = originalKey ^ stp->key ^ Zobrist::side;
1406
1407
for (int i = 3; i <= end; i += 2)
1408
{
1409
stp = stp->previous;
1410
other ^= stp->key ^ stp->previous->key ^ Zobrist::side;
1411
stp = stp->previous;
1412
1413
if (other != 0)
1414
continue;
1415
1416
Key moveKey = originalKey ^ stp->key;
1417
if ((j = H1(moveKey), cuckoo[j] == moveKey) || (j = H2(moveKey), cuckoo[j] == moveKey))
1418
{
1419
Move move = cuckooMove[j];
1420
Square s1 = move.from_sq();
1421
Square s2 = move.to_sq();
1422
1423
if (!((between_bb(s1, s2) ^ s2) & pieces()))
1424
{
1425
if (ply > i)
1426
return true;
1427
1428
// For nodes before or at the root, check that the move is a
1429
// repetition rather than a move to the current position.
1430
if (stp->repetition)
1431
return true;
1432
}
1433
}
1434
}
1435
return false;
1436
}
1437
1438
1439
// Flips position with the white and black sides reversed. This
1440
// is only useful for debugging e.g. for finding evaluation symmetry bugs.
1441
void Position::flip() {
1442
1443
string f, token;
1444
std::stringstream ss(fen());
1445
1446
for (Rank r = RANK_8;; --r) // Piece placement
1447
{
1448
std::getline(ss, token, r > RANK_1 ? '/' : ' ');
1449
f.insert(0, token + (f.empty() ? " " : "/"));
1450
1451
if (r == RANK_1)
1452
break;
1453
}
1454
1455
ss >> token; // Active color
1456
f += (token == "w" ? "B " : "W "); // Will be lowercased later
1457
1458
ss >> token; // Castling availability
1459
f += token + " ";
1460
1461
std::transform(f.begin(), f.end(), f.begin(),
1462
[](char c) { return char(islower(c) ? toupper(c) : tolower(c)); });
1463
1464
ss >> token; // En passant square
1465
f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3"));
1466
1467
std::getline(ss, token); // Half and full moves
1468
f += token;
1469
1470
set(f, is_chess960(), st);
1471
1472
assert(pos_is_ok());
1473
}
1474
1475
1476
bool Position::material_key_is_ok() const { return compute_material_key() == st->materialKey; }
1477
1478
1479
// Performs some consistency checks for the position object
1480
// and raise an assert if something wrong is detected.
1481
// This is meant to be helpful when debugging.
1482
bool Position::pos_is_ok() const {
1483
1484
constexpr bool Fast = true; // Quick (default) or full check?
1485
1486
if ((sideToMove != WHITE && sideToMove != BLACK) || piece_on(square<KING>(WHITE)) != W_KING
1487
|| piece_on(square<KING>(BLACK)) != B_KING
1488
|| (ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6))
1489
assert(0 && "pos_is_ok: Default");
1490
1491
if (Fast)
1492
return true;
1493
1494
if (pieceCount[W_KING] != 1 || pieceCount[B_KING] != 1
1495
|| attackers_to_exist(square<KING>(~sideToMove), pieces(), sideToMove))
1496
assert(0 && "pos_is_ok: Kings");
1497
1498
if ((pieces(PAWN) & (Rank1BB | Rank8BB)) || pieceCount[W_PAWN] > 8 || pieceCount[B_PAWN] > 8)
1499
assert(0 && "pos_is_ok: Pawns");
1500
1501
if ((pieces(WHITE) & pieces(BLACK)) || (pieces(WHITE) | pieces(BLACK)) != pieces()
1502
|| popcount(pieces(WHITE)) > 16 || popcount(pieces(BLACK)) > 16)
1503
assert(0 && "pos_is_ok: Bitboards");
1504
1505
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
1506
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
1507
if (p1 != p2 && (pieces(p1) & pieces(p2)))
1508
assert(0 && "pos_is_ok: Bitboards");
1509
1510
1511
for (Piece pc : Pieces)
1512
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
1513
|| pieceCount[pc] != std::count(board.begin(), board.end(), pc))
1514
assert(0 && "pos_is_ok: Pieces");
1515
1516
for (Color c : {WHITE, BLACK})
1517
for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE})
1518
{
1519
if (!can_castle(cr))
1520
continue;
1521
1522
if (piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK)
1523
|| castlingRightsMask[castlingRookSquare[cr]] != cr
1524
|| (castlingRightsMask[square<KING>(c)] & cr) != cr)
1525
assert(0 && "pos_is_ok: Castling");
1526
}
1527
1528
assert(material_key_is_ok() && "pos_is_ok: materialKey");
1529
1530
return true;
1531
}
1532
1533
} // namespace Stockfish
1534
1535