Line data Source code
1 : #pragma once
2 :
3 : #include "bitboard.hpp"
4 : #include "definition.hpp"
5 : #include "moveApply.hpp"
6 : #include "timers.hpp"
7 :
8 : #ifdef WITH_NNUE
9 : #include "nnue.hpp"
10 :
11 : [[nodiscard]] static constexpr size_t getBlock(const Square ksq) {
12 860236914 : return ksq;
13 : //return (ksq / 16) * 4 + ((ksq % 8) / 2);
14 : }
15 :
16 : [[nodiscard]] static constexpr size_t NNUEIndiceUs(const Square ksq, const Square s, const Piece p) {
17 504112337 : return nnue::FeatureIdx::major * getBlock(HFlip(ksq)) + HFlip(s) + nnue::FeatureIdx::usOffset(p);
18 : }
19 :
20 : [[nodiscard]] static constexpr size_t NNUEIndiceThem(const Square ksq, const Square s, const Piece p) {
21 528374021 : return nnue::FeatureIdx::major * getBlock(HFlip(ksq)) + HFlip(s) + nnue::FeatureIdx::themOffset(p);
22 : }
23 : #endif // WITH_NNUE
24 :
25 : struct Position; // forward decl
26 : struct RootPosition; // forward decl
27 :
28 : /*!
29 : * Main Position initialisation function
30 : * - silent will forbid logging (for info, not for error !)
31 : * - withMoveCount shall be set in order to read last part of the FEN string
32 : */
33 : bool readFEN(const std::string& fen, RootPosition& p, bool silent = false, bool withMoveCount = false); // forward decl
34 :
35 : /*!
36 : * Informations associated with an initially given Position (from readFEN)
37 : * There will not change inside the search tree
38 : */
39 89 : struct RootInformation {
40 : array1d<CastlingRights, NbSquare> castlePermHashTable = {CastlingRights::C_none}; // C_none is 0 so ok
41 : array2d<Square, 2, 2> rooksInit = {{{INVALIDSQUARE, INVALIDSQUARE}, {INVALIDSQUARE, INVALIDSQUARE}}};
42 : colored<Square> kingInit = {INVALIDSQUARE, INVALIDSQUARE};
43 : void initCaslingPermHashTable();
44 : };
45 :
46 : /*!
47 : * The main position structure
48 : * Storing
49 : * - board
50 : * - all bitboards
51 : * - material
52 : * - hash (full position and just K+P)
53 : * - some game status info
54 : *
55 : * Contains also some usefull accessor
56 : *
57 : * Minic is a copy/make engine, so that this structure is copied a lot !
58 : */
59 : struct alignas(32) Position {
60 : Position();
61 : virtual ~Position();
62 :
63 : array1d<Piece, NbSquare> _b {{P_none}}; // works because P_none is in fact 0
64 : array1d<BitBoard, 6> _allB {{emptyBitBoard}}; // works because emptyBitBoard is in fact 0
65 : array1d<BitBoard, 2> allPieces {{emptyBitBoard}}; // works because emptyBitBoard is in fact 0
66 :
67 : // t p n b r q k bl bd M n x x x x x (total is first so that pawn to king is same index as Piece type)
68 : using Material = colored<array1d<uint8_t, 16>>;
69 : Material mat = {{{{0}}}}; // such a nice syntax ...
70 :
71 : // shared by all "child" of a same "root" position
72 : // Assumed rule of 3 disrespect
73 : // the default copy CTOR and copy operator will copy that
74 : // but only a RootPosition will delete it
75 : // (this is way faster than a shared_ptr)
76 : mutable RootInformation* root = nullptr;
77 :
78 : #ifdef WITH_NNUE
79 : mutable NNUEEvaluator* associatedEvaluator = nullptr;
80 : #endif
81 :
82 : mutable Hash h = nullHash;
83 : mutable Hash ph = nullHash;
84 : MiniMove lastMove = INVALIDMINIMOVE;
85 : uint16_t moves = 0;
86 : uint16_t halfmoves = 0;
87 : colored<Square> king = {INVALIDSQUARE, INVALIDSQUARE};
88 : Square ep = INVALIDSQUARE;
89 : uint8_t fifty = 0;
90 : CastlingRights castling = C_none;
91 : Color c = Co_White;
92 :
93 : inline void clear(){
94 308 : _b = {{P_none}};
95 308 : _allB = {{emptyBitBoard}};
96 308 : allPieces = {{emptyBitBoard}};
97 308 : mat = {{{{0}}}};
98 308 : h = nullHash;
99 308 : ph = nullHash;
100 308 : lastMove = INVALIDMINIMOVE;
101 308 : moves = 0;
102 308 : halfmoves = 0;
103 308 : king = {INVALIDSQUARE, INVALIDSQUARE};
104 : //root = nullptr;
105 308 : ep = INVALIDSQUARE;
106 308 : fifty = 0;
107 308 : castling = C_none;
108 308 : c = Co_White;
109 : }
110 :
111 : //Position & operator=(const Position & p2);
112 : //Position(const Position& p);
113 :
114 : #ifdef DEBUG_FIFTY_COLLISION
115 : [[nodiscard]] bool operator== (const Position &p)const{
116 : return _allB == p._allB && ep == p.ep && castling == p.castling && c == p.c;
117 : }
118 : [[nodiscard]] bool operator!= (const Position &p)const{
119 : return _allB != p._allB || ep != p.ep || castling != p.castling || c != p.c;
120 : }
121 : #endif
122 :
123 : [[nodiscard]] FORCE_FINLINE RootInformation& rootInfo() {
124 149093056 : assert(root);
125 : return *root;
126 : }
127 :
128 : [[nodiscard]] FORCE_FINLINE const RootInformation& rootInfo() const {
129 14453171 : assert(root);
130 : return *root;
131 : }
132 :
133 402863938 : [[nodiscard]] FORCE_FINLINE const Piece& board_const(const Square k) const { return _b[k]; }
134 179518446 : [[nodiscard]] FORCE_FINLINE Piece& board (const Square k) { return _b[k]; }
135 :
136 344496684 : [[nodiscard]] FORCE_FINLINE BitBoard occupancy() const { return allPieces[Co_White] | allPieces[Co_Black]; }
137 :
138 13649408 : [[nodiscard]] FORCE_FINLINE BitBoard allKing() const { return _allB[5]; }
139 17220899 : [[nodiscard]] FORCE_FINLINE BitBoard allQueen() const { return _allB[4]; }
140 16423936 : [[nodiscard]] FORCE_FINLINE BitBoard allRook() const { return _allB[3]; }
141 16423996 : [[nodiscard]] FORCE_FINLINE BitBoard allBishop() const { return _allB[2]; }
142 5790404 : [[nodiscard]] FORCE_FINLINE BitBoard allKnight() const { return _allB[1]; }
143 796968 : [[nodiscard]] FORCE_FINLINE BitBoard allPawn() const { return _allB[0]; }
144 :
145 43653193 : [[nodiscard]] FORCE_FINLINE BitBoard blackKing() const { return _allB[5] & allPieces[Co_Black]; }
146 48799078 : [[nodiscard]] FORCE_FINLINE BitBoard blackQueen() const { return _allB[4] & allPieces[Co_Black]; }
147 44471781 : [[nodiscard]] FORCE_FINLINE BitBoard blackRook() const { return _allB[3] & allPieces[Co_Black]; }
148 58083089 : [[nodiscard]] FORCE_FINLINE BitBoard blackBishop() const { return _allB[2] & allPieces[Co_Black]; }
149 43676217 : [[nodiscard]] FORCE_FINLINE BitBoard blackKnight() const { return _allB[1] & allPieces[Co_Black]; }
150 49792373 : [[nodiscard]] FORCE_FINLINE BitBoard blackPawn() const { return _allB[0] & allPieces[Co_Black]; }
151 :
152 166249740 : [[nodiscard]] FORCE_FINLINE BitBoard whitePawn() const { return _allB[0] & allPieces[Co_White]; }
153 157098204 : [[nodiscard]] FORCE_FINLINE BitBoard whiteKnight() const { return _allB[1] & allPieces[Co_White]; }
154 172408326 : [[nodiscard]] FORCE_FINLINE BitBoard whiteBishop() const { return _allB[2] & allPieces[Co_White]; }
155 162569770 : [[nodiscard]] FORCE_FINLINE BitBoard whiteRook() const { return _allB[3] & allPieces[Co_White]; }
156 161304110 : [[nodiscard]] FORCE_FINLINE BitBoard whiteQueen() const { return _allB[4] & allPieces[Co_White]; }
157 157036089 : [[nodiscard]] FORCE_FINLINE BitBoard whiteKing() const { return _allB[5] & allPieces[Co_White]; }
158 :
159 796968 : [[nodiscard]] FORCE_FINLINE BitBoard whiteLightBishop() const { return whiteBishop() & BB::whiteSquare; }
160 796968 : [[nodiscard]] FORCE_FINLINE BitBoard whiteDarkBishop() const { return whiteBishop() & BB::blackSquare; }
161 796968 : [[nodiscard]] FORCE_FINLINE BitBoard blackLightBishop() const { return blackBishop() & BB::whiteSquare; }
162 796968 : [[nodiscard]] FORCE_FINLINE BitBoard blackDarkBishop() const { return blackBishop() & BB::blackSquare; }
163 :
164 : template<Piece pp> [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Color cc) const {
165 : assert(pp > P_none);
166 : assert(pp < P_end);
167 74178426 : assert(cc == Co_White || cc == Co_Black);
168 86185112 : return _allB[pp - 1] & allPieces[cc];
169 : }
170 : [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Color cc, const Piece pp) const {
171 36372036 : assert(pp > P_none);
172 : assert(pp < P_end);
173 70209278 : assert(cc == Co_White || cc == Co_Black);
174 76043179 : return _allB[pp - 1] & allPieces[cc];
175 : }
176 : [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Piece pp) const {
177 0 : assert(pp != P_none);
178 0 : assert(pp < P_end);
179 0 : assert(pp >= P_bk);
180 0 : return _allB[Abs(pp) - 1] & allPieces[pp > 0 ? Co_White : Co_Black];
181 : }
182 : // next one is kinda "private"
183 : [[nodiscard]] FORCE_FINLINE BitBoard& _pieces(const Piece pp) {
184 359636 : assert(pp != P_none);
185 190428043 : assert(pp < P_end);
186 190428043 : assert(pp >= P_bk);
187 369701035 : return _allB[Abs(pp) - 1];
188 : }
189 :
190 : #ifdef WITH_NNUE
191 : void associateEvaluator(NNUEEvaluator& evaluator, bool dirty = true) {
192 5403534 : associatedEvaluator = &evaluator;
193 5403534 : evaluator.dirty = dirty;
194 : }
195 :
196 : void dissociateEvaluator() {
197 0 : associatedEvaluator = nullptr;
198 : }
199 :
200 : [[nodiscard]] NNUEEvaluator& evaluator() {
201 175305545 : assert(associatedEvaluator);
202 : return *associatedEvaluator;
203 : }
204 : [[nodiscard]] const NNUEEvaluator& evaluator() const {
205 7530209 : assert(associatedEvaluator);
206 : return *associatedEvaluator;
207 : }
208 : [[nodiscard]] bool hasEvaluator() const {
209 308 : return associatedEvaluator != nullptr;
210 : }
211 :
212 : // Vastly taken from Seer implementation.
213 : // see https://github.com/connormcmonigle/seer-nnue
214 :
215 8634774 : template<Color c> void resetNNUEIndices_(NNUEEvaluator& nnueEvaluator) const {
216 : //us
217 110278718 : BB::applyOn(pieces_const<P_wp>(c), [&](const Square & k) {
218 50821972 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wp));
219 : });
220 26723550 : BB::applyOn(pieces_const<P_wn>(c), [&](const Square & k) {
221 9044388 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wn));
222 : });
223 26703814 : BB::applyOn(pieces_const<P_wb>(c), [&](const Square & k) {
224 9034520 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wb));
225 : });
226 36012810 : BB::applyOn(pieces_const<P_wr>(c), [&](const Square & k) {
227 13689018 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wr));
228 : });
229 18840972 : BB::applyOn(pieces_const<P_wq>(c), [&](const Square & k) {
230 5103099 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wq));
231 : });
232 25904322 : BB::applyOn(pieces_const<P_wk>(c), [&](const Square & k) {
233 8634774 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wk));
234 : });
235 : //them
236 109332378 : BB::applyOn(pieces_const<P_wp>(~c), [&](const Square & k) {
237 50348802 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wp));
238 : });
239 26884060 : BB::applyOn(pieces_const<P_wn>(~c), [&](const Square & k) {
240 9124643 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wn));
241 : });
242 26913852 : BB::applyOn(pieces_const<P_wb>(~c), [&](const Square & k) {
243 9139539 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wb));
244 : });
245 36303432 : BB::applyOn(pieces_const<P_wr>(~c), [&](const Square & k) {
246 13834329 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wr));
247 : });
248 18828310 : BB::applyOn(pieces_const<P_wq>(~c), [&](const Square & k) {
249 5096768 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wq));
250 : });
251 25904322 : BB::applyOn(pieces_const<P_wk>(~c), [&](const Square & k) {
252 8634774 : nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wk));
253 : });
254 8634774 : }
255 :
256 1218 : void resetNNUEEvaluator(NNUEEvaluator& nnueEvaluator) const {
257 : START_TIMER
258 : nnueEvaluator.clear();
259 1218 : resetNNUEIndices_<Co_White>(nnueEvaluator);
260 1218 : resetNNUEIndices_<Co_Black>(nnueEvaluator);
261 1218 : nnueEvaluator.dirty = false;
262 : STOP_AND_SUM_TIMER(ResetNNUE)
263 1218 : }
264 :
265 8632338 : void resetNNUEEvaluator(NNUEEvaluator& nnueEvaluator, Color color) const {
266 : START_TIMER
267 : nnueEvaluator.clear(color);
268 8632338 : if (color == Co_White)
269 1735711 : resetNNUEIndices_<Co_White>(nnueEvaluator);
270 : else
271 6896627 : resetNNUEIndices_<Co_Black>(nnueEvaluator);
272 8632338 : nnueEvaluator.dirty = false;
273 : STOP_AND_SUM_TIMER(ResetNNUE)
274 8632338 : }
275 :
276 : #endif
277 : };
278 :
279 : /*!
280 : * RootPosition only specific responsability is to
281 : * allocate and delete root pointer
282 : */
283 : struct RootPosition : public Position {
284 89 : RootPosition(){
285 : // a shared pointer here will be too slow
286 89 : root = new RootInformation;
287 89 : }
288 :
289 : RootPosition(const std::string& fen, bool withMoveCount = true);
290 :
291 0 : RootPosition(const RootPosition& p): Position(p) {
292 0 : assert(p.root);
293 : // we take a copy of the RootInformation of the copied RootPosition
294 0 : root = new RootInformation(*p.root);
295 0 : };
296 :
297 : // Root position cannot be copied
298 : // use this kind of thing instead
299 : // const bool b = readFEN(fen, rootPos, false, true);
300 : RootPosition & operator=(const RootPosition &) = delete;
301 :
302 89 : ~RootPosition() override {
303 89 : delete root;
304 89 : }
305 :
306 : };
307 :
308 : #ifdef WITH_NNUE
309 158320064 : template<Color c> void updateNNUEEvaluator(NNUEEvaluator& nnueEvaluator, const MoveInfo& moveInfo) {
310 : START_TIMER
311 158320064 : const Piece fromType = Abs(moveInfo.fromP);
312 158320064 : const Piece toType = Abs(moveInfo.toP);
313 158320064 : nnueEvaluator.template us<c>().erase(NNUEIndiceUs(moveInfo.king[c], moveInfo.from, fromType));
314 158320064 : nnueEvaluator.template them<c>().erase(NNUEIndiceThem(moveInfo.king[~c], moveInfo.from, fromType));
315 158320064 : if (isPromotion(moveInfo.type)) {
316 422359 : const Piece promPieceType = promShift(moveInfo.type);
317 422359 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(moveInfo.king[c], moveInfo.to, promPieceType));
318 422359 : nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, promPieceType));
319 : }
320 : else {
321 157897705 : nnueEvaluator.template us<c>().insert(NNUEIndiceUs(moveInfo.king[c], moveInfo.to, fromType));
322 157897705 : nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, fromType));
323 : }
324 158320064 : if (moveInfo.type == T_ep) {
325 58151 : const Square epSq = moveInfo.ep + (c == Co_White ? -8 : +8);
326 58151 : nnueEvaluator.template us<c>().erase(NNUEIndiceThem(moveInfo.king[c], epSq, P_wp));
327 58151 : nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], epSq, P_wp));
328 : }
329 158261913 : else if (toType != P_none) {
330 8593216 : nnueEvaluator.template us<c>().erase(NNUEIndiceThem(moveInfo.king[c], moveInfo.to, toType));
331 8593216 : nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], moveInfo.to, toType));
332 : }
333 158320064 : nnueEvaluator.dirty = false;
334 : STOP_AND_SUM_TIMER(UpdateNNUE)
335 158320064 : }
336 :
337 8352932 : template<Color c> void updateNNUEEvaluatorThemOnly(NNUEEvaluator& nnueEvaluator, const MoveInfo& moveInfo) {
338 : START_TIMER
339 8352932 : const Piece fromType = Abs(moveInfo.fromP);
340 8352932 : const Piece toType = Abs(moveInfo.toP);
341 8352932 : nnueEvaluator.template them<c>().erase(NNUEIndiceThem(moveInfo.king[~c], moveInfo.from, fromType));
342 8352932 : if (isPromotion(moveInfo.type)) {
343 0 : const Piece promPieceType = promShift(moveInfo.type);
344 0 : nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, promPieceType));
345 : }
346 : else {
347 8352932 : nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, fromType));
348 : }
349 8352932 : if (moveInfo.type == T_ep) {
350 0 : const Square epSq = moveInfo.ep + (c == Co_White ? -8 : +8);
351 0 : nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], epSq, P_wp));
352 : }
353 8352932 : else if (toType != P_none) {
354 441434 : nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], moveInfo.to, toType));
355 : }
356 8352932 : nnueEvaluator.dirty = false;
357 : STOP_AND_SUM_TIMER(UpdateNNUE)
358 8352932 : }
359 : #endif
|