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