Line data Source code
1 : #pragma once
2 :
3 : #include "definition.hpp"
4 : #include "evalDef.hpp"
5 : #include "material.hpp"
6 : #include "score.hpp"
7 : #include "stats.hpp"
8 : #include "tables.hpp"
9 : #include "threading.hpp"
10 :
11 : /*!
12 : * Searcher struct store all the information needed by a search thread
13 : * Implements main search function (driver, pvs, qsearch, see, display to GUI, ...)
14 : * This was inspired from the former thread Stockfish style management
15 : *
16 : * Many things are templates here, so other hpp file are included at the bottom of this one.
17 : */
18 : struct Searcher {
19 : bool stopFlag = true;
20 :
21 159967 : struct StackData {
22 : Position p;
23 : Hash h = nullHash;
24 : //EvalData data;
25 : ScoreType eval = 0;
26 : MiniMove threat = INVALIDMINIMOVE;
27 : };
28 :
29 : struct PVSData{
30 : // CMH
31 : CMHPtrArray cmhPtr;
32 :
33 : // move counting
34 : int validMoveCount {0};
35 : int validQuietMoveCount {0};
36 : int validNonPrunedCount {0};
37 :
38 : // from call
39 : ScoreType alpha {0};
40 : ScoreType beta {0};
41 : bool isInCheck {false};
42 : bool cutNode {false};
43 : bool pvnode {false};
44 : bool rootnode {false};
45 : bool theirTurn {false};
46 : bool withoutSkipMove {true};
47 : bool previousMoveIsNullMove {false};
48 :
49 : // tt related stuff
50 : DepthType marginDepth {0};
51 : TT::Bound bound {TT::B_none};
52 : bool ttMoveIsCapture {false};
53 : bool ttMoveSingularExt {false};
54 : bool ttMoveTried {false};
55 : bool validTTmove {false};
56 : bool ttHit {false};
57 : bool ttPV {false};
58 : bool ttIsCheck {false};
59 : bool formerPV {false};
60 : bool evalScoreIsHashScore {false};
61 :
62 : // context
63 : bool improving {false};
64 : bool isEmergencyDefence {false};
65 : bool isEmergencyAttack {false};
66 : bool isBoomingAttack {false};
67 : bool isBoomingDefend {false};
68 : bool isMoobingAttack {false};
69 : bool isMoobingDefend {false};
70 : bool isNotPawnEndGame {false};
71 : bool lessZugzwangRisk {false};
72 : bool isKnownEndGame {false};
73 :
74 : // situation
75 : bool bestMoveIsCheck {false};
76 : bool mateThreat {false};
77 : bool alphaUpdated {false};
78 :
79 : // current move
80 : bool isCheck {false};
81 : bool isQuiet {false};
82 : bool isAdvancedPawnPush {false};
83 : bool earlyMove {false};
84 : bool isTTMove {false};
85 :
86 : // pruning and extension triggers
87 : bool futility {false};
88 : bool lmp {false};
89 : bool historyPruning {false};
90 : bool capHistoryPruning {false};
91 : bool CMHPruning {false};
92 : bool BMextension {false};
93 : };
94 :
95 : MoveDifficultyUtil::MoveDifficulty moveDifficulty = MoveDifficultyUtil::MD_std;
96 : MoveDifficultyUtil::PositionEvolution positionEvolution = MoveDifficultyUtil::PE_std;
97 :
98 : TimeType currentMoveMs = 777;
99 : TimeType getCurrentMoveMs()const; // use this (and not the variable) to take emergency time into account !
100 :
101 : array1d<StackData, MAX_PLY> stack;
102 : [[nodiscard]] bool isBooming(uint16_t halfmove); // from stack
103 : [[nodiscard]] bool isMoobing(uint16_t halfmove); // from stack
104 :
105 : mutable Stats stats;
106 :
107 : // beta cut more refined statistics are possible and gather using this function
108 : void updateStatBetaCut(const Position & p, const Move m, const DepthType height);
109 :
110 : FORCE_FINLINE void updatePV(PVList& pv, const Move& m, const PVList& childPV) {
111 : stats.incr(Stats::sid_PVupdate);
112 : pv.clear();
113 13477 : pv.emplace_back(m);
114 13477 : std::ranges::copy(childPV, std::back_inserter(pv));
115 13477 : }
116 :
117 : void displayStats() const {
118 : for (size_t k = 0; k < Stats::sid_maxid; ++k) {
119 : Logging::LogIt(Logging::logInfo) << Stats::Names[k] << " " << stats.counters[(Stats::StatId)k];
120 : }
121 : }
122 :
123 : std::vector<RootScores> rootScores;
124 :
125 : // used for move ordering
126 : Move previousBest = INVALIDMOVE;
127 :
128 : KillerT killerT;
129 : HistoryT historyT;
130 : CounterT counterT;
131 : DepthType nullMoveMinPly = 0;
132 : Color nullMoveVerifColor = Co_None;
133 : EvalScore contempt = 0;
134 : bool subSearch = false;
135 : bool isStoppableCoSearcher = false;
136 : DepthType height_ = 0; ///@todo use this everywhere, instead of passing height in pvs and qsearch call ?
137 :
138 : #ifdef WITH_GENFILE
139 : std::ofstream genStream;
140 : void writeToGenFile(const Position& p, bool getQuietPos, const ThreadData & d, const std::optional<int> result);
141 : #endif
142 : std::ofstream pgnStream;
143 :
144 : static Position getQuiet(const Position& p, Searcher* searcher = nullptr, ScoreType* qScore = nullptr);
145 :
146 : static Searcher& getCoSearcher(size_t id);
147 :
148 : void getCMHPtr(const unsigned int ply, CMHPtrArray& cmhPtr);
149 : [[nodiscard]] ScoreType getCMHScore(const Position& p, const Square from, const Square to, const CMHPtrArray& cmhPtr) const;
150 :
151 : [[nodiscard]] bool isCMHGood(const Position& p, const Square from, const Square to, const CMHPtrArray& cmhPtr, const ScoreType threshold) const;
152 : [[nodiscard]] bool isCMHBad (const Position& p, const Square from, const Square to, const CMHPtrArray& cmhPtr, const ScoreType threshold) const;
153 :
154 : [[nodiscard]] ScoreType drawScore(const Position& p, DepthType height) const;
155 :
156 : std::tuple<DepthType, DepthType, DepthType> depthPolicy(const Position & p, DepthType depth, DepthType height, Move m, const PVSData & pvsData, const EvalData & evalData, ScoreType evalScore, DepthType extensions, bool isReductible) const;
157 :
158 : void timeCheck();
159 :
160 : template<bool pvnode>
161 : [[nodiscard]]
162 : ScoreType pvs(ScoreType alpha,
163 : ScoreType beta,
164 : const Position& p,
165 : DepthType depth,
166 : DepthType height,
167 : PVList& pv,
168 : DepthType& seldepth,
169 : DepthType extensions,
170 : bool isInCheck,
171 : bool cutNode,
172 : const std::vector<MiniMove>* skipMoves = nullptr);
173 :
174 : [[nodiscard]] ScoreType qsearch(ScoreType alpha,
175 : ScoreType beta,
176 : const Position& p,
177 : DepthType height,
178 : DepthType& seldepth,
179 : DepthType qply,
180 : bool qRoot,
181 : bool pvnode,
182 : int8_t isInCheckHint = -1);
183 :
184 : // used for tuning not search !
185 : [[nodiscard]] ScoreType qsearchNoPruning(ScoreType alpha,
186 : ScoreType beta,
187 : const Position& p,
188 : DepthType height,
189 : DepthType& seldepth,
190 : PVList* pv = nullptr);
191 :
192 : [[nodiscard]] static bool SEE_GE(const Position& p, const Move& m, ScoreType threshold);
193 :
194 : [[nodiscard]] static ScoreType SEE(const Position& p, const Move& m);
195 :
196 : void searchDriver(bool postMove = true);
197 :
198 : template<bool isPv = true>
199 : [[nodiscard]] std::optional<ScoreType> interiorNodeRecognizer(const Position& p, DepthType height) const;
200 :
201 : [[nodiscard]] bool isRep(const Position& p, bool isPv) const;
202 : [[nodiscard]] bool isMaterialDraw(const Position& p) const;
203 : [[nodiscard]] bool is50moves(const Position& p, bool afterMoveLoop) const;
204 :
205 : void displayGUI(DepthType depth,
206 : DepthType seldepth,
207 : ScoreType bestScore,
208 : unsigned int ply,
209 : const PVList& pv,
210 : int multipv,
211 : const std::string& mark = "");
212 :
213 : void idleLoop();
214 :
215 : void startThread();
216 :
217 : void wait();
218 :
219 : void searchLauncher();
220 :
221 : [[nodiscard]] size_t id() const;
222 : [[nodiscard]] bool isMainThread() const;
223 :
224 : explicit Searcher(size_t n);
225 : ~Searcher();
226 : // non copyable
227 : Searcher(const Searcher&) = delete;
228 : Searcher(const Searcher&&) = delete;
229 : Searcher& operator=(const Searcher&) = delete;
230 : Searcher& operator=(const Searcher&&) = delete;
231 :
232 : void setData(const ThreadData& d);
233 : [[nodiscard]] const ThreadData& getData() const;
234 : [[nodiscard]] ThreadData& getData();
235 : [[nodiscard]] const SearchData& getSearchData() const;
236 : [[nodiscard]] SearchData& getSearchData();
237 :
238 : static std::atomic<bool> startLock;
239 :
240 : std::chrono::time_point<Clock> startTime;
241 :
242 : [[nodiscard]] bool searching() const;
243 :
244 : void clearGame();
245 :
246 : void clearSearch(bool forceHistoryClear = false);
247 :
248 3014656 : struct PawnEntry {
249 : colored<BitBoard> pawnTargets = {emptyBitBoard, emptyBitBoard};
250 : colored<BitBoard> holes = {emptyBitBoard, emptyBitBoard};
251 : colored<BitBoard> semiOpenFiles = {emptyBitBoard, emptyBitBoard};
252 : colored<BitBoard> passed = {emptyBitBoard, emptyBitBoard};
253 : BitBoard openFiles = emptyBitBoard;
254 : EvalScore score = {0, 0};
255 : MiniHash h = nullHash;
256 : colored<ScoreType> danger = {0, 0};
257 :
258 : FORCE_FINLINE void reset() {
259 148754 : score = {0, 0};
260 148754 : danger[Co_White] = 0;
261 148754 : danger[Co_Black] = 0;
262 : }
263 : };
264 :
265 : std::unique_ptr<Searcher::PawnEntry[]> tablePawn = nullptr;
266 : uint64_t ttSizePawn = 0;
267 :
268 : void initPawnTable();
269 :
270 : void clearPawnTT();
271 :
272 : [[nodiscard]] bool getPawnEntry(Hash h, PawnEntry*& pe);
273 :
274 : void prefetchPawn(Hash h);
275 :
276 : private:
277 : ThreadData _data;
278 : std::mutex _mutexPV;
279 : size_t _index;
280 : std::mutex _mutex;
281 : std::condition_variable _cv;
282 : // next two MUST be initialized BEFORE _stdThread
283 : bool _exit;
284 : bool _searching;
285 : std::thread _stdThread;
286 : };
287 :
288 : #include "searcherDraw.hpp"
289 : #include "searcherPVS.hpp"
|