Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/position.cpp
627 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, const TranspositionTable& tt) {
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
prefetch(tt.first_entry(key()));
1232
1233
st->pliesFromNull = 0;
1234
1235
sideToMove = ~sideToMove;
1236
1237
set_check_info();
1238
1239
st->repetition = 0;
1240
1241
assert(pos_is_ok());
1242
}
1243
1244
1245
// Must be used to undo a "null move"
1246
void Position::undo_null_move() {
1247
1248
assert(!checkers());
1249
1250
st = st->previous;
1251
sideToMove = ~sideToMove;
1252
}
1253
1254
1255
// Tests if the SEE (Static Exchange Evaluation)
1256
// value of move is greater or equal to the given threshold. We'll use an
1257
// algorithm similar to alpha-beta pruning with a null window.
1258
bool Position::see_ge(Move m, int threshold) const {
1259
1260
assert(m.is_ok());
1261
1262
// Only deal with normal moves, assume others pass a simple SEE
1263
if (m.type_of() != NORMAL)
1264
return VALUE_ZERO >= threshold;
1265
1266
Square from = m.from_sq(), to = m.to_sq();
1267
1268
assert(piece_on(from) != NO_PIECE);
1269
1270
int swap = PieceValue[piece_on(to)] - threshold;
1271
if (swap < 0)
1272
return false;
1273
1274
swap = PieceValue[piece_on(from)] - swap;
1275
if (swap <= 0)
1276
return true;
1277
1278
assert(color_of(piece_on(from)) == sideToMove);
1279
Bitboard occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic
1280
Color stm = sideToMove;
1281
Bitboard attackers = attackers_to(to, occupied);
1282
Bitboard stmAttackers, bb;
1283
int res = 1;
1284
1285
while (true)
1286
{
1287
stm = ~stm;
1288
attackers &= occupied;
1289
1290
// If stm has no more attackers then give up: stm loses
1291
if (!(stmAttackers = attackers & pieces(stm)))
1292
break;
1293
1294
// Don't allow pinned pieces to attack as long as there are
1295
// pinners on their original square.
1296
if (pinners(~stm) & occupied)
1297
{
1298
stmAttackers &= ~blockers_for_king(stm);
1299
1300
if (!stmAttackers)
1301
break;
1302
}
1303
1304
res ^= 1;
1305
1306
// Locate and remove the next least valuable attacker, and add to
1307
// the bitboard 'attackers' any X-ray attackers behind it.
1308
if ((bb = stmAttackers & pieces(PAWN)))
1309
{
1310
if ((swap = PawnValue - swap) < res)
1311
break;
1312
occupied ^= least_significant_square_bb(bb);
1313
1314
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
1315
}
1316
1317
else if ((bb = stmAttackers & pieces(KNIGHT)))
1318
{
1319
if ((swap = KnightValue - swap) < res)
1320
break;
1321
occupied ^= least_significant_square_bb(bb);
1322
}
1323
1324
else if ((bb = stmAttackers & pieces(BISHOP)))
1325
{
1326
if ((swap = BishopValue - swap) < res)
1327
break;
1328
occupied ^= least_significant_square_bb(bb);
1329
1330
attackers |= attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN);
1331
}
1332
1333
else if ((bb = stmAttackers & pieces(ROOK)))
1334
{
1335
if ((swap = RookValue - swap) < res)
1336
break;
1337
occupied ^= least_significant_square_bb(bb);
1338
1339
attackers |= attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN);
1340
}
1341
1342
else if ((bb = stmAttackers & pieces(QUEEN)))
1343
{
1344
swap = QueenValue - swap;
1345
// implies that the previous recapture was done by a higher rated piece than a Queen (King is excluded)
1346
assert(swap >= res);
1347
occupied ^= least_significant_square_bb(bb);
1348
1349
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
1350
| (attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN));
1351
}
1352
1353
else // KING
1354
// If we "capture" with the king but the opponent still has attackers,
1355
// reverse the result.
1356
return (attackers & ~pieces(stm)) ? res ^ 1 : res;
1357
}
1358
1359
return bool(res);
1360
}
1361
1362
// Tests whether the position is drawn by 50-move rule
1363
// or by repetition. It does not detect stalemates.
1364
bool Position::is_draw(int ply) const {
1365
1366
if (st->rule50 > 99 && (!checkers() || MoveList<LEGAL>(*this).size()))
1367
return true;
1368
1369
return is_repetition(ply);
1370
}
1371
1372
// Return a draw score if a position repeats once earlier but strictly
1373
// after the root, or repeats twice before or at the root.
1374
bool Position::is_repetition(int ply) const { return st->repetition && st->repetition < ply; }
1375
1376
// Tests whether there has been at least one repetition
1377
// of positions since the last capture or pawn move.
1378
bool Position::has_repeated() const {
1379
1380
StateInfo* stc = st;
1381
int end = std::min(st->rule50, st->pliesFromNull);
1382
while (end-- >= 4)
1383
{
1384
if (stc->repetition)
1385
return true;
1386
1387
stc = stc->previous;
1388
}
1389
return false;
1390
}
1391
1392
1393
// Tests if the position has a move which draws by repetition.
1394
// This function accurately matches the outcome of is_draw() over all legal moves.
1395
bool Position::upcoming_repetition(int ply) const {
1396
1397
int j;
1398
1399
int end = std::min(st->rule50, st->pliesFromNull);
1400
1401
if (end < 3)
1402
return false;
1403
1404
Key originalKey = st->key;
1405
StateInfo* stp = st->previous;
1406
Key other = originalKey ^ stp->key ^ Zobrist::side;
1407
1408
for (int i = 3; i <= end; i += 2)
1409
{
1410
stp = stp->previous;
1411
other ^= stp->key ^ stp->previous->key ^ Zobrist::side;
1412
stp = stp->previous;
1413
1414
if (other != 0)
1415
continue;
1416
1417
Key moveKey = originalKey ^ stp->key;
1418
if ((j = H1(moveKey), cuckoo[j] == moveKey) || (j = H2(moveKey), cuckoo[j] == moveKey))
1419
{
1420
Move move = cuckooMove[j];
1421
Square s1 = move.from_sq();
1422
Square s2 = move.to_sq();
1423
1424
if (!((between_bb(s1, s2) ^ s2) & pieces()))
1425
{
1426
if (ply > i)
1427
return true;
1428
1429
// For nodes before or at the root, check that the move is a
1430
// repetition rather than a move to the current position.
1431
if (stp->repetition)
1432
return true;
1433
}
1434
}
1435
}
1436
return false;
1437
}
1438
1439
1440
// Flips position with the white and black sides reversed. This
1441
// is only useful for debugging e.g. for finding evaluation symmetry bugs.
1442
void Position::flip() {
1443
1444
string f, token;
1445
std::stringstream ss(fen());
1446
1447
for (Rank r = RANK_8;; --r) // Piece placement
1448
{
1449
std::getline(ss, token, r > RANK_1 ? '/' : ' ');
1450
f.insert(0, token + (f.empty() ? " " : "/"));
1451
1452
if (r == RANK_1)
1453
break;
1454
}
1455
1456
ss >> token; // Active color
1457
f += (token == "w" ? "B " : "W "); // Will be lowercased later
1458
1459
ss >> token; // Castling availability
1460
f += token + " ";
1461
1462
std::transform(f.begin(), f.end(), f.begin(),
1463
[](char c) { return char(islower(c) ? toupper(c) : tolower(c)); });
1464
1465
ss >> token; // En passant square
1466
f += (token == "-" ? token : token.replace(1, 1, token[1] == '3' ? "6" : "3"));
1467
1468
std::getline(ss, token); // Half and full moves
1469
f += token;
1470
1471
set(f, is_chess960(), st);
1472
1473
assert(pos_is_ok());
1474
}
1475
1476
1477
bool Position::material_key_is_ok() const { return compute_material_key() == st->materialKey; }
1478
1479
1480
// Performs some consistency checks for the position object
1481
// and raise an assert if something wrong is detected.
1482
// This is meant to be helpful when debugging.
1483
bool Position::pos_is_ok() const {
1484
1485
constexpr bool Fast = true; // Quick (default) or full check?
1486
1487
if ((sideToMove != WHITE && sideToMove != BLACK) || piece_on(square<KING>(WHITE)) != W_KING
1488
|| piece_on(square<KING>(BLACK)) != B_KING
1489
|| (ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6))
1490
assert(0 && "pos_is_ok: Default");
1491
1492
if (Fast)
1493
return true;
1494
1495
if (pieceCount[W_KING] != 1 || pieceCount[B_KING] != 1
1496
|| attackers_to_exist(square<KING>(~sideToMove), pieces(), sideToMove))
1497
assert(0 && "pos_is_ok: Kings");
1498
1499
if ((pieces(PAWN) & (Rank1BB | Rank8BB)) || pieceCount[W_PAWN] > 8 || pieceCount[B_PAWN] > 8)
1500
assert(0 && "pos_is_ok: Pawns");
1501
1502
if ((pieces(WHITE) & pieces(BLACK)) || (pieces(WHITE) | pieces(BLACK)) != pieces()
1503
|| popcount(pieces(WHITE)) > 16 || popcount(pieces(BLACK)) > 16)
1504
assert(0 && "pos_is_ok: Bitboards");
1505
1506
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
1507
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
1508
if (p1 != p2 && (pieces(p1) & pieces(p2)))
1509
assert(0 && "pos_is_ok: Bitboards");
1510
1511
1512
for (Piece pc : Pieces)
1513
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
1514
|| pieceCount[pc] != std::count(board.begin(), board.end(), pc))
1515
assert(0 && "pos_is_ok: Pieces");
1516
1517
for (Color c : {WHITE, BLACK})
1518
for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE})
1519
{
1520
if (!can_castle(cr))
1521
continue;
1522
1523
if (piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK)
1524
|| castlingRightsMask[castlingRookSquare[cr]] != cr
1525
|| (castlingRightsMask[square<KING>(c)] & cr) != cr)
1526
assert(0 && "pos_is_ok: Castling");
1527
}
1528
1529
assert(material_key_is_ok() && "pos_is_ok: materialKey");
1530
1531
return true;
1532
}
1533
1534
} // namespace Stockfish
1535
1536