Line data Source code
1 : #pragma once
2 :
3 : #include <algorithm>
4 : #include <array>
5 : #include <atomic>
6 : #include <bitset>
7 : #include <cassert>
8 : #include <cctype>
9 : #include <chrono>
10 : #include <climits>
11 : #include <cmath>
12 : #include <condition_variable>
13 : #include <cstdint>
14 : #include <cstdlib>
15 : #include <cstring>
16 : #include <fstream>
17 : #include <functional>
18 : #include <future>
19 : #include <iomanip>
20 : #include <iostream>
21 : #include <iterator>
22 : #include <list>
23 : #include <map>
24 : #include <mutex>
25 : #include <optional>
26 : #include <random>
27 : #include <regex>
28 : #include <set>
29 : #include <span>
30 : #include <sstream>
31 : #include <string>
32 : #include <string_view>
33 : #include <thread>
34 : #include <type_traits>
35 : #include <unordered_map>
36 : #include <utility>
37 : #include <vector>
38 : #ifdef _WIN32
39 : #include <intrin.h>
40 : #include <process.h>
41 : #include <stdlib.h>
42 : typedef uint64_t u_int64_t;
43 : #else
44 : #include <unistd.h>
45 : #endif
46 :
47 : #include "config.hpp"
48 :
49 : #ifdef WITH_FMTLIB
50 : #include <fmt/color.h>
51 : #endif
52 :
53 : #ifdef WITH_EVAL_TUNING
54 : #define CONST_EVAL_TUNING
55 : #undef WITH_EVALSCORE_AS_INT
56 : #else
57 : #define CONST_EVAL_TUNING const
58 : #endif
59 :
60 : #ifdef WITH_SEARCH_TUNING
61 : #define CONST_SEARCH_TUNING
62 : #define CONSTEXPR_SEARCH_TUNING
63 : #else
64 : #define CONST_SEARCH_TUNING const
65 : #define CONSTEXPR_SEARCH_TUNING constexpr
66 : #endif
67 :
68 : #ifdef WITH_PIECE_TUNING
69 : #define CONST_PIECE_TUNING
70 : #else
71 : #define CONST_PIECE_TUNING const
72 : #endif
73 :
74 : inline constexpr size_t NNUEALIGNMENT = 64; // AVX512 compatible ...
75 : inline constexpr auto NNUEALIGNMENT_STD = std::align_val_t{ NNUEALIGNMENT };
76 :
77 : #ifdef __clang__
78 : #define CONSTEXPR
79 : #else
80 : #define CONSTEXPR constexpr
81 : #endif
82 :
83 : #if _WIN32 || _WIN64
84 : #if _WIN64
85 : #define ENV64BIT
86 : #else
87 : #define ENV32BIT
88 : #endif
89 : #endif
90 :
91 : #if __GNUC__
92 : #if __x86_64__ || __ppc64__
93 : #define ENV64BIT
94 : #else
95 : #define ENV32BIT
96 : #endif
97 : #endif
98 :
99 : #ifdef _MSC_VER
100 : #pragma warning(disable:4996)
101 : #pragma warning(disable:4068)
102 : #endif
103 :
104 : #if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
105 : #define __PRETTY_FUNCTION__ __FUNCSIG__
106 : #endif
107 :
108 : #if defined(WITH_SMALL_MEMORY)
109 : constexpr size_t SIZE_MULTIPLIER = 1024ull; // Kb
110 : #else
111 : constexpr size_t SIZE_MULTIPLIER = 1024ull * 1024ull; // Mb
112 : #endif
113 :
114 : #if defined(_MSC_VER)
115 : #define FORCE_INLINE __inline
116 : #elif defined(__GNUC__)
117 : #if defined(__STRICT_ANSI__)
118 : #define FORCE_INLINE __inline__
119 : #else
120 : #define FORCE_INLINE inline
121 : #endif
122 : #else
123 : #define FORCE_INLINE
124 : #endif
125 :
126 : #ifdef _MSC_VER
127 : #define FORCE_FINLINE __forceinline
128 : #define RESTRICT __restrict
129 : #elif defined(__GNUC__)
130 : #define FORCE_FINLINE FORCE_INLINE __attribute__((always_inline))
131 : #define RESTRICT __restrict__
132 : #else
133 : #define FORCE_FINLINE
134 : #endif
135 :
136 1936513225 : template<typename T> [[nodiscard]] constexpr inline T Abs(const T& s) {
137 : static_assert(T(-1) < T(0));
138 : if constexpr (std::is_enum_v<T>){
139 1075626717 : assert(s != std::numeric_limits<std::underlying_type_t<T>>::min());
140 : }
141 : else{
142 860886508 : assert(s != std::numeric_limits<T>::min());
143 : }
144 2137275923 : const T ret = s >= T(0) ? s : T(-s);
145 1936513225 : assert(ret == std::abs(s));
146 1936513225 : return ret;
147 : }
148 :
149 : #define ENABLE_INCR_OPERATORS_ON(T) \
150 : constexpr T& operator++(T& d) { return d = static_cast<T>(static_cast<std::underlying_type_t<T>>(d) + 1); } \
151 : constexpr T& operator--(T& d) { return d = static_cast<T>(static_cast<std::underlying_type_t<T>>(d) - 1); }
152 :
153 : using Clock = std::chrono::system_clock;
154 : using DepthType = int8_t;
155 : using Move = int32_t; // invalid if < 0
156 : using MiniMove = int16_t; // invalid if < 0
157 : using Square = int8_t; // invalid if < 0, MUST be signed because also used as negative delta sometimes (like in computeAttacks)
158 : using Hash = uint64_t; // invalid if == nullHash
159 : using MiniHash = uint32_t; // invalid if == 0
160 : using Counter = uint64_t;
161 : using BitBoard = uint64_t;
162 : using ScoreType = int16_t;
163 : using TimeType = int64_t;
164 : using GenerationType = uint8_t;
165 :
166 : enum File : uint8_t { File_a = 0, File_b, File_c, File_d, File_e, File_f, File_g, File_h };
167 0 : ENABLE_INCR_OPERATORS_ON(File)
168 :
169 : enum Rank : uint8_t { Rank_1 = 0, Rank_2, Rank_3, Rank_4, Rank_5, Rank_6, Rank_7, Rank_8 };
170 892524 : ENABLE_INCR_OPERATORS_ON(Rank)
171 :
172 : enum Sq : uint8_t { Sq_a1 = 0,Sq_b1,Sq_c1,Sq_d1,Sq_e1,Sq_f1,Sq_g1,Sq_h1,
173 : Sq_a2,Sq_b2,Sq_c2,Sq_d2,Sq_e2,Sq_f2,Sq_g2,Sq_h2,
174 : Sq_a3,Sq_b3,Sq_c3,Sq_d3,Sq_e3,Sq_f3,Sq_g3,Sq_h3,
175 : Sq_a4,Sq_b4,Sq_c4,Sq_d4,Sq_e4,Sq_f4,Sq_g4,Sq_h4,
176 : Sq_a5,Sq_b5,Sq_c5,Sq_d5,Sq_e5,Sq_f5,Sq_g5,Sq_h5,
177 : Sq_a6,Sq_b6,Sq_c6,Sq_d6,Sq_e6,Sq_f6,Sq_g6,Sq_h6,
178 : Sq_a7,Sq_b7,Sq_c7,Sq_d7,Sq_e7,Sq_f7,Sq_g7,Sq_h7,
179 : Sq_a8,Sq_b8,Sq_c8,Sq_d8,Sq_e8,Sq_f8,Sq_g8,Sq_h8};
180 :
181 : template<typename T, int N>
182 : using array1d = std::array<T,N>;
183 :
184 : template<typename T, int N, int M>
185 : using array2d = array1d<array1d<T,M>,N>;
186 :
187 : template<typename T, int N, int M, int L>
188 : using array3d = array1d<array1d<array1d<T,L>,M>,N>;
189 :
190 : template<typename T>
191 : using colored = array1d<T,2>;
192 :
193 : inline constexpr array1d<Rank,2> PromRank = {Rank_8, Rank_1};
194 : inline constexpr array1d<Rank,2> EPRank = {Rank_6, Rank_3};
195 :
196 : inline constexpr Hash nullHash = 0ull; //std::numeric_limits<MiniHash>::max(); // use MiniHash to allow same "null" value for Hash(64) and MiniHash(32)
197 : inline constexpr BitBoard emptyBitBoard = 0ull;
198 : inline constexpr auto INFINITETIME = static_cast<TimeType>(60ull * 60ull * 1000ull * 24ull * 30ull); // 1 month ...
199 : inline constexpr auto STOPSCORE = static_cast<ScoreType>(-20000);
200 : inline constexpr auto INFSCORE = static_cast<ScoreType>(15000);
201 : inline constexpr auto MATE = static_cast<ScoreType>(10000);
202 : inline constexpr auto WIN = static_cast<ScoreType>(3000);
203 : inline constexpr auto INVALIDMOVE = static_cast<int32_t>(0xFFFF0002);
204 : inline constexpr auto INVALIDMINIMOVE = static_cast<int16_t>(0x0002);
205 : inline constexpr auto NULLMOVE = static_cast<int16_t>(0x1112);
206 :
207 : inline constexpr Square INVALIDSQUARE = -1;
208 : inline constexpr uint16_t MAX_PLY = 2048; // same type as Position::halfmoves
209 : inline constexpr int MAX_MOVE = 256; // 256 is enough I guess/hope ...
210 : inline constexpr auto MAX_DEPTH = static_cast<DepthType>(127); // if DepthType is a char, !!!do not go above 127!!!
211 : inline constexpr auto HISTORY_POWER = 10;
212 : inline constexpr ScoreType HISTORY_MAX = (1 << HISTORY_POWER);
213 : inline constexpr size_t MAX_THREADS = 1024; // same type as Searcher::id()
214 :
215 : constexpr ScoreType HISTORY_DIV(const int x) {
216 3598807 : const int ret = x >> HISTORY_POWER;
217 2484635 : assert (Abs(ret) < std::numeric_limits<ScoreType>::max());
218 : return ret;
219 : }
220 1147496 : constexpr ScoreType SQR(const ScoreType x) { return x * x;}
221 1147496 : constexpr ScoreType HSCORE(const DepthType depth) {
222 1147496 : const int ret = SQR(std::min(static_cast<int>(depth), 32)) * 4;
223 1147496 : assert (ret < std::numeric_limits<ScoreType>::max());
224 1147496 : return static_cast<ScoreType>(ret);}
225 :
226 : enum Color : uint8_t { Co_White = 0, Co_Black = 1, Co_None = 2, Co_End = Co_None };
227 2788290872 : [[nodiscard]] constexpr Color operator~(Color c) { return static_cast<Color>(c ^ Co_Black); } // switch Color
228 6328278 : ENABLE_INCR_OPERATORS_ON(Color)
229 :
230 5873305 : constexpr auto SQFILE(const Square s) { return static_cast<File>(s & 7);}
231 17164827 : constexpr auto SQRANK(const Square s) { return static_cast<Rank>(s >> 3);}
232 22176 : constexpr auto ISOUTERFILE(const Square x) { return (SQFILE(x) == 0 || SQFILE(x) == 7);}
233 113000448 : constexpr auto ISNEIGHBOUR(const Square x, const Square y) { return (x >= 0 && x < 64 && y >= 0 && y < 64 && Abs(SQRANK(x) - SQRANK(y)) <= 1 && Abs(SQFILE(x) - SQFILE(y)) <= 1);}
234 5810116 : constexpr auto PROMOTION_RANK(const Square x) { return (SQRANK(x) == 0 || SQRANK(x) == 7);}
235 : constexpr auto PROMOTION_RANK_C(const Square x, const Square c){ return ((c == Co_Black && SQRANK(x) == 0) || (c == Co_White && SQRANK(x) == 7));}
236 4325376 : constexpr auto MakeSquare(const File f, const Rank r) { return static_cast<Square>((r << 3) + f);}
237 0 : constexpr auto VFlip(const Square s) { return static_cast<Square>(s ^ Sq_a8);}
238 860236920 : constexpr auto HFlip(const Square s) { return static_cast<Square>(s ^ Sq_h1);}
239 : constexpr auto MFlip(const Square s) { return static_cast<Square>(s ^ Sq_h8);}
240 :
241 : #define TO_STR2(x) #x
242 : #define TO_STR(x) TO_STR2(x)
243 : #define LINE_NAME(prefix, suffix) JOIN(JOIN(prefix, __LINE__), suffix)
244 : #define JOIN(symbol1, symbol2) _DO_JOIN(symbol1, symbol2)
245 : #define _DO_JOIN(symbol1, symbol2) symbol1##symbol2
246 :
247 : #define DISCARD [[maybe_unused]] const auto LINE_NAME(_tmp,_) =
248 :
249 : #ifdef _WIN32
250 : #define GETPID _getpid
251 : #else
252 : #define GETPID ::getpid
253 : #endif
254 :
255 : template<typename T>
256 : [[nodiscard]] FORCE_FINLINE
257 : T asLeastOne(const T &t){
258 7278 : return std::max(static_cast<std::remove_const_t<decltype(t)>>(1), t);
259 : }
260 :
261 : [[nodiscard]] FORCE_FINLINE
262 : TimeType getTimeDiff(const Clock::time_point & reference){
263 6441 : const auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - reference).count();
264 : return static_cast<TimeType>(asLeastOne(diff));
265 : }
266 :
267 : [[nodiscard]] FORCE_FINLINE
268 : TimeType getTimeDiff(const Clock::time_point & current, const Clock::time_point & reference){
269 307 : const auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(current - reference).count();
270 : return static_cast<TimeType>(asLeastOne(diff));
271 : }
272 :
273 : [[nodiscard]] FORCE_FINLINE double msec2sec(TimeType periodInMsec){
274 : using fpMilliseconds = std::chrono::duration<float, std::chrono::milliseconds::period>;
275 : using fpSeconds = std::chrono::duration<float, std::chrono::seconds::period>;
276 274 : return fpSeconds(fpMilliseconds(periodInMsec)).count();
277 : }
278 :
279 : template<typename OT, typename IT>
280 : [[nodiscard]] FORCE_FINLINE
281 : OT clampInt(IT t){
282 3 : return static_cast<OT>(std::min(std::numeric_limits<IT>::max(), std::max(std::numeric_limits<IT>::min(), t)));
283 : }
284 :
285 : template<typename OT, typename IT>
286 : [[nodiscard]] FORCE_FINLINE
287 : OT clampIntU(IT t){
288 15 : return static_cast<OT>(std::min(std::numeric_limits<IT>::max(), std::max(0, t)));
289 : }
290 :
291 : template<typename T>
292 : [[nodiscard]] FORCE_FINLINE
293 : DepthType clampDepth(const T & d){
294 15 : return static_cast<DepthType>(std::max(static_cast<T>(0), std::min(static_cast<T>(MAX_DEPTH),d)));
295 : }
296 :
297 : template<typename T>
298 : [[nodiscard]] constexpr ScoreType clampScore(T s) {
299 5848896 : return static_cast<ScoreType>(std::clamp(s, (T)(-MATE + 2 * MAX_DEPTH), (T)(MATE - 2 * MAX_DEPTH)));
300 : }
301 :
302 : enum GamePhase { MG = 0, EG = 1, GP_MAX = 2 };
303 28603116924 : ENABLE_INCR_OPERATORS_ON(GamePhase)
304 :
305 11955124 : template<typename T, int SIZE> struct OptList : public std::vector<T> {
306 11955124 : OptList(): std::vector<T>() { std::vector<T>::reserve(SIZE); }
307 : };
308 : using MoveList = OptList<Move, MAX_MOVE / 4>; ///@todo tune this ?
309 : using PVList = std::vector<Move>;
310 :
311 10573614 : [[nodiscard]] constexpr MiniHash Hash64to32(Hash h) { return static_cast<MiniHash>((h >> 32) & 0xFFFFFFFF); }
312 927449034 : [[nodiscard]] constexpr MiniMove Move2MiniMove(Move m) { return static_cast<MiniMove>(m & 0xFFFF); } // skip score
313 :
314 : // sameMove is not comparing score part of the Move, only the MiniMove part !
315 58075372 : [[nodiscard]] constexpr bool sameMove(const Move& a, const Move& b) { return Move2MiniMove(a) == Move2MiniMove(b); }
316 213087129 : [[nodiscard]] constexpr bool sameMove(const Move& a, const MiniMove& b) { return Move2MiniMove(a) == b; }
317 :
318 1457223021 : [[nodiscard]] constexpr bool isValidMove(const Move& m) { return !sameMove(m, NULLMOVE) && !sameMove(m, INVALIDMOVE); }
319 36487079 : [[nodiscard]] constexpr bool isValidMove(const MiniMove& m) { return m != INVALIDMINIMOVE && m != NULLMOVE; }
320 :
321 : inline constexpr std::string_view startPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
322 : inline constexpr std::string_view fine70 = "8/k7/3p4/p2P1p2/P2P1P2/8/8/K7 w - - 0 1";
323 : inline constexpr std::string_view shirov = "6r1/2rp1kpp/2qQp3/p3Pp1P/1pP2P2/1P2KP2/P5R1/6R1 w - - 0 1";
324 : inline constexpr std::string_view shirov2 = "8/2rp1krp/2qQp3/p3Pp1P/1pP2P2/1P2KP2/P7/6R1 w - - 0 2";
325 : inline constexpr std::string_view mate4 = "r1bnk2r/pppp1ppp/1b4q1/4P3/2B1N3/Q1Pp1N2/P4PPP/R3R1K1 w - - 1 1";
326 :
327 : enum Piece : signed char {
328 : P_bk = -6,
329 : P_bq = -5,
330 : P_br = -4,
331 : P_bb = -3,
332 : P_bn = -2,
333 : P_bp = -1,
334 : P_none = 0,
335 : P_wp = 1,
336 : P_wn = 2,
337 : P_wb = 3,
338 : P_wr = 4,
339 : P_wq = 5,
340 : P_wk = 6,
341 : P_end
342 : };
343 53015896 : ENABLE_INCR_OPERATORS_ON(Piece)
344 :
345 80230 : constexpr Piece operator~(Piece pp) { return static_cast<Piece>(-pp); } // switch piece Color
346 : constexpr int PieceShift = 6;
347 : constexpr int NbPiece = 2 * PieceShift + 1;
348 :
349 591022153 : [[nodiscard]] constexpr int PieceIdx(Piece p) { return p + PieceShift; } ///@todo use it everywhere !
350 :
351 : enum Mat : uint8_t { M_t = 0, M_p, M_n, M_b, M_r, M_q, M_k, M_bl, M_bd, M_M, M_m };
352 3343826772 : ENABLE_INCR_OPERATORS_ON(Mat)
353 :
354 : extern CONST_PIECE_TUNING array1d<ScoreType,NbPiece> Values;
355 : extern CONST_PIECE_TUNING array1d<ScoreType,NbPiece> ValuesEG;
356 : extern CONST_PIECE_TUNING array1d<ScoreType,NbPiece> ValuesGP;
357 : extern CONST_PIECE_TUNING array1d<ScoreType,NbPiece> ValuesSEE;
358 :
359 1667 : [[nodiscard]] FORCE_FINLINE ScoreType value(Piece pp) { return Values[pp + PieceShift]; }
360 3 : [[nodiscard]] FORCE_FINLINE ScoreType valueEG(Piece pp) { return ValuesEG[pp + PieceShift]; }
361 : [[nodiscard]] FORCE_FINLINE ScoreType valueGP(Piece pp) { return ValuesGP[pp + PieceShift]; }
362 10637631 : [[nodiscard]] FORCE_FINLINE ScoreType valueSEE(Piece pp) { return ValuesSEE[pp + PieceShift]; }
363 :
364 : #ifdef WITH_PIECE_TUNING
365 : FORCE_FINLINE void SymetrizeValue() {
366 : for (Piece pp = P_wp; pp <= P_wk; ++pp) {
367 : Values[-pp + PieceShift] = Values[pp + PieceShift];
368 : ValuesEG[-pp + PieceShift] = ValuesEG[pp + PieceShift];
369 : ValuesGP[-pp + PieceShift] = ValuesGP[pp + PieceShift];
370 : ValuesSEE[-pp + PieceShift] = ValuesSEE[pp + PieceShift];
371 : }
372 : }
373 : #endif
374 :
375 : const ScoreType dummyScore = 0;
376 :
377 : inline array1d<const ScoreType* const,7> absValues_ = {&dummyScore,
378 : &Values[P_wp + PieceShift],
379 : &Values[P_wn + PieceShift],
380 : &Values[P_wb + PieceShift],
381 : &Values[P_wr + PieceShift],
382 : &Values[P_wq + PieceShift],
383 : &Values[P_wk + PieceShift]};
384 :
385 : inline array1d<const ScoreType* const,7> absValuesEG_ = {&dummyScore,
386 : &ValuesEG[P_wp + PieceShift],
387 : &ValuesEG[P_wn + PieceShift],
388 : &ValuesEG[P_wb + PieceShift],
389 : &ValuesEG[P_wr + PieceShift],
390 : &ValuesEG[P_wq + PieceShift],
391 : &ValuesEG[P_wk + PieceShift]};
392 :
393 : inline array1d<const ScoreType* const,7> absValuesGP_ = {&dummyScore,
394 : &ValuesGP[P_wp + PieceShift],
395 : &ValuesGP[P_wn + PieceShift],
396 : &ValuesGP[P_wb + PieceShift],
397 : &ValuesGP[P_wr + PieceShift],
398 : &ValuesGP[P_wq + PieceShift],
399 : &ValuesGP[P_wk + PieceShift]};
400 :
401 : inline array1d<const ScoreType* const,7> absValuesSEE_ = {&dummyScore,
402 : &ValuesSEE[P_wp + PieceShift],
403 : &ValuesSEE[P_wn + PieceShift],
404 : &ValuesSEE[P_wb + PieceShift],
405 : &ValuesSEE[P_wr + PieceShift],
406 : &ValuesSEE[P_wq + PieceShift],
407 : &ValuesSEE[P_wk + PieceShift]};
408 :
409 105226167 : [[nodiscard]] FORCE_FINLINE ScoreType absValue(Piece pp) { return *absValues_[pp]; }
410 105226163 : [[nodiscard]] FORCE_FINLINE ScoreType absValueEG(Piece pp) { return *absValuesEG_[pp]; }
411 105562816 : [[nodiscard]] FORCE_FINLINE ScoreType absValueGP(Piece pp) { return *absValuesGP_[pp]; }
412 : [[nodiscard]] FORCE_FINLINE ScoreType absValueSEE(Piece pp){ return *absValuesSEE_[pp]; }
413 :
414 5309420 : template<typename T> [[nodiscard]] constexpr int sgn(T val) { return (T(0) < val) - (val < T(0)); }
415 :
416 : inline constexpr array1d<std::string_view,NbPiece> PieceNames = {"k", "q", "r", "b", "n", "p", " ", "P", "N", "B", "R", "Q", "K"};
417 : inline constexpr array1d<std::string_view,NbPiece> PieceNamesUTF = {"♔", "♕", "♖", "♗", "♘", "♙", " ", "♟︎", "♞", "♝", "♜", "♛", "♚" };
418 :
419 : inline constexpr Square NbSquare = 64;
420 :
421 : inline constexpr array1d<std::string_view,NbSquare> SquareNames = { "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
422 : "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
423 : "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
424 : "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
425 : "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
426 : "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
427 : "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
428 : "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8" };
429 :
430 : inline constexpr array1d<std::string_view,8> FileNames = {"a", "b", "c", "d", "e", "f", "g", "h"};
431 : inline constexpr array1d<std::string_view,8> RankNames = {"1", "2", "3", "4", "5", "6", "7", "8"};
432 :
433 : template<Color C> [[nodiscard]] constexpr ScoreType ColorSignHelper() { return C == Co_White ? +1 : -1; }
434 4736 : template<Color C> [[nodiscard]] constexpr Square PromotionSquare(const Square k) { return C == Co_White ? (SQFILE(k) + 56) : SQFILE(k); }
435 542115 : template<Color C> [[nodiscard]] constexpr Rank ColorRank(const Square k) { return Rank(C == Co_White ? SQRANK(k) : (7 - SQRANK(k))); }
436 :
437 : enum CastlingTypes : uint8_t { CT_OOO = 0, CT_OO = 1 };
438 : enum CastlingRights : uint8_t {
439 : C_none = 0,
440 : C_wks = 1,
441 : C_wqs = 2,
442 : C_w_all = 3,
443 : C_all_but_b = 3,
444 : C_bks = 4,
445 : C_all_but_bqs = 7,
446 : C_bqs = 8,
447 : C_all_but_bks = 11,
448 : C_b_all = 12,
449 : C_all_but_w = 12,
450 : C_all_but_wqs = 13,
451 : C_all_but_wks = 14,
452 : C_all = 15
453 : };
454 14456026 : constexpr CastlingRights operator&(const CastlingRights& a, const CastlingRights& b) { return CastlingRights(char(a) & char(b)); }
455 263 : constexpr CastlingRights operator|(const CastlingRights& a, const CastlingRights& b) { return CastlingRights(char(a) | char(b)); }
456 : constexpr CastlingRights operator~(const CastlingRights& a) { return CastlingRights(~char(a)); }
457 10059028 : constexpr void operator&=(CastlingRights& a, const CastlingRights& b) { a = a & b; }
458 377 : constexpr void operator|=(CastlingRights& a, const CastlingRights& b) { a = a | b; }
459 :
460 18 : [[nodiscard]] FORCE_FINLINE Square stringToSquare(const std::string& str) { return static_cast<Square>((str.at(1) - 49) * 8 + (str.at(0) - 97)); }
461 :
462 : enum MType : uint8_t {
463 : T_std = 0,
464 : T_capture = 1,
465 : T_reserved = 2,
466 : T_ep = 3, // binary 0 to 11
467 : T_promq = 4,
468 : T_promr = 5,
469 : T_promb = 6,
470 : T_promn = 7, // binary 100 to 111
471 : T_cappromq = 8,
472 : T_cappromr = 9,
473 : T_cappromb = 10,
474 : T_cappromn = 11, // binary 1000 to 1011
475 : T_wks = 12,
476 : T_wqs = 13,
477 : T_bks = 14,
478 : T_bqs = 15, // binary 1100 to 1111
479 : T_max = 16
480 : };
481 :
482 : // castling are encoded with to Square being initial rook position
483 : // this allows to change it to king destination square
484 : const array1d<Square,T_bqs+1> correctedKingDestSq = { INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
485 : INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
486 : INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
487 : Sq_g1, Sq_c1, Sq_g8, Sq_c8};
488 : // this allows to change it to rook destination square
489 : const array1d<Square,T_bqs+1> correctedRookDestSq = { INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
490 : INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
491 : INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE, INVALIDSQUARE,
492 : Sq_f1, Sq_d1, Sq_f8, Sq_d8};
493 :
494 : [[nodiscard]] constexpr bool isValidMoveType(const MType m) { return m <= T_bqs; }
495 1516250672 : [[nodiscard]] constexpr bool isValidSquare(const Square s) { return s >= 0 && s < NbSquare; }
496 327274169 : [[nodiscard]] constexpr bool isValidPiece(const Piece pp) { return pp >= P_bk && pp <= P_wk; }
497 308914269 : [[nodiscard]] constexpr bool isValidPieceNotNone(const Piece pp) { return isValidPiece(pp) && pp != P_none; }
498 : [[nodiscard]] constexpr bool isNotEmpty(const BitBoard bb) { return bb != emptyBitBoard; }
499 :
500 853449 : [[nodiscard]] constexpr Piece promShift(const MType mt) {
501 853449 : assert(mt >= T_promq);
502 853449 : assert(mt <= T_cappromn);
503 853449 : return static_cast<Piece>(P_wq - (mt % 4));
504 : } // awfull hack
505 :
506 : // previous best root 20000
507 : // ttmove 15000
508 : // ~~king evasion 10000~~
509 : // good cap +7000 +SEE (or MVA and cap history)
510 : // killers 1900-1700-1500
511 : // counter 1300
512 : // standard move use -1024 < history < 1024
513 : // leaving threat +512
514 : // MVV-LVA [0 400]
515 : // recapture +512
516 : inline constexpr array1d<ScoreType,16> MoveScoring = { 0, // standard
517 : 7000, // cap (bad cap will be *=-1)
518 : 0, // reserved
519 : 7000, // ep
520 : 3950, 3500, 3350, 3300, // prom
521 : 7950, 7500, 7350, 7300, // prom+cap
522 : 256, 256, 256, 256 // castling bonus
523 : };
524 :
525 : [[nodiscard]] FORCE_FINLINE bool isSkipMove(const Move& a, const std::vector<MiniMove>* skipMoves) {
526 13570389 : return skipMoves && std::ranges::find(*skipMoves, Move2MiniMove(a)) != skipMoves->end();
527 : }
528 :
529 : [[nodiscard]] constexpr ScoreType Move2Score(const Move m) {
530 0 : assert(isValidMove(m));
531 335850110 : return static_cast<ScoreType>((m >> 16) & 0xFFFF);
532 : }
533 250441789 : [[nodiscard]] constexpr Square Move2From(const Move m) {
534 0 : assert(isValidMove(m));
535 250441789 : return static_cast<Square>((m >> 10) & 0x3F);
536 : }
537 263601354 : [[nodiscard]] constexpr Square Move2To(const Move m) {
538 0 : assert(isValidMove(m));
539 263601354 : return static_cast<Square>((m >> 4) & 0x3F);
540 : }
541 : [[nodiscard]] constexpr MType Move2Type(const Move m) {
542 0 : assert(isValidMove(m));
543 419525936 : return static_cast<MType>(m & 0xF);
544 : }
545 13 : [[nodiscard]] constexpr MiniMove ToMove(const Square from, const Square to, const MType type) {
546 13 : assert(isValidSquare(from));
547 13 : assert(isValidSquare(to));
548 13 : return static_cast<MiniMove>((from << 10) | (to << 4) | type);
549 : }
550 222430664 : [[nodiscard]] constexpr Move ToMove(const Square from, const Square to, const MType type, const ScoreType score) {
551 222430664 : assert(isValidSquare(from));
552 222430664 : assert(isValidSquare(to));
553 222430664 : return static_cast<Move>((score << 16) | (from << 10) | (to << 4) | type);
554 : }
555 :
556 6233158 : [[nodiscard]] constexpr ScoreType matingScore (const DepthType in) { return static_cast<ScoreType>(MATE - in); }
557 7892220 : [[nodiscard]] constexpr ScoreType matedScore (const DepthType in) { return static_cast<ScoreType>(-MATE + in); }
558 :
559 : [[nodiscard]] constexpr bool isMatingScore(const ScoreType s) { return (s >= MATE - MAX_DEPTH); }
560 : [[nodiscard]] constexpr bool isMatedScore (const ScoreType s) { return (s <= matedScore(MAX_DEPTH)); }
561 14380040 : [[nodiscard]] constexpr bool isMateScore (const ScoreType s) { return (Abs(s) >= MATE - MAX_DEPTH); }
562 :
563 : [[nodiscard]] constexpr bool isPromotionStd(const MType mt) {
564 : assert(isValidMoveType(mt));
565 499313357 : return (mt >> 2 == 0x1);
566 : }
567 : [[nodiscard]] constexpr bool isPromotionStd(const Move m) { return isPromotionStd(Move2Type(m)); }
568 : [[nodiscard]] constexpr bool isPromotionCap(const MType mt) {
569 : assert(isValidMoveType(mt));
570 186973736 : return (mt >> 2 == 0x2);
571 : }
572 : [[nodiscard]] constexpr bool isPromotionCap(const Move m) { return isPromotionCap(Move2Type(m)); }
573 :
574 499313357 : [[nodiscard]] constexpr bool isPromotion(const MType mt) {
575 499313357 : assert(isValidMoveType(mt));
576 499313357 : return isPromotionStd(mt) || isPromotionCap(mt);
577 : }
578 4134170 : [[nodiscard]] constexpr bool isPromotion(const Move m) { return isPromotion(Move2Type(m)); }
579 :
580 : [[nodiscard]] constexpr bool isCastling(const MType mt) {
581 8492635 : assert(isValidMoveType(mt));
582 250370205 : return (mt >> 2) == 0x3;
583 : }
584 45760546 : [[nodiscard]] constexpr bool isCastling(const Move m) { return isCastling(Move2Type(m)); }
585 :
586 202562284 : [[nodiscard]] constexpr bool isCapture(const MType mt) {
587 202562284 : assert(isValidMoveType(mt));
588 202562284 : return mt == T_capture || mt == T_ep || isPromotionCap(mt);
589 : }
590 25141832 : [[nodiscard]] constexpr bool isCapture(const Move m) { return isCapture(Move2Type(m)); }
591 :
592 1349207 : [[nodiscard]] constexpr bool isCaptureNoEP(const MType mt) {
593 1349207 : assert(isValidMoveType(mt));
594 1349207 : return mt == T_capture || isPromotionCap(mt);
595 : }
596 1326896 : [[nodiscard]] constexpr bool isCaptureNoEP(const Move m) { return isCaptureNoEP(Move2Type(m)); }
597 :
598 :
599 175492987 : [[nodiscard]] constexpr bool isCaptureOrProm(const MType mt) {
600 175492987 : assert(isValidMoveType(mt));
601 175492987 : return mt == T_capture || mt == T_ep || isPromotion(mt);
602 : }
603 : [[nodiscard]] constexpr bool isCaptureOrProm(const Move m) { return isCaptureOrProm(Move2Type(m)); }
604 :
605 : [[nodiscard]] constexpr bool isEnPassant(const MType mt) {
606 : assert(isValidMoveType(mt));
607 4152185 : return mt == T_ep;
608 : }
609 8304370 : [[nodiscard]] constexpr bool isEnPassant(const Move m) { return isEnPassant(Move2Type(m)); }
610 :
611 2002004 : [[nodiscard]] constexpr ScoreType badCapScore(const Move m) { return Move2Score(m) + MoveScoring[T_capture]; }
612 :
613 5768601 : [[nodiscard]] constexpr Square chebyshevDistance(const Square sq1, const Square sq2) {
614 5768601 : return std::max(Abs(static_cast<Square>(SQRANK(sq2) - SQRANK(sq1))), Abs(static_cast<Square>(SQFILE(sq2) - SQFILE(sq1))));
615 : }
616 : [[nodiscard]] constexpr Square manatthanDistance(const Square sq1, const Square sq2) {
617 : return Abs(static_cast<Square>(SQRANK(sq2) - SQRANK(sq1))) + Abs(static_cast<Square>(SQFILE(sq2) - SQFILE(sq1)));
618 : }
619 : [[nodiscard]] constexpr Square minDistance(const Square sq1, const Square sq2) {
620 : return std::min(Abs(static_cast<Square>(SQRANK(sq2) - SQRANK(sq1))), Abs(static_cast<Square>(SQFILE(sq2) - SQFILE(sq1))));
621 : }
622 :
623 : [[nodiscard]] FORCE_FINLINE Square correctedMove2ToKingDest(const Move m) {
624 0 : assert(isValidMove(m));
625 : const MType mtype = Move2Type(m);
626 235389856 : return (!isCastling(mtype)) ? Move2To(m) : correctedKingDestSq[mtype];
627 : }
628 :
629 : [[nodiscard]] FORCE_FINLINE Square correctedMove2ToRookDest(const Move m) {
630 : assert(isValidMove(m));
631 : const MType mtype = Move2Type(m);
632 : return (!isCastling(mtype)) ? Move2To(m) : correctedRookDestSq[mtype];
633 : }
634 :
635 : namespace MoveDifficultyUtil {
636 : enum MoveDifficulty {
637 : MD_forced = 0,
638 : MD_easy,
639 : MD_std,
640 : MD_moobDefenceIID,
641 : MD_moobAttackIID
642 : };
643 :
644 : enum PositionEvolution{
645 : PE_none = 0,
646 : PE_std,
647 : PE_moobingAttack,
648 : PE_moobingDefence,
649 : PE_boomingAttack,
650 : PE_boomingDefence,
651 : };
652 :
653 : const DepthType emergencyMinDepth = 14;
654 : const ScoreType emergencyMargin = 64;
655 : const ScoreType emergencyAttackThreshold = 130;
656 : const ScoreType easyMoveMargin = 180;
657 : const int emergencyFactorIID = 3;
658 : const int emergencyFactorIIDGood = 3;
659 : const int emergencyFactorMoobHistory = 2;
660 : const int emergencyFactorBoomHistory = 1;
661 : const int maxStealDivisor = 5; // 1/maxStealDivisor of remaining time
662 :
663 : extern float variability;
664 5099 : [[nodiscard]] FORCE_FINLINE float variabilityFactor() { return 2.f / (1.f + std::exp(1.f - MoveDifficultyUtil::variability)); } // inside [0.5 .. 2]
665 :
666 : } // namespace MoveDifficultyUtil
667 :
668 : template<typename T, int seed> [[nodiscard]] FORCE_FINLINE T randomInt(T m, T M) {
669 : ///@todo this is slow because the static here implies a guard variable !!
670 20080 : static std::mt19937 mt(seed); // fixed seed for ZHash for instance !!!
671 20080 : static std::uniform_int_distribution<T> dist(m, M);
672 20080 : return dist(mt);
673 : }
674 :
675 : template<typename T> [[nodiscard]] FORCE_FINLINE T randomInt(T m, T M) {
676 : ///@todo this is slow because the static here implies a guard variable !!
677 0 : static std::random_device r;
678 0 : static std::seed_seq seed {r(), r(), r(), r(), r(), r(), r(), r()};
679 0 : static std::mt19937 mt(seed);
680 0 : static std::uniform_int_distribution<T> dist(m, M);
681 : return dist(mt);
682 : }
683 :
684 : template<class T> [[nodiscard]] constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
685 : assert(!(hi < lo));
686 : return (v < lo) ? lo : (hi < v) ? hi : v;
687 : }
688 :
689 22595351 : [[nodiscard]] constexpr Square relative_square(const Color c, const Square s) { return static_cast<Square>(s ^ (c * 56)); }
690 :
691 : template<Color C> [[nodiscard]] constexpr Square ColorSquarePstHelper(const Square k) { return relative_square(~C, k); }
692 :
693 : [[nodiscard]] constexpr uint64_t powerFloor(const uint64_t x) {
694 : uint64_t power = 1;
695 1081 : while (power <= x) power *= 2;
696 50 : return power / 2;
697 : }
698 :
699 : FORCE_FINLINE void* std_aligned_alloc(const size_t alignment, const size_t size) {
700 : #ifdef __ANDROID__
701 : return malloc(size);
702 : #elif defined(__EMSCRIPTEN__)
703 : return malloc(size);
704 : #elif defined(__APPLE__)
705 : return aligned_alloc(alignment, size);
706 : #elif defined(_WIN32)
707 : return _mm_malloc(size, alignment);
708 : #elif defined(ARDUINO) || defined(ESP32)
709 : return malloc(size);
710 : #else
711 24 : void* ret = std::aligned_alloc(alignment, size);
712 : #ifdef MADV_HUGEPAGE
713 : madvise(ret, size, MADV_HUGEPAGE);
714 : #endif
715 : return ret;
716 : #endif
717 : }
718 :
719 : FORCE_FINLINE void std_aligned_free(void* ptr) {
720 : #ifdef __ANDROID__
721 : return free(ptr);
722 : #elif defined(__EMSCRIPTEN__)
723 : return free(ptr);
724 : #elif defined(__APPLE__)
725 : free(ptr);
726 : #elif defined(_WIN32)
727 : _mm_free(ptr);
728 : #else
729 24 : free(ptr);
730 : #endif
731 : }
732 :
733 : FORCE_FINLINE std::string toHexString(const uint32_t i) {
734 44 : std::stringstream s;
735 : s << "0x" << std::hex << i;
736 : return s.str();
737 44 : }
|