Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
official-stockfish
GitHub Repository: official-stockfish/Stockfish
Path: blob/master/src/position.h
632 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
#ifndef POSITION_H_INCLUDED
20
#define POSITION_H_INCLUDED
21
22
#include <array>
23
#include <cassert>
24
#include <deque>
25
#include <iosfwd>
26
#include <memory>
27
#include <new>
28
#include <string>
29
30
#include "bitboard.h"
31
#include "types.h"
32
33
namespace Stockfish {
34
35
class TranspositionTable;
36
struct SharedHistories;
37
38
// StateInfo struct stores information needed to restore a Position object to
39
// its previous state when we retract a move. Whenever a move is made on the
40
// board (by calling Position::do_move), a StateInfo object must be passed.
41
42
struct StateInfo {
43
44
// Copied when making a move
45
Key materialKey;
46
Key pawnKey;
47
Key minorPieceKey;
48
Key nonPawnKey[COLOR_NB];
49
Value nonPawnMaterial[COLOR_NB];
50
int castlingRights;
51
int rule50;
52
int pliesFromNull;
53
Square epSquare;
54
55
// Not copied when making a move (will be recomputed anyhow)
56
Key key;
57
Bitboard checkersBB;
58
StateInfo* previous;
59
Bitboard blockersForKing[COLOR_NB];
60
Bitboard pinners[COLOR_NB];
61
Bitboard checkSquares[PIECE_TYPE_NB];
62
Piece capturedPiece;
63
int repetition;
64
};
65
66
67
// A list to keep track of the position states along the setup moves (from the
68
// start position to the position just before the search starts). Needed by
69
// 'draw by repetition' detection. Use a std::deque because pointers to
70
// elements are not invalidated upon list resizing.
71
using StateListPtr = std::unique_ptr<std::deque<StateInfo>>;
72
73
// Position class stores information regarding the board representation as
74
// pieces, side to move, hash keys, castling info, etc. Important methods are
75
// do_move() and undo_move(), used by the search to update node info when
76
// traversing the search tree.
77
class Position {
78
public:
79
static void init();
80
81
Position() = default;
82
Position(const Position&) = delete;
83
Position& operator=(const Position&) = delete;
84
85
// FEN string input/output
86
Position& set(const std::string& fenStr, bool isChess960, StateInfo* si);
87
Position& set(const std::string& code, Color c, StateInfo* si);
88
std::string fen() const;
89
90
// Position representation
91
Bitboard pieces() const; // All pieces
92
template<typename... PieceTypes>
93
Bitboard pieces(PieceTypes... pts) const;
94
Bitboard pieces(Color c) const;
95
template<typename... PieceTypes>
96
Bitboard pieces(Color c, PieceTypes... pts) const;
97
Piece piece_on(Square s) const;
98
const std::array<Piece, SQUARE_NB>& piece_array() const;
99
Square ep_square() const;
100
bool empty(Square s) const;
101
template<PieceType Pt>
102
int count(Color c) const;
103
template<PieceType Pt>
104
int count() const;
105
template<PieceType Pt>
106
Square square(Color c) const;
107
108
// Castling
109
bool can_castle(CastlingRights cr) const;
110
bool castling_impeded(CastlingRights cr) const;
111
Square castling_rook_square(CastlingRights cr) const;
112
113
// Checking
114
Bitboard checkers() const;
115
Bitboard blockers_for_king(Color c) const;
116
Bitboard check_squares(PieceType pt) const;
117
Bitboard pinners(Color c) const;
118
119
// Attacks to/from a given square
120
Bitboard attackers_to(Square s) const;
121
Bitboard attackers_to(Square s, Bitboard occupied) const;
122
bool attackers_to_exist(Square s, Bitboard occupied, Color c) const;
123
void update_slider_blockers(Color c) const;
124
template<PieceType Pt>
125
Bitboard attacks_by(Color c) const;
126
127
// Properties of moves
128
bool legal(Move m) const;
129
bool pseudo_legal(const Move m) const;
130
bool capture(Move m) const;
131
bool capture_stage(Move m) const;
132
bool gives_check(Move m) const;
133
Piece moved_piece(Move m) const;
134
Piece captured_piece() const;
135
136
// Doing and undoing moves
137
void do_move(Move m, StateInfo& newSt, const TranspositionTable* tt);
138
void do_move(Move m,
139
StateInfo& newSt,
140
bool givesCheck,
141
DirtyPiece& dp,
142
DirtyThreats& dts,
143
const TranspositionTable* tt,
144
const SharedHistories* worker);
145
void undo_move(Move m);
146
void do_null_move(StateInfo& newSt);
147
void undo_null_move();
148
149
// Static Exchange Evaluation
150
bool see_ge(Move m, int threshold = 0) const;
151
152
// Accessing hash keys
153
Key key() const;
154
Key material_key() const;
155
Key pawn_key() const;
156
Key minor_piece_key() const;
157
Key non_pawn_key(Color c) const;
158
159
// Other properties of the position
160
Color side_to_move() const;
161
int game_ply() const;
162
bool is_chess960() const;
163
bool is_draw(int ply) const;
164
bool is_repetition(int ply) const;
165
bool upcoming_repetition(int ply) const;
166
bool has_repeated() const;
167
int rule50_count() const;
168
Value non_pawn_material(Color c) const;
169
Value non_pawn_material() const;
170
171
// Position consistency check, for debugging
172
bool pos_is_ok() const;
173
bool material_key_is_ok() const;
174
void flip();
175
176
StateInfo* state() const;
177
178
void put_piece(Piece pc, Square s, DirtyThreats* const dts = nullptr);
179
void remove_piece(Square s, DirtyThreats* const dts = nullptr);
180
void swap_piece(Square s, Piece pc, DirtyThreats* const dts = nullptr);
181
182
private:
183
// Initialization helpers (used while setting up a position)
184
void set_castling_right(Color c, Square rfrom);
185
Key compute_material_key() const;
186
void set_state() const;
187
void set_check_info() const;
188
189
// Other helpers
190
template<bool PutPiece, bool ComputeRay = true>
191
void update_piece_threats(Piece pc,
192
Square s,
193
DirtyThreats* const dts,
194
Bitboard noRaysContaining = -1ULL) const;
195
void move_piece(Square from, Square to, DirtyThreats* const dts = nullptr);
196
template<bool Do>
197
void do_castling(Color us,
198
Square from,
199
Square& to,
200
Square& rfrom,
201
Square& rto,
202
DirtyThreats* const dts = nullptr,
203
DirtyPiece* const dp = nullptr);
204
Key adjust_key50(Key k) const;
205
206
// Data members
207
std::array<Piece, SQUARE_NB> board;
208
std::array<Bitboard, PIECE_TYPE_NB> byTypeBB;
209
std::array<Bitboard, COLOR_NB> byColorBB;
210
211
int pieceCount[PIECE_NB];
212
int castlingRightsMask[SQUARE_NB];
213
Square castlingRookSquare[CASTLING_RIGHT_NB];
214
Bitboard castlingPath[CASTLING_RIGHT_NB];
215
StateInfo* st;
216
int gamePly;
217
Color sideToMove;
218
bool chess960;
219
DirtyPiece scratch_dp;
220
DirtyThreats scratch_dts;
221
};
222
223
std::ostream& operator<<(std::ostream& os, const Position& pos);
224
225
inline Color Position::side_to_move() const { return sideToMove; }
226
227
inline Piece Position::piece_on(Square s) const {
228
assert(is_ok(s));
229
return board[s];
230
}
231
232
inline const std::array<Piece, SQUARE_NB>& Position::piece_array() const { return board; }
233
234
inline bool Position::empty(Square s) const { return piece_on(s) == NO_PIECE; }
235
236
inline Piece Position::moved_piece(Move m) const { return piece_on(m.from_sq()); }
237
238
inline Bitboard Position::pieces() const { return byTypeBB[ALL_PIECES]; }
239
240
template<typename... PieceTypes>
241
inline Bitboard Position::pieces(PieceTypes... pts) const {
242
return (byTypeBB[pts] | ...);
243
}
244
245
inline Bitboard Position::pieces(Color c) const { return byColorBB[c]; }
246
247
template<typename... PieceTypes>
248
inline Bitboard Position::pieces(Color c, PieceTypes... pts) const {
249
return pieces(c) & pieces(pts...);
250
}
251
252
template<PieceType Pt>
253
inline int Position::count(Color c) const {
254
return pieceCount[make_piece(c, Pt)];
255
}
256
257
template<PieceType Pt>
258
inline int Position::count() const {
259
return count<Pt>(WHITE) + count<Pt>(BLACK);
260
}
261
262
template<PieceType Pt>
263
inline Square Position::square(Color c) const {
264
assert(count<Pt>(c) == 1);
265
return lsb(pieces(c, Pt));
266
}
267
268
inline Square Position::ep_square() const { return st->epSquare; }
269
270
inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; }
271
272
inline bool Position::castling_impeded(CastlingRights cr) const {
273
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
274
return pieces() & castlingPath[cr];
275
}
276
277
inline Square Position::castling_rook_square(CastlingRights cr) const {
278
assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO);
279
return castlingRookSquare[cr];
280
}
281
282
inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, pieces()); }
283
284
template<PieceType Pt>
285
inline Bitboard Position::attacks_by(Color c) const {
286
287
if constexpr (Pt == PAWN)
288
return c == WHITE ? pawn_attacks_bb<WHITE>(pieces(WHITE, PAWN))
289
: pawn_attacks_bb<BLACK>(pieces(BLACK, PAWN));
290
else
291
{
292
Bitboard threats = 0;
293
Bitboard attackers = pieces(c, Pt);
294
while (attackers)
295
threats |= attacks_bb<Pt>(pop_lsb(attackers), pieces());
296
return threats;
297
}
298
}
299
300
inline Bitboard Position::checkers() const { return st->checkersBB; }
301
302
inline Bitboard Position::blockers_for_king(Color c) const { return st->blockersForKing[c]; }
303
304
inline Bitboard Position::pinners(Color c) const { return st->pinners[c]; }
305
306
inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; }
307
308
inline Key Position::key() const { return adjust_key50(st->key); }
309
310
inline Key Position::adjust_key50(Key k) const {
311
return st->rule50 < 14 ? k : k ^ make_key((st->rule50 - 14) / 8);
312
}
313
314
inline Key Position::pawn_key() const { return st->pawnKey; }
315
316
inline Key Position::material_key() const { return st->materialKey; }
317
318
inline Key Position::minor_piece_key() const { return st->minorPieceKey; }
319
320
inline Key Position::non_pawn_key(Color c) const { return st->nonPawnKey[c]; }
321
322
inline Value Position::non_pawn_material(Color c) const { return st->nonPawnMaterial[c]; }
323
324
inline Value Position::non_pawn_material() const {
325
return non_pawn_material(WHITE) + non_pawn_material(BLACK);
326
}
327
328
inline int Position::game_ply() const { return gamePly; }
329
330
inline int Position::rule50_count() const { return st->rule50; }
331
332
inline bool Position::is_chess960() const { return chess960; }
333
334
inline bool Position::capture(Move m) const {
335
assert(m.is_ok());
336
return (!empty(m.to_sq()) && m.type_of() != CASTLING) || m.type_of() == EN_PASSANT;
337
}
338
339
// Returns true if a move is generated from the capture stage, having also
340
// queen promotions covered, i.e. consistency with the capture stage move
341
// generation is needed to avoid the generation of duplicate moves.
342
inline bool Position::capture_stage(Move m) const {
343
assert(m.is_ok());
344
return capture(m) || m.promotion_type() == QUEEN;
345
}
346
347
inline Piece Position::captured_piece() const { return st->capturedPiece; }
348
349
inline void Position::put_piece(Piece pc, Square s, DirtyThreats* const dts) {
350
board[s] = pc;
351
byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s;
352
byColorBB[color_of(pc)] |= s;
353
pieceCount[pc]++;
354
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
355
356
if (dts)
357
update_piece_threats<true>(pc, s, dts);
358
}
359
360
inline void Position::remove_piece(Square s, DirtyThreats* const dts) {
361
Piece pc = board[s];
362
363
if (dts)
364
update_piece_threats<false>(pc, s, dts);
365
366
byTypeBB[ALL_PIECES] ^= s;
367
byTypeBB[type_of(pc)] ^= s;
368
byColorBB[color_of(pc)] ^= s;
369
board[s] = NO_PIECE;
370
pieceCount[pc]--;
371
pieceCount[make_piece(color_of(pc), ALL_PIECES)]--;
372
}
373
374
inline void Position::move_piece(Square from, Square to, DirtyThreats* const dts) {
375
Piece pc = board[from];
376
Bitboard fromTo = from | to;
377
378
if (dts)
379
update_piece_threats<false>(pc, from, dts, fromTo);
380
381
byTypeBB[ALL_PIECES] ^= fromTo;
382
byTypeBB[type_of(pc)] ^= fromTo;
383
byColorBB[color_of(pc)] ^= fromTo;
384
board[from] = NO_PIECE;
385
board[to] = pc;
386
387
if (dts)
388
update_piece_threats<true>(pc, to, dts, fromTo);
389
}
390
391
inline void Position::swap_piece(Square s, Piece pc, DirtyThreats* const dts) {
392
Piece old = board[s];
393
394
remove_piece(s);
395
396
if (dts)
397
update_piece_threats<false, false>(old, s, dts);
398
399
put_piece(pc, s);
400
401
if (dts)
402
update_piece_threats<true, false>(pc, s, dts);
403
}
404
405
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
406
new (&scratch_dts) DirtyThreats;
407
do_move(m, newSt, gives_check(m), scratch_dp, scratch_dts, tt, nullptr);
408
}
409
410
inline StateInfo* Position::state() const { return st; }
411
412
} // namespace Stockfish
413
414
#endif // #ifndef POSITION_H_INCLUDED
415
416