Rev 96 | Rev 169 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 96 | Rev 154 | ||
---|---|---|---|
Line 27... | Line 27... | ||
27 | 27 | ||
28 | #include "evaluate.h" |
28 | #include "evaluate.h" |
29 | #include "misc.h" |
29 | #include "misc.h" |
30 | #include "movegen.h" |
30 | #include "movegen.h" |
31 | #include "movepick.h" |
31 | #include "movepick.h" |
- | 32 | #include "position.h" |
|
32 | #include "search.h" |
33 | #include "search.h" |
33 | #include "timeman.h" |
34 | #include "timeman.h" |
34 | #include "thread.h" |
35 | #include "thread.h" |
35 | #include "tt.h" |
36 | #include "tt.h" |
36 | #include "uci.h" |
37 | #include "uci.h" |
Line 38... | Line 39... | ||
38 | 39 | ||
39 | namespace Search { |
40 | namespace Search { |
40 | 41 | ||
41 | SignalsType Signals; |
42 | SignalsType Signals; |
42 | LimitsType Limits; |
43 | LimitsType Limits; |
43 | StateStackPtr SetupStates; |
- | |
44 | } |
44 | } |
45 | 45 | ||
46 | namespace Tablebases { |
46 | namespace Tablebases { |
47 | 47 | ||
48 | int Cardinality; |
48 | int Cardinality; |
49 | uint64_t Hits; |
- | |
50 | bool RootInTB; |
49 | bool RootInTB; |
51 | bool UseRule50; |
50 | bool UseRule50; |
52 | Depth ProbeDepth; |
51 | Depth ProbeDepth; |
53 | Value Score; |
52 | Value Score; |
54 | } |
53 | } |
Line 64... | Line 63... | ||
64 | // Different node types, used as a template parameter |
63 | // Different node types, used as a template parameter |
65 | enum NodeType { NonPV, PV }; |
64 | enum NodeType { NonPV, PV }; |
66 | 65 | ||
67 | // Razoring and futility margin based on depth |
66 | // Razoring and futility margin based on depth |
68 | const int razor_margin[4] = { 483, 570, 603, 554 }; |
67 | const int razor_margin[4] = { 483, 570, 603, 554 }; |
69 | Value futility_margin(Depth d) { return Value( |
68 | Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); } |
70 | 69 | ||
71 | // Futility and reductions lookup tables, initialized at startup |
70 | // Futility and reductions lookup tables, initialized at startup |
72 | int FutilityMoveCounts[2][16]; |
71 | int FutilityMoveCounts[2][16]; // [improving][depth] |
73 |
|
72 | int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber] |
74 | 73 | ||
75 | template <bool PvNode> Depth reduction(bool i, Depth d, int mn) { |
74 | template <bool PvNode> Depth reduction(bool i, Depth d, int mn) { |
76 | return Reductions[PvNode][i][std::min( |
75 | return Reductions[PvNode][i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] * ONE_PLY; |
77 | } |
76 | } |
78 | 77 | ||
79 | // Skill structure is used to implement strength limit |
78 | // Skill structure is used to implement strength limit |
80 | struct Skill { |
79 | struct Skill { |
81 | Skill(int l) : level(l) {} |
80 | Skill(int l) : level(l) {} |
Line 112... | Line 111... | ||
112 | if (!std::equal(newPv.begin(), newPv.begin() + 3, pv)) |
111 | if (!std::equal(newPv.begin(), newPv.begin() + 3, pv)) |
113 | { |
112 | { |
114 | std::copy(newPv.begin(), newPv.begin() + 3, pv); |
113 | std::copy(newPv.begin(), newPv.begin() + 3, pv); |
115 | 114 | ||
116 | StateInfo st[2]; |
115 | StateInfo st[2]; |
117 | pos.do_move(newPv[0], st[0], pos.gives_check(newPv[0] |
116 | pos.do_move(newPv[0], st[0], pos.gives_check(newPv[0])); |
118 | pos.do_move(newPv[1], st[1], pos.gives_check(newPv[1] |
117 | pos.do_move(newPv[1], st[1], pos.gives_check(newPv[1])); |
119 | expectedPosKey = pos.key(); |
118 | expectedPosKey = pos.key(); |
120 | pos.undo_move(newPv[1]); |
119 | pos.undo_move(newPv[1]); |
121 | pos.undo_move(newPv[0]); |
120 | pos.undo_move(newPv[0]); |
122 | } |
121 | } |
123 | } |
122 | } |
Line 156... | Line 155... | ||
156 | 155 | ||
157 | const size_t HalfDensitySize = std::extent<decltype(HalfDensity)>::value; |
156 | const size_t HalfDensitySize = std::extent<decltype(HalfDensity)>::value; |
158 | 157 | ||
159 | EasyMoveManager EasyMove; |
158 | EasyMoveManager EasyMove; |
160 | Value DrawValue[COLOR_NB]; |
159 | Value DrawValue[COLOR_NB]; |
161 | CounterMoveHistoryStats CounterMoveHistory; |
- | |
162 | 160 | ||
163 | template <NodeType NT> |
161 | template <NodeType NT> |
164 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); |
162 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); |
165 | 163 | ||
166 | template <NodeType NT, bool InCheck> |
164 | template <NodeType NT, bool InCheck> |
167 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); |
165 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); |
168 | 166 | ||
169 | Value value_to_tt(Value v, int ply); |
167 | Value value_to_tt(Value v, int ply); |
170 | Value value_from_tt(Value v, int ply); |
168 | Value value_from_tt(Value v, int ply); |
171 | void update_pv(Move* pv, Move move, Move* childPv); |
169 | void update_pv(Move* pv, Move move, Move* childPv); |
- | 170 | void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus); |
|
172 | void update_stats(const Position& pos, Stack* ss, Move move, |
171 | void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, Value bonus); |
173 | void check_time(); |
172 | void check_time(); |
174 | 173 | ||
175 | } // namespace |
174 | } // namespace |
176 | 175 | ||
177 | 176 | ||
178 | /// Search::init() is called during startup to initialize various lookup tables |
177 | /// Search::init() is called during startup to initialize various lookup tables |
179 | 178 | ||
180 | void Search::init() { |
179 | void Search::init() { |
181 | 180 | ||
- | 181 | for (int imp = 0; imp <= 1; ++imp) |
|
- | 182 | for (int d = 1; d < 64; ++d) |
|
- | 183 | for (int mc = 1; mc < 64; ++mc) |
|
- | 184 | { |
|
182 |
|
185 | double r = log(d) * log(mc) / 2; |
- | 186 | if (r < 0.80) |
|
- | 187 | continue; |
|
183 | 188 | ||
184 | for (int pv = 0; pv <= 1; ++pv) |
- | |
185 | for (int imp = 0; imp <= 1; ++imp) |
- | |
186 | for (int d = 1; d < 64; ++d) |
- | |
187 |
|
189 | Reductions[NonPV][imp][d][mc] = int(std::round(r)); |
188 | { |
- | |
189 |
|
190 | Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0); |
190 | 191 | ||
191 | if (r >= 1.5) |
- | |
192 | Reductions[pv][imp][d][mc] = int(r) * ONE_PLY; |
- | |
193 | - | ||
194 |
|
192 | // Increase reduction for non-PV nodes when eval is not improving |
195 |
|
193 | if (!imp && Reductions[NonPV][imp][d][mc] >= 2) |
196 |
|
194 | Reductions[NonPV][imp][d][mc]++; |
197 |
|
195 | } |
198 | 196 | ||
199 | for (int d = 0; d < 16; ++d) |
197 | for (int d = 0; d < 16; ++d) |
200 | { |
198 | { |
201 | FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8)); |
199 | FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8)); |
202 | FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8)); |
200 | FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8)); |
Line 207... | Line 205... | ||
207 | /// Search::clear() resets search state to zero, to obtain reproducible results |
205 | /// Search::clear() resets search state to zero, to obtain reproducible results |
208 | 206 | ||
209 | void Search::clear() { |
207 | void Search::clear() { |
210 | 208 | ||
211 | TT.clear(); |
209 | TT.clear(); |
212 | CounterMoveHistory.clear(); |
- | |
213 | 210 | ||
214 | for (Thread* th : Threads) |
211 | for (Thread* th : Threads) |
215 | { |
212 | { |
216 | th->history.clear(); |
213 | th->history.clear(); |
217 | th->counterMoves.clear(); |
214 | th->counterMoves.clear(); |
- | 215 | th->fromTo.clear(); |
|
- | 216 | th->counterMoveHistory.clear(); |
|
218 | } |
217 | } |
219 | 218 | ||
220 | Threads.main()->previousScore = VALUE_INFINITE; |
219 | Threads.main()->previousScore = VALUE_INFINITE; |
221 | } |
220 | } |
222 | 221 | ||
Line 226... | Line 225... | ||
226 | template<bool Root> |
225 | template<bool Root> |
227 | uint64_t Search::perft(Position& pos, Depth depth) { |
226 | uint64_t Search::perft(Position& pos, Depth depth) { |
228 | 227 | ||
229 | StateInfo st; |
228 | StateInfo st; |
230 | uint64_t cnt, nodes = 0; |
229 | uint64_t cnt, nodes = 0; |
231 | CheckInfo ci(pos); |
- | |
232 | const bool leaf = (depth == 2 * ONE_PLY); |
230 | const bool leaf = (depth == 2 * ONE_PLY); |
233 | 231 | ||
234 | for (const auto& m : MoveList<LEGAL>(pos)) |
232 | for (const auto& m : MoveList<LEGAL>(pos)) |
235 | { |
233 | { |
236 | if (Root && depth <= ONE_PLY) |
234 | if (Root && depth <= ONE_PLY) |
237 | cnt = 1, nodes++; |
235 | cnt = 1, nodes++; |
238 | else |
236 | else |
239 | { |
237 | { |
240 | pos.do_move(m, st, pos.gives_check( |
238 | pos.do_move(m, st, pos.gives_check(m)); |
241 | cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY); |
239 | cnt = leaf ? MoveList<LEGAL>(pos).size() : perft<false>(pos, depth - ONE_PLY); |
242 | nodes += cnt; |
240 | nodes += cnt; |
243 | pos.undo_move(m); |
241 | pos.undo_move(m); |
244 | } |
242 | } |
245 | if (Root) |
243 | if (Root) |
Line 260... | Line 258... | ||
260 | Time.init(Limits, us, rootPos.game_ply()); |
258 | Time.init(Limits, us, rootPos.game_ply()); |
261 | 259 | ||
262 | int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns |
260 | int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns |
263 | DrawValue[ us] = VALUE_DRAW - Value(contempt); |
261 | DrawValue[ us] = VALUE_DRAW - Value(contempt); |
264 | DrawValue[~us] = VALUE_DRAW + Value(contempt); |
262 | DrawValue[~us] = VALUE_DRAW + Value(contempt); |
265 | - | ||
266 | TB::Hits = 0; |
- | |
267 | TB::RootInTB = false; |
- | |
268 | TB::UseRule50 = Options["Syzygy50MoveRule"]; |
- | |
269 | TB::ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY; |
- | |
270 | TB::Cardinality = Options["SyzygyProbeLimit"]; |
- | |
271 | - | ||
272 | // Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality |
- | |
273 | if (TB::Cardinality > TB::MaxCardinality) |
- | |
274 | { |
- | |
275 | TB::Cardinality = TB::MaxCardinality; |
- | |
276 | TB::ProbeDepth = DEPTH_ZERO; |
- | |
277 | } |
- | |
278 | 263 | ||
279 | if (rootMoves.empty()) |
264 | if (rootMoves.empty()) |
280 | { |
265 | { |
281 | rootMoves.push_back(RootMove(MOVE_NONE)); |
266 | rootMoves.push_back(RootMove(MOVE_NONE)); |
282 | sync_cout << "info depth 0 score " |
267 | sync_cout << "info depth 0 score " |
283 | << UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW) |
268 | << UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW) |
284 | << sync_endl; |
269 | << sync_endl; |
285 | } |
270 | } |
286 | else |
271 | else |
287 | { |
272 | { |
288 | if ( TB::Cardinality >= rootPos.count<ALL_PIECES>(WHITE) |
- | |
289 | + rootPos.count<ALL_PIECES>(BLACK) |
- | |
290 | && !rootPos.can_castle(ANY_CASTLING)) |
- | |
291 | { |
- | |
292 | // If the current root position is in the tablebases, then RootMoves |
- | |
293 | // contains only moves that preserve the draw or the win. |
- | |
294 | TB::RootInTB = Tablebases::root_probe(rootPos, rootMoves, TB::Score); |
- | |
295 | - | ||
296 | if (TB::RootInTB) |
- | |
297 | TB::Cardinality = 0; // Do not probe tablebases during the search |
- | |
298 | - | ||
299 | else // If DTZ tables are missing, use WDL tables as a fallback |
- | |
300 | { |
- | |
301 | // Filter out moves that do not preserve the draw or the win. |
- | |
302 | TB::RootInTB = Tablebases::root_probe_wdl(rootPos, rootMoves, TB::Score); |
- | |
303 | - | ||
304 | // Only probe during search if winning |
- | |
305 | if (TB::Score <= VALUE_DRAW) |
- | |
306 | TB::Cardinality = 0; |
- | |
307 | } |
- | |
308 | - | ||
309 | if (TB::RootInTB) |
- | |
310 | { |
- | |
311 | TB::Hits = rootMoves.size(); |
- | |
312 | - | ||
313 | if (!TB::UseRule50) |
- | |
314 | TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1 |
- | |
315 | : TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1 |
- | |
316 | : VALUE_DRAW; |
- | |
317 | } |
- | |
318 | } |
- | |
319 | - | ||
320 | for (Thread* th : Threads) |
273 | for (Thread* th : Threads) |
321 | { |
- | |
322 | th->maxPly = 0; |
- | |
323 | th->rootDepth = DEPTH_ZERO; |
- | |
324 | if (th != this) |
274 | if (th != this) |
325 | { |
- | |
326 | th->rootPos = Position(rootPos, th); |
- | |
327 | th->rootMoves = rootMoves; |
- | |
328 | th->start_searching(); |
275 | th->start_searching(); |
329 | } |
- | |
330 | } |
- | |
331 | 276 | ||
332 | Thread::search(); // Let's start searching! |
277 | Thread::search(); // Let's start searching! |
333 | } |
278 | } |
334 | 279 | ||
335 | // When playing in 'nodes as time' mode, subtract the searched nodes from |
280 | // When playing in 'nodes as time' mode, subtract the searched nodes from |
Line 358... | Line 303... | ||
358 | 303 | ||
359 | // Check if there are threads with a better score than main thread |
304 | // Check if there are threads with a better score than main thread |
360 | Thread* bestThread = this; |
305 | Thread* bestThread = this; |
361 | if ( !this->easyMovePlayed |
306 | if ( !this->easyMovePlayed |
362 | && Options["MultiPV"] == 1 |
307 | && Options["MultiPV"] == 1 |
- | 308 | && !Limits.depth |
|
363 | && !Skill(Options["Skill Level"]).enabled( |
309 | && !Skill(Options["Skill Level"]).enabled() |
- | 310 | && rootMoves[0].pv[0] != MOVE_NONE) |
|
364 | { |
311 | { |
365 | for (Thread* th : Threads) |
312 | for (Thread* th : Threads) |
366 | if ( th->completedDepth > bestThread->completedDepth |
313 | if ( th->completedDepth > bestThread->completedDepth |
367 | && th->rootMoves[0].score > bestThread->rootMoves[0].score) |
314 | && th->rootMoves[0].score > bestThread->rootMoves[0].score) |
368 | bestThread = th; |
315 | bestThread = th; |
Line 387... | Line 334... | ||
387 | // repeatedly with increasing depth until the allocated thinking time has been |
334 | // repeatedly with increasing depth until the allocated thinking time has been |
388 | // consumed, the user stops the search, or the maximum search depth is reached. |
335 | // consumed, the user stops the search, or the maximum search depth is reached. |
389 | 336 | ||
390 | void Thread::search() { |
337 | void Thread::search() { |
391 | 338 | ||
392 | Stack stack[MAX_PLY+ |
339 | Stack stack[MAX_PLY+7], *ss = stack+5; // To allow referencing (ss-5) and (ss+2) |
393 | Value bestValue, alpha, beta, delta; |
340 | Value bestValue, alpha, beta, delta; |
394 | Move easyMove = MOVE_NONE; |
341 | Move easyMove = MOVE_NONE; |
395 | MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); |
342 | MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); |
396 | 343 | ||
397 | std::memset(ss- |
344 | std::memset(ss-5, 0, 8 * sizeof(Stack)); |
398 | 345 | ||
399 | bestValue = delta = alpha = -VALUE_INFINITE; |
346 | bestValue = delta = alpha = -VALUE_INFINITE; |
400 | beta = VALUE_INFINITE; |
347 | beta = VALUE_INFINITE; |
401 | completedDepth = DEPTH_ZERO; |
348 | completedDepth = DEPTH_ZERO; |
402 | 349 | ||
Line 417... | Line 364... | ||
417 | if (skill.enabled()) |
364 | if (skill.enabled()) |
418 | multiPV = std::max(multiPV, (size_t)4); |
365 | multiPV = std::max(multiPV, (size_t)4); |
419 | 366 | ||
420 | multiPV = std::min(multiPV, rootMoves.size()); |
367 | multiPV = std::min(multiPV, rootMoves.size()); |
421 | 368 | ||
422 | // Iterative deepening loop until requested to stop or the target depth is reached |
369 | // Iterative deepening loop until requested to stop or the target depth is reached |
- | 370 | while ( (rootDepth += ONE_PLY) < DEPTH_MAX |
|
- | 371 | && !Signals.stop |
|
423 |
|
372 | && (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth)) |
424 | { |
373 | { |
425 | // Set up the new depths for the helper threads skipping on average every |
374 | // Set up the new depths for the helper threads skipping on average every |
426 | // 2nd ply (using a half-density matrix). |
375 | // 2nd ply (using a half-density matrix). |
427 | if (!mainThread) |
376 | if (!mainThread) |
428 | { |
377 | { |
429 | const Row& row = HalfDensity[(idx - 1) % HalfDensitySize]; |
378 | const Row& row = HalfDensity[(idx - 1) % HalfDensitySize]; |
430 | if (row[(rootDepth + rootPos.game_ply()) % row.size()]) |
379 | if (row[(rootDepth / ONE_PLY + rootPos.game_ply()) % row.size()]) |
431 | continue; |
380 | continue; |
432 | } |
381 | } |
433 | 382 | ||
434 | // Age out PV variability metric |
383 | // Age out PV variability metric |
435 | if (mainThread) |
384 | if (mainThread) |
Line 463... | Line 412... | ||
463 | // first and eventually the new best one are set to -VALUE_INFINITE |
412 | // first and eventually the new best one are set to -VALUE_INFINITE |
464 | // and we want to keep the same order for all the moves except the |
413 | // and we want to keep the same order for all the moves except the |
465 | // new PV that goes to the front. Note that in case of MultiPV |
414 | // new PV that goes to the front. Note that in case of MultiPV |
466 | // search the already searched PV lines are preserved. |
415 | // search the already searched PV lines are preserved. |
467 | std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end()); |
416 | std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end()); |
468 | - | ||
469 | // Write PV back to the transposition table in case the relevant |
- | |
470 | // entries have been overwritten during the search. |
- | |
471 | for (size_t i = 0; i <= PVIdx; ++i) |
- | |
472 | rootMoves[i].insert_pv_in_tt(rootPos); |
- | |
473 | 417 | ||
474 | // If search has been stopped, break immediately. Sorting and |
418 | // If search has been stopped, break immediately. Sorting and |
475 | // writing PV back to TT is safe because RootMoves is still |
419 | // writing PV back to TT is safe because RootMoves is still |
476 | // valid, although it refers to the previous iteration. |
420 | // valid, although it refers to the previous iteration. |
477 | if (Signals.stop) |
421 | if (Signals.stop) |
Line 513... | Line 457... | ||
513 | 457 | ||
514 | // Sort the PV lines searched so far and update the GUI |
458 | // Sort the PV lines searched so far and update the GUI |
515 | std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1); |
459 | std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1); |
516 | 460 | ||
517 | if (!mainThread) |
461 | if (!mainThread) |
518 |
|
462 | continue; |
519 | - | ||
520 | if (Signals.stop) |
- | |
521 | sync_cout << "info nodes " << Threads.nodes_searched() |
- | |
522 | << " time " << Time.elapsed() << sync_endl; |
- | |
523 | 463 | ||
524 |
|
464 | if (Signals.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000) |
525 | sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; |
465 | sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; |
526 | } |
466 | } |
527 | 467 | ||
528 | if (!Signals.stop) |
468 | if (!Signals.stop) |
529 | completedDepth = rootDepth; |
469 | completedDepth = rootDepth; |
Line 547... | Line 487... | ||
547 | if (!Signals.stop && !Signals.stopOnPonderhit) |
487 | if (!Signals.stop && !Signals.stopOnPonderhit) |
548 | { |
488 | { |
549 | // Stop the search if only one legal move is available, or if all |
489 | // Stop the search if only one legal move is available, or if all |
550 | // of the available time has been used, or if we matched an easyMove |
490 | // of the available time has been used, or if we matched an easyMove |
551 | // from the previous search and just did a fast verification. |
491 | // from the previous search and just did a fast verification. |
552 | const |
492 | const int F[] = { mainThread->failedLow, |
553 |
|
493 | bestValue - mainThread->previousScore }; |
554 | 494 | ||
555 | int improvingFactor = |
495 | int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1])); |
556 | double unstablePvFactor = 1 + mainThread->bestMoveChanges; |
496 | double unstablePvFactor = 1 + mainThread->bestMoveChanges; |
557 | 497 | ||
558 | bool doEasyMove = rootMoves[0].pv[0] == easyMove |
498 | bool doEasyMove = rootMoves[0].pv[0] == easyMove |
559 | && mainThread->bestMoveChanges < 0.03 |
499 | && mainThread->bestMoveChanges < 0.03 |
560 | && Time.elapsed() > Time.optimum() * |
500 | && Time.elapsed() > Time.optimum() * 5 / 42; |
561 | 501 | ||
562 | if ( rootMoves.size() == 1 |
502 | if ( rootMoves.size() == 1 |
563 | || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / |
503 | || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628 |
564 | || (mainThread->easyMovePlayed = doEasyMove)) |
504 | || (mainThread->easyMovePlayed = doEasyMove, doEasyMove)) |
565 | { |
505 | { |
566 | // If we are allowed to ponder do not stop the search now but |
506 | // If we are allowed to ponder do not stop the search now but |
567 | // keep pondering until the GUI sends "ponderhit" or "stop". |
507 | // keep pondering until the GUI sends "ponderhit" or "stop". |
568 | if (Limits.ponder) |
508 | if (Limits.ponder) |
569 | Signals.stopOnPonderhit = true; |
509 | Signals.stopOnPonderhit = true; |
Line 605... | Line 545... | ||
605 | const bool rootNode = PvNode && (ss-1)->ply == 0; |
545 | const bool rootNode = PvNode && (ss-1)->ply == 0; |
606 | 546 | ||
607 | assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); |
547 | assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); |
608 | assert(PvNode || (alpha == beta - 1)); |
548 | assert(PvNode || (alpha == beta - 1)); |
609 | assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); |
549 | assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); |
- | 550 | assert(!(PvNode && cutNode)); |
|
- | 551 | assert(depth / ONE_PLY * ONE_PLY == depth); |
|
610 | 552 | ||
611 | Move pv[MAX_PLY+1], quietsSearched[64]; |
553 | Move pv[MAX_PLY+1], quietsSearched[64]; |
612 | StateInfo st; |
554 | StateInfo st; |
613 | TTEntry* tte; |
555 | TTEntry* tte; |
614 | Key posKey; |
556 | Key posKey; |
615 | Move ttMove, move, excludedMove, bestMove; |
557 | Move ttMove, move, excludedMove, bestMove; |
616 | Depth extension, |
558 | Depth extension, newDepth; |
617 | Value bestValue, value, ttValue, eval, |
559 | Value bestValue, value, ttValue, eval, nullValue; |
618 | bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; |
560 | bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; |
619 | bool captureOrPromotion, |
561 | bool captureOrPromotion, doFullDepthSearch, moveCountPruning; |
- | 562 | Piece moved_piece; |
|
620 | int moveCount, quietCount; |
563 | int moveCount, quietCount; |
621 | 564 | ||
622 | // Step 1. Initialize node |
565 | // Step 1. Initialize node |
623 | Thread* thisThread = pos.this_thread(); |
566 | Thread* thisThread = pos.this_thread(); |
624 | inCheck = pos.checkers(); |
567 | inCheck = pos.checkers(); |
625 | moveCount = quietCount = ss->moveCount = 0; |
568 | moveCount = quietCount = ss->moveCount = 0; |
- | 569 | ss->history = VALUE_ZERO; |
|
626 | bestValue = -VALUE_INFINITE; |
570 | bestValue = -VALUE_INFINITE; |
627 | ss->ply = (ss-1)->ply + 1; |
571 | ss->ply = (ss-1)->ply + 1; |
628 | 572 | ||
629 | // Check for the available remaining time |
573 | // Check for the available remaining time |
630 | if (thisThread->resetCalls.load(std::memory_order_relaxed)) |
574 | if (thisThread->resetCalls.load(std::memory_order_relaxed)) |
Line 664... | Line 608... | ||
664 | } |
608 | } |
665 | 609 | ||
666 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
610 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
667 | 611 | ||
668 | ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; |
612 | ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; |
- | 613 | ss->counterMoves = nullptr; |
|
669 | (ss+1)->skipEarlyPruning = false; |
614 | (ss+1)->skipEarlyPruning = false; |
670 | (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; |
615 | (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; |
671 | 616 | ||
672 | // Step 4. Transposition table lookup. We don't want the score of a partial |
617 | // Step 4. Transposition table lookup. We don't want the score of a partial |
673 | // search to overwrite a previous full search TT value, so we use a different |
618 | // search to overwrite a previous full search TT value, so we use a different |
674 | // position key in case of an excluded move. |
619 | // position key in case of an excluded move. |
675 | excludedMove = ss->excludedMove; |
620 | excludedMove = ss->excludedMove; |
676 | posKey = |
621 | posKey = pos.key() ^ Key(excludedMove); |
677 | tte = TT.probe(posKey, ttHit); |
622 | tte = TT.probe(posKey, ttHit); |
678 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
623 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
679 | ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0] |
624 | ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0] |
680 | : ttHit ? tte->move() : MOVE_NONE; |
625 | : ttHit ? tte->move() : MOVE_NONE; |
681 | 626 | ||
Line 685... | Line 630... | ||
685 | && tte->depth() >= depth |
630 | && tte->depth() >= depth |
686 | && ttValue != VALUE_NONE // Possible in case of TT access race |
631 | && ttValue != VALUE_NONE // Possible in case of TT access race |
687 | && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) |
632 | && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) |
688 | : (tte->bound() & BOUND_UPPER))) |
633 | : (tte->bound() & BOUND_UPPER))) |
689 | { |
634 | { |
690 | ss->currentMove = ttMove; // Can be MOVE_NONE |
- | |
691 | - | ||
692 | // If ttMove is quiet, update killers, history, counter move on TT hit |
635 | // If ttMove is quiet, update killers, history, counter move on TT hit |
693 | if (ttValue >= beta && ttMove |
636 | if (ttValue >= beta && ttMove) |
- | 637 | { |
|
694 |
|
638 | int d = depth / ONE_PLY; |
695 | 639 | ||
- | 640 | if (!pos.capture_or_promotion(ttMove)) |
|
- | 641 | { |
|
- | 642 | Value bonus = Value(d * d + 2 * d - 2); |
|
- | 643 | update_stats(pos, ss, ttMove, nullptr, 0, bonus); |
|
- | 644 | } |
|
- | 645 | ||
- | 646 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
|
- | 647 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
|
- | 648 | { |
|
- | 649 | Value penalty = Value(d * d + 4 * d + 1); |
|
- | 650 | Square prevSq = to_sq((ss-1)->currentMove); |
|
- | 651 | update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -penalty); |
|
- | 652 | } |
|
- | 653 | } |
|
696 | return ttValue; |
654 | return ttValue; |
697 | } |
655 | } |
698 | 656 | ||
699 | // Step 4a. Tablebase probe |
657 | // Step 4a. Tablebase probe |
700 | if (!rootNode && TB::Cardinality) |
658 | if (!rootNode && TB::Cardinality) |
Line 708... | Line 666... | ||
708 | { |
666 | { |
709 | int found, v = Tablebases::probe_wdl(pos, &found); |
667 | int found, v = Tablebases::probe_wdl(pos, &found); |
710 | 668 | ||
711 | if (found) |
669 | if (found) |
712 | { |
670 | { |
713 |
|
671 | thisThread->tbHits++; |
714 | 672 | ||
715 | int drawScore = TB::UseRule50 ? 1 : 0; |
673 | int drawScore = TB::UseRule50 ? 1 : 0; |
716 | 674 | ||
717 | value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply |
675 | value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply |
718 | : v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply |
676 | : v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply |
Line 759... | Line 717... | ||
759 | goto moves_loop; |
717 | goto moves_loop; |
760 | 718 | ||
761 | // Step 6. Razoring (skipped when in check) |
719 | // Step 6. Razoring (skipped when in check) |
762 | if ( !PvNode |
720 | if ( !PvNode |
763 | && depth < 4 * ONE_PLY |
721 | && depth < 4 * ONE_PLY |
764 | && eval + razor_margin[depth] <= alpha |
- | |
765 | && ttMove == MOVE_NONE |
722 | && ttMove == MOVE_NONE |
- | 723 | && eval + razor_margin[depth / ONE_PLY] <= alpha) |
|
766 | { |
724 | { |
767 | if ( |
725 | if (depth <= ONE_PLY) |
768 | && eval + razor_margin[3 * ONE_PLY] <= alpha) |
- | |
769 | return qsearch<NonPV, false>(pos, ss, alpha, beta, DEPTH_ZERO); |
726 | return qsearch<NonPV, false>(pos, ss, alpha, beta, DEPTH_ZERO); |
770 | 727 | ||
771 | Value ralpha = alpha - razor_margin[depth]; |
728 | Value ralpha = alpha - razor_margin[depth / ONE_PLY]; |
772 | Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1, DEPTH_ZERO); |
729 | Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1, DEPTH_ZERO); |
773 | if (v <= ralpha) |
730 | if (v <= ralpha) |
774 | return v; |
731 | return v; |
775 | } |
732 | } |
776 | 733 | ||
Line 778... | Line 735... | ||
778 | if ( !rootNode |
735 | if ( !rootNode |
779 | && depth < 7 * ONE_PLY |
736 | && depth < 7 * ONE_PLY |
780 | && eval - futility_margin(depth) >= beta |
737 | && eval - futility_margin(depth) >= beta |
781 | && eval < VALUE_KNOWN_WIN // Do not return unproven wins |
738 | && eval < VALUE_KNOWN_WIN // Do not return unproven wins |
782 | && pos.non_pawn_material(pos.side_to_move())) |
739 | && pos.non_pawn_material(pos.side_to_move())) |
783 | return eval |
740 | return eval; |
784 | 741 | ||
785 | // Step 8. Null move search with verification search (is omitted in PV nodes) |
742 | // Step 8. Null move search with verification search (is omitted in PV nodes) |
786 | if ( !PvNode |
743 | if ( !PvNode |
787 | && depth >= 2 * ONE_PLY |
- | |
788 | && eval >= beta |
744 | && eval >= beta |
- | 745 | && (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY) |
|
789 | && pos.non_pawn_material(pos.side_to_move())) |
746 | && pos.non_pawn_material(pos.side_to_move())) |
790 | { |
747 | { |
791 | ss->currentMove = MOVE_NULL; |
748 | ss->currentMove = MOVE_NULL; |
- | 749 | ss->counterMoves = nullptr; |
|
792 | 750 | ||
793 | assert(eval - beta >= 0); |
751 | assert(eval - beta >= 0); |
794 | 752 | ||
795 | // Null move dynamic reduction based on depth and value |
753 | // Null move dynamic reduction based on depth and value |
796 | Depth R = ((823 + 67 * depth) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY; |
754 | Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY; |
797 | 755 | ||
798 | pos.do_null_move(st); |
756 | pos.do_null_move(st); |
799 | (ss+1)->skipEarlyPruning = true; |
757 | (ss+1)->skipEarlyPruning = true; |
800 | nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO) |
758 | nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO) |
801 | : - search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode); |
759 | : - search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode); |
Line 821... | Line 779... | ||
821 | return nullValue; |
779 | return nullValue; |
822 | } |
780 | } |
823 | } |
781 | } |
824 | 782 | ||
825 | // Step 9. ProbCut (skipped when in check) |
783 | // Step 9. ProbCut (skipped when in check) |
826 | // If we have a |
784 | // If we have a good enough capture and a reduced search returns a value |
827 | // and a reduced search returns a value much above beta, we can (almost) |
- | |
828 | // safely prune the previous move. |
785 | // much above beta, we can (almost) safely prune the previous move. |
829 | if ( !PvNode |
786 | if ( !PvNode |
830 | && depth >= 5 * ONE_PLY |
787 | && depth >= 5 * ONE_PLY |
831 | && abs(beta) < VALUE_MATE_IN_MAX_PLY) |
788 | && abs(beta) < VALUE_MATE_IN_MAX_PLY) |
832 | { |
789 | { |
833 | Value rbeta = std::min(beta + 200, VALUE_INFINITE); |
790 | Value rbeta = std::min(beta + 200, VALUE_INFINITE); |
Line 835... | Line 792... | ||
835 | 792 | ||
836 | assert(rdepth >= ONE_PLY); |
793 | assert(rdepth >= ONE_PLY); |
837 | assert((ss-1)->currentMove != MOVE_NONE); |
794 | assert((ss-1)->currentMove != MOVE_NONE); |
838 | assert((ss-1)->currentMove != MOVE_NULL); |
795 | assert((ss-1)->currentMove != MOVE_NULL); |
839 | 796 | ||
840 | MovePicker mp(pos, ttMove, |
797 | MovePicker mp(pos, ttMove, rbeta - ss->staticEval); |
841 | CheckInfo ci(pos); |
- | |
842 | 798 | ||
843 | while ((move = mp.next_move()) != MOVE_NONE) |
799 | while ((move = mp.next_move()) != MOVE_NONE) |
844 | if (pos.legal( |
800 | if (pos.legal(move)) |
845 | { |
801 | { |
846 | ss->currentMove = move; |
802 | ss->currentMove = move; |
- | 803 | ss->counterMoves = &thisThread->counterMoveHistory[pos.moved_piece(move)][to_sq(move)]; |
|
847 | pos.do_move(move, st, pos.gives_check( |
804 | pos.do_move(move, st, pos.gives_check(move)); |
848 | value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode); |
805 | value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode); |
849 | pos.undo_move(move); |
806 | pos.undo_move(move); |
850 | if (value >= rbeta) |
807 | if (value >= rbeta) |
851 | return value; |
808 | return value; |
852 | } |
809 | } |
853 | } |
810 | } |
854 | 811 | ||
855 | // Step 10. Internal iterative deepening (skipped when in check) |
812 | // Step 10. Internal iterative deepening (skipped when in check) |
856 | if ( depth >= |
813 | if ( depth >= 6 * ONE_PLY |
857 | && !ttMove |
814 | && !ttMove |
858 | && (PvNode || ss->staticEval + 256 >= beta)) |
815 | && (PvNode || ss->staticEval + 256 >= beta)) |
859 | { |
816 | { |
860 | Depth d = |
817 | Depth d = (3 * depth / (4 * ONE_PLY) - 2) * ONE_PLY; |
861 | ss->skipEarlyPruning = true; |
818 | ss->skipEarlyPruning = true; |
862 | search<NT>(pos, ss, alpha, beta, d, |
819 | search<NT>(pos, ss, alpha, beta, d, cutNode); |
863 | ss->skipEarlyPruning = false; |
820 | ss->skipEarlyPruning = false; |
864 | 821 | ||
865 | tte = TT.probe(posKey, ttHit); |
822 | tte = TT.probe(posKey, ttHit); |
866 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
823 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
867 | } |
824 | } |
868 | 825 | ||
869 | moves_loop: // When in check search starts from here |
826 | moves_loop: // When in check search starts from here |
870 | 827 | ||
871 |
|
828 | const CounterMoveStats* cmh = (ss-1)->counterMoves; |
872 |
|
829 | const CounterMoveStats* fmh = (ss-2)->counterMoves; |
873 | const CounterMoveStats |
830 | const CounterMoveStats* fmh2 = (ss-4)->counterMoves; |
874 | 831 | ||
875 | MovePicker mp(pos, ttMove, depth, |
832 | MovePicker mp(pos, ttMove, depth, ss); |
876 | CheckInfo ci(pos); |
- | |
877 | value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc |
833 | value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc |
878 | improving = ss->staticEval >= (ss-2)->staticEval |
834 | improving = ss->staticEval >= (ss-2)->staticEval |
879 |
|
835 | /* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */ |
880 | ||(ss-2)->staticEval == VALUE_NONE; |
836 | ||(ss-2)->staticEval == VALUE_NONE; |
881 | 837 | ||
882 | singularExtensionNode = !rootNode |
838 | singularExtensionNode = !rootNode |
883 | && depth >= 8 * ONE_PLY |
839 | && depth >= 8 * ONE_PLY |
884 | && ttMove != MOVE_NONE |
840 | && ttMove != MOVE_NONE |
885 | /* && ttValue != VALUE_NONE Already implicit in the next condition */ |
- | |
886 | && |
841 | && ttValue != VALUE_NONE |
887 | && !excludedMove // Recursive singular search is not allowed |
842 | && !excludedMove // Recursive singular search is not allowed |
888 | && (tte->bound() & BOUND_LOWER) |
843 | && (tte->bound() & BOUND_LOWER) |
889 | && tte->depth() >= depth - 3 * ONE_PLY; |
844 | && tte->depth() >= depth - 3 * ONE_PLY; |
890 | 845 | ||
891 | // Step 11. Loop through moves |
846 | // Step 11. Loop through moves |
Line 914... | Line 869... | ||
914 | if (PvNode) |
869 | if (PvNode) |
915 | (ss+1)->pv = nullptr; |
870 | (ss+1)->pv = nullptr; |
916 | 871 | ||
917 | extension = DEPTH_ZERO; |
872 | extension = DEPTH_ZERO; |
918 | captureOrPromotion = pos.capture_or_promotion(move); |
873 | captureOrPromotion = pos.capture_or_promotion(move); |
- | 874 | moved_piece = pos.moved_piece(move); |
|
919 | 875 | ||
920 | givesCheck = type_of(move) == NORMAL && ! |
876 | givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates() |
921 | ? |
877 | ? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move) |
922 | : pos.gives_check( |
878 | : pos.gives_check(move); |
- | 879 | ||
- | 880 | moveCountPruning = depth < 16 * ONE_PLY |
|
- | 881 | && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; |
|
923 | 882 | ||
924 | // Step 12. Extend checks |
883 | // Step 12. Extend checks |
- | 884 | if ( givesCheck |
|
- | 885 | && !moveCountPruning |
|
925 |
|
886 | && pos.see_ge(move, VALUE_ZERO)) |
926 | extension = ONE_PLY; |
887 | extension = ONE_PLY; |
927 | 888 | ||
928 | // Singular extension search. If all moves but one fail low on a search of |
889 | // Singular extension search. If all moves but one fail low on a search of |
929 | // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move |
890 | // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move |
930 | // is singular and should be extended. To verify this we do a reduced search |
891 | // is singular and should be extended. To verify this we do a reduced search |
931 | // on all the other moves but the ttMove and if the result is lower than |
892 | // on all the other moves but the ttMove and if the result is lower than |
932 | // ttValue minus a margin then we extend the ttMove. |
893 | // ttValue minus a margin then we extend the ttMove. |
933 | if ( singularExtensionNode |
894 | if ( singularExtensionNode |
934 | && move == ttMove |
895 | && move == ttMove |
935 | && !extension |
896 | && !extension |
936 | && pos.legal( |
897 | && pos.legal(move)) |
937 | { |
898 | { |
938 | Value rBeta = ttValue - 2 * depth / |
899 | Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); |
- | 900 | Depth d = (depth / (2 * ONE_PLY)) * ONE_PLY; |
|
939 | ss->excludedMove = move; |
901 | ss->excludedMove = move; |
940 | ss->skipEarlyPruning = true; |
902 | ss->skipEarlyPruning = true; |
941 | value = search<NonPV>(pos, ss, rBeta - 1, rBeta, |
903 | value = search<NonPV>(pos, ss, rBeta - 1, rBeta, d, cutNode); |
942 | ss->skipEarlyPruning = false; |
904 | ss->skipEarlyPruning = false; |
943 | ss->excludedMove = MOVE_NONE; |
905 | ss->excludedMove = MOVE_NONE; |
944 | 906 | ||
945 | if (value < rBeta) |
907 | if (value < rBeta) |
946 | extension = ONE_PLY; |
908 | extension = ONE_PLY; |
Line 948... | Line 910... | ||
948 | 910 | ||
949 | // Update the current move (this must be done after singular extension search) |
911 | // Update the current move (this must be done after singular extension search) |
950 | newDepth = depth - ONE_PLY + extension; |
912 | newDepth = depth - ONE_PLY + extension; |
951 | 913 | ||
952 | // Step 13. Pruning at shallow depth |
914 | // Step 13. Pruning at shallow depth |
953 | if ( |
915 | if ( !rootNode |
954 | && !captureOrPromotion |
- | |
955 | && !inCheck |
- | |
956 | && !givesCheck |
- | |
957 | && !pos.advanced_pawn_push(move) |
- | |
958 | && |
916 | && bestValue > VALUE_MATED_IN_MAX_PLY) |
959 | { |
917 | { |
960 |
|
918 | if ( !captureOrPromotion |
961 |
|
919 | && !givesCheck |
- | 920 | && !pos.advanced_pawn_push(move)) |
|
- | 921 | { |
|
962 |
|
922 | // Move count based pruning |
- | 923 | if (moveCountPruning) |
|
963 | continue; |
924 | continue; |
964 | 925 | ||
965 | // History based pruning |
- | |
966 |
|
926 | // Reduced depth of the next LMR search |
967 | && move != ss->killers[0] |
- | |
968 |
|
927 | int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY; |
969 | && cmh[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO) |
- | |
970 | continue; |
- | |
971 | 928 | ||
- | 929 | // Countermoves based pruning |
|
- | 930 | if ( lmrDepth < 3 |
|
- | 931 | && (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO) |
|
972 |
|
932 | && (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO) |
- | 933 | && (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh))) |
|
- | 934 | continue; |
|
973 | 935 | ||
974 | // Futility pruning: parent node |
936 | // Futility pruning: parent node |
975 |
|
937 | if ( lmrDepth < 7 |
976 |
|
938 | && !inCheck |
977 |
|
939 | && ss->staticEval + 256 + 200 * lmrDepth <= alpha) |
- | 940 | continue; |
|
978 | 941 | ||
979 |
|
942 | // Prune moves with negative SEE |
980 | |
943 | if ( lmrDepth < 8 |
981 |
|
944 | && !pos.see_ge(move, Value(-35 * lmrDepth * lmrDepth))) |
982 | continue; |
945 | continue; |
983 | } |
- | |
984 | } |
946 | } |
985 | - | ||
986 |
|
947 | else if ( depth < 7 * ONE_PLY |
- | 948 | && !extension |
|
987 |
|
949 | && !pos.see_ge(move, Value(-35 * depth / ONE_PLY * depth / ONE_PLY))) |
988 | continue; |
950 | continue; |
989 | } |
951 | } |
990 | 952 | ||
991 | // Speculative prefetch as early as possible |
953 | // Speculative prefetch as early as possible |
992 | prefetch(TT.first_entry(pos.key_after(move))); |
954 | prefetch(TT.first_entry(pos.key_after(move))); |
993 | 955 | ||
994 | // Check for legality just before making the move |
956 | // Check for legality just before making the move |
995 | if (!rootNode && !pos.legal( |
957 | if (!rootNode && !pos.legal(move)) |
996 | { |
958 | { |
997 | ss->moveCount = --moveCount; |
959 | ss->moveCount = --moveCount; |
998 | continue; |
960 | continue; |
999 | } |
961 | } |
1000 | 962 | ||
1001 | ss->currentMove = move; |
963 | ss->currentMove = move; |
- | 964 | ss->counterMoves = &thisThread->counterMoveHistory[moved_piece][to_sq(move)]; |
|
1002 | 965 | ||
1003 | // Step 14. Make the move |
966 | // Step 14. Make the move |
1004 | pos.do_move(move, st, givesCheck); |
967 | pos.do_move(move, st, givesCheck); |
1005 | 968 | ||
1006 | // Step 15. Reduced depth search (LMR). If the move fails high it will be |
969 | // Step 15. Reduced depth search (LMR). If the move fails high it will be |
1007 | // re-searched at full depth. |
970 | // re-searched at full depth. |
1008 | if ( depth >= 3 * ONE_PLY |
971 | if ( depth >= 3 * ONE_PLY |
1009 | && moveCount > 1 |
972 | && moveCount > 1 |
1010 | && !captureOrPromotion) |
973 | && (!captureOrPromotion || moveCountPruning)) |
1011 | { |
974 | { |
1012 | Depth r = reduction<PvNode>(improving, depth, moveCount); |
975 | Depth r = reduction<PvNode>(improving, depth, moveCount); |
1013 | 976 | ||
1014 |
|
977 | if (captureOrPromotion) |
1015 |
|
978 | r -= r ? ONE_PLY : DEPTH_ZERO; |
- | 979 | else |
|
- | 980 | { |
|
1016 |
|
981 | // Increase reduction for cut nodes |
1017 |
|
982 | if (cutNode) |
1018 | r += ONE_PLY; |
983 | r += 2 * ONE_PLY; |
1019 | 984 | ||
1020 | // Decrease |
985 | // Decrease reduction for moves that escape a capture. Filter out |
- | 986 | // castling moves, because they are coded as "king captures rook" and |
|
- | 987 | // hence break make_move(). Also use see() instead of see_sign(), |
|
- | 988 | // because the destination square is empty. |
|
- | 989 | else if ( type_of(move) == NORMAL |
|
1021 |
|
990 | && type_of(pos.piece_on(to_sq(move))) != PAWN |
1022 |
|
991 | && !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO)) |
1023 |
|
992 | r -= 2 * ONE_PLY; |
1024 | 993 | ||
1025 |
|
994 | ss->history = thisThread->history[moved_piece][to_sq(move)] |
1026 |
|
995 | + (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO) |
1027 |
|
996 | + (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO) |
- | 997 | + (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO) |
|
- | 998 | + thisThread->fromTo.get(~pos.side_to_move(), move) |
|
1028 |
|
999 | - 8000; // Correction factor |
- | 1000 | ||
- | 1001 | // Decrease/increase reduction by comparing opponent's stat score |
|
- | 1002 | if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO) |
|
1029 |
|
1003 | r -= ONE_PLY; |
- | 1004 | ||
1030 | && |
1005 | else if (ss->history < VALUE_ZERO && (ss-1)->history > VALUE_ZERO) |
1031 |
|
1006 | r += ONE_PLY; |
- | 1007 | ||
1032 |
|
1008 | // Decrease/increase reduction for moves with a good/bad history |
1033 | r = std::max(DEPTH_ZERO, r - ONE_PLY); |
1009 | r = std::max(DEPTH_ZERO, (r / ONE_PLY - ss->history / 20000) * ONE_PLY); |
- | 1010 | } |
|
1034 | 1011 | ||
1035 | Depth d = std::max(newDepth - r, ONE_PLY); |
1012 | Depth d = std::max(newDepth - r, ONE_PLY); |
1036 | 1013 | ||
1037 | value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true); |
1014 | value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true); |
1038 | 1015 | ||
1039 | doFullDepthSearch = (value > alpha && |
1016 | doFullDepthSearch = (value > alpha && d != newDepth); |
1040 | } |
1017 | } |
1041 | else |
1018 | else |
1042 | doFullDepthSearch = !PvNode || moveCount > 1; |
1019 | doFullDepthSearch = !PvNode || moveCount > 1; |
1043 | 1020 | ||
1044 | // Step 16. Full depth search when LMR is skipped or fails high |
1021 | // Step 16. Full depth search when LMR is skipped or fails high |
Line 1145... | Line 1122... | ||
1145 | 1122 | ||
1146 | // Step 20. Check for mate and stalemate |
1123 | // Step 20. Check for mate and stalemate |
1147 | // All legal moves have been searched and if there are no legal moves, it |
1124 | // All legal moves have been searched and if there are no legal moves, it |
1148 | // must be a mate or a stalemate. If we are in a singular extension search then |
1125 | // must be a mate or a stalemate. If we are in a singular extension search then |
1149 | // return a fail low score. |
1126 | // return a fail low score. |
- | 1127 | ||
- | 1128 | assert(moveCount || !inCheck || excludedMove || !MoveList<LEGAL>(pos).size()); |
|
- | 1129 | ||
1150 | if (!moveCount) |
1130 | if (!moveCount) |
1151 | bestValue = excludedMove ? alpha |
1131 | bestValue = excludedMove ? alpha |
1152 | : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; |
1132 | : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; |
- | 1133 | else if (bestMove) |
|
- | 1134 | { |
|
- | 1135 | int d = depth / ONE_PLY; |
|
1153 | 1136 | ||
1154 | // Quiet best move: update killers, history and countermoves |
1137 | // Quiet best move: update killers, history and countermoves |
1155 |
|
1138 | if (!pos.capture_or_promotion(bestMove)) |
- | 1139 | { |
|
- | 1140 | Value bonus = Value(d * d + 2 * d - 2); |
|
1156 | update_stats(pos, ss, bestMove, |
1141 | update_stats(pos, ss, bestMove, quietsSearched, quietCount, bonus); |
- | 1142 | } |
|
1157 | 1143 | ||
- | 1144 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
|
- | 1145 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
|
- | 1146 | { |
|
- | 1147 | Value penalty = Value(d * d + 4 * d + 1); |
|
- | 1148 | Square prevSq = to_sq((ss-1)->currentMove); |
|
- | 1149 | update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -penalty); |
|
- | 1150 | } |
|
- | 1151 | } |
|
1158 | // Bonus for prior countermove that caused the fail low |
1152 | // Bonus for prior countermove that caused the fail low |
1159 | else if ( depth >= 3 * ONE_PLY |
1153 | else if ( depth >= 3 * ONE_PLY |
1160 | && !bestMove |
- | |
1161 | && !inCheck |
- | |
1162 | && !pos. |
1154 | && !pos.captured_piece() |
1163 | && is_ok((ss - 1)->currentMove) |
- | |
1164 | && is_ok((ss |
1155 | && is_ok((ss-1)->currentMove)) |
1165 | { |
1156 | { |
- | 1157 | int d = depth / ONE_PLY; |
|
1166 | Value bonus = Value( |
1158 | Value bonus = Value(d * d + 2 * d - 2); |
1167 | Square |
1159 | Square prevSq = to_sq((ss-1)->currentMove); |
1168 | CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq]; |
- | |
1169 |
|
1160 | update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, bonus); |
1170 | } |
1161 | } |
1171 | 1162 | ||
1172 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
1163 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
1173 | bestValue >= beta ? BOUND_LOWER : |
1164 | bestValue >= beta ? BOUND_LOWER : |
1174 | PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, |
1165 | PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, |
Line 1191... | Line 1182... | ||
1191 | 1182 | ||
1192 | assert(InCheck == !!pos.checkers()); |
1183 | assert(InCheck == !!pos.checkers()); |
1193 | assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); |
1184 | assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); |
1194 | assert(PvNode || (alpha == beta - 1)); |
1185 | assert(PvNode || (alpha == beta - 1)); |
1195 | assert(depth <= DEPTH_ZERO); |
1186 | assert(depth <= DEPTH_ZERO); |
- | 1187 | assert(depth / ONE_PLY * ONE_PLY == depth); |
|
1196 | 1188 | ||
1197 | Move pv[MAX_PLY+1]; |
1189 | Move pv[MAX_PLY+1]; |
1198 | StateInfo st; |
1190 | StateInfo st; |
1199 | TTEntry* tte; |
1191 | TTEntry* tte; |
1200 | Key posKey; |
1192 | Key posKey; |
Line 1236... | Line 1228... | ||
1236 | && ttHit |
1228 | && ttHit |
1237 | && tte->depth() >= ttDepth |
1229 | && tte->depth() >= ttDepth |
1238 | && ttValue != VALUE_NONE // Only in case of TT access race |
1230 | && ttValue != VALUE_NONE // Only in case of TT access race |
1239 | && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) |
1231 | && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) |
1240 | : (tte->bound() & BOUND_UPPER))) |
1232 | : (tte->bound() & BOUND_UPPER))) |
1241 | { |
- | |
1242 | ss->currentMove = ttMove; // Can be MOVE_NONE |
- | |
1243 | return ttValue; |
1233 | return ttValue; |
1244 | } |
- | |
1245 | 1234 | ||
1246 | // Evaluate the position statically |
1235 | // Evaluate the position statically |
1247 | if (InCheck) |
1236 | if (InCheck) |
1248 | { |
1237 | { |
1249 | ss->staticEval = VALUE_NONE; |
1238 | ss->staticEval = VALUE_NONE; |
Line 1285... | Line 1274... | ||
1285 | 1274 | ||
1286 | // Initialize a MovePicker object for the current position, and prepare |
1275 | // Initialize a MovePicker object for the current position, and prepare |
1287 | // to search the moves. Because the depth is <= 0 here, only captures, |
1276 | // to search the moves. Because the depth is <= 0 here, only captures, |
1288 | // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will |
1277 | // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will |
1289 | // be generated. |
1278 | // be generated. |
1290 | MovePicker mp(pos, ttMove, depth, |
1279 | MovePicker mp(pos, ttMove, depth, to_sq((ss-1)->currentMove)); |
1291 | CheckInfo ci(pos); |
- | |
1292 | 1280 | ||
1293 | // Loop through the moves until no moves remain or a beta cutoff occurs |
1281 | // Loop through the moves until no moves remain or a beta cutoff occurs |
1294 | while ((move = mp.next_move()) != MOVE_NONE) |
1282 | while ((move = mp.next_move()) != MOVE_NONE) |
1295 | { |
1283 | { |
1296 | assert(is_ok(move)); |
1284 | assert(is_ok(move)); |
1297 | 1285 | ||
1298 | givesCheck = type_of(move) == NORMAL && ! |
1286 | givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates() |
1299 | ? |
1287 | ? pos.check_squares(type_of(pos.piece_on(from_sq(move)))) & to_sq(move) |
1300 | : pos.gives_check( |
1288 | : pos.gives_check(move); |
1301 | 1289 | ||
1302 | // Futility pruning |
1290 | // Futility pruning |
1303 | if ( !InCheck |
1291 | if ( !InCheck |
1304 | && !givesCheck |
1292 | && !givesCheck |
1305 | && futilityBase > -VALUE_KNOWN_WIN |
1293 | && futilityBase > -VALUE_KNOWN_WIN |
Line 1313... | Line 1301... | ||
1313 | { |
1301 | { |
1314 | bestValue = std::max(bestValue, futilityValue); |
1302 | bestValue = std::max(bestValue, futilityValue); |
1315 | continue; |
1303 | continue; |
1316 | } |
1304 | } |
1317 | 1305 | ||
1318 | if (futilityBase <= alpha && pos. |
1306 | if (futilityBase <= alpha && !pos.see_ge(move, VALUE_ZERO + 1)) |
1319 | { |
1307 | { |
1320 | bestValue = std::max(bestValue, futilityBase); |
1308 | bestValue = std::max(bestValue, futilityBase); |
1321 | continue; |
1309 | continue; |
1322 | } |
1310 | } |
1323 | } |
1311 | } |
Line 1328... | Line 1316... | ||
1328 | && !pos.capture(move); |
1316 | && !pos.capture(move); |
1329 | 1317 | ||
1330 | // Don't search moves with negative SEE values |
1318 | // Don't search moves with negative SEE values |
1331 | if ( (!InCheck || evasionPrunable) |
1319 | if ( (!InCheck || evasionPrunable) |
1332 | && type_of(move) != PROMOTION |
1320 | && type_of(move) != PROMOTION |
1333 | && |
1321 | && !pos.see_ge(move, VALUE_ZERO)) |
1334 | continue; |
1322 | continue; |
1335 | 1323 | ||
1336 | // Speculative prefetch as early as possible |
1324 | // Speculative prefetch as early as possible |
1337 | prefetch(TT.first_entry(pos.key_after(move))); |
1325 | prefetch(TT.first_entry(pos.key_after(move))); |
1338 | 1326 | ||
1339 | // Check for legality just before making the move |
1327 | // Check for legality just before making the move |
1340 | if (!pos.legal( |
1328 | if (!pos.legal(move)) |
1341 | continue; |
1329 | continue; |
1342 | 1330 | ||
1343 | ss->currentMove = move; |
1331 | ss->currentMove = move; |
1344 | 1332 | ||
1345 | // Make and search the move |
1333 | // Make and search the move |
Line 1424... | Line 1412... | ||
1424 | *pv++ = *childPv++; |
1412 | *pv++ = *childPv++; |
1425 | *pv = MOVE_NONE; |
1413 | *pv = MOVE_NONE; |
1426 | } |
1414 | } |
1427 | 1415 | ||
1428 | 1416 | ||
- | 1417 | // update_cm_stats() updates countermove and follow-up move history |
|
- | 1418 | ||
- | 1419 | void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) { |
|
- | 1420 | ||
- | 1421 | CounterMoveStats* cmh = (ss-1)->counterMoves; |
|
- | 1422 | CounterMoveStats* fmh1 = (ss-2)->counterMoves; |
|
- | 1423 | CounterMoveStats* fmh2 = (ss-4)->counterMoves; |
|
- | 1424 | ||
- | 1425 | if (cmh) |
|
- | 1426 | cmh->update(pc, s, bonus); |
|
- | 1427 | ||
- | 1428 | if (fmh1) |
|
- | 1429 | fmh1->update(pc, s, bonus); |
|
- | 1430 | ||
- | 1431 | if (fmh2) |
|
- | 1432 | fmh2->update(pc, s, bonus); |
|
- | 1433 | } |
|
- | 1434 | ||
- | 1435 | ||
1429 | // update_stats() updates killers, history, countermove and countermove |
1436 | // update_stats() updates killers, history, countermove and countermove plus |
1430 | // history when a new quiet best move is found. |
1437 | // follow-up move history when a new quiet best move is found. |
1431 | 1438 | ||
1432 | void update_stats(const Position& pos, Stack* ss, Move move, |
1439 | void update_stats(const Position& pos, Stack* ss, Move move, |
1433 |
|
1440 | Move* quiets, int quietsCnt, Value bonus) { |
1434 | 1441 | ||
1435 | if (ss->killers[0] != move) |
1442 | if (ss->killers[0] != move) |
1436 | { |
1443 | { |
1437 | ss->killers[1] = ss->killers[0]; |
1444 | ss->killers[1] = ss->killers[0]; |
1438 | ss->killers[0] = move; |
1445 | ss->killers[0] = move; |
1439 | } |
1446 | } |
1440 | 1447 | ||
1441 | Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1); |
- | |
1442 | - | ||
1443 |
|
1448 | Color c = pos.side_to_move(); |
1444 | CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq]; |
- | |
1445 | Thread* thisThread = pos.this_thread(); |
1449 | Thread* thisThread = pos.this_thread(); |
1446 | - | ||
- | 1450 | thisThread->fromTo.update(c, move, bonus); |
|
1447 | thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus); |
1451 | thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus); |
- | 1452 | update_cm_stats(ss, pos.moved_piece(move), to_sq(move), bonus); |
|
1448 | 1453 | ||
1449 | if |
1454 | if ((ss-1)->counterMoves) |
1450 | { |
1455 | { |
- | 1456 | Square prevSq = to_sq((ss-1)->currentMove); |
|
1451 | thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move); |
1457 | thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move); |
1452 | cmh.update(pos.moved_piece(move), to_sq(move), bonus); |
- | |
1453 | } |
1458 | } |
1454 | 1459 | ||
1455 | // Decrease all the other played quiet moves |
1460 | // Decrease all the other played quiet moves |
1456 | for (int i = 0; i < quietsCnt; ++i) |
1461 | for (int i = 0; i < quietsCnt; ++i) |
1457 | { |
1462 | { |
- | 1463 | thisThread->fromTo.update(c, quiets[i], -bonus); |
|
1458 | thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); |
1464 | thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); |
1459 | - | ||
1460 | if (is_ok((ss-1)->currentMove)) |
- | |
1461 |
|
1465 | update_cm_stats(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); |
1462 | } |
- | |
1463 | - | ||
1464 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
- | |
1465 | if ( (ss-1)->moveCount == 1 |
- | |
1466 | && !pos.captured_piece_type() |
- | |
1467 | && is_ok((ss-2)->currentMove)) |
- | |
1468 | { |
- | |
1469 | Square prevPrevSq = to_sq((ss-2)->currentMove); |
- | |
1470 | CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq]; |
- | |
1471 | prevCmh.update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY); |
- | |
1472 | } |
1466 | } |
1473 | } |
1467 | } |
1474 | 1468 | ||
1475 | 1469 | ||
1476 | // When playing with strength handicap, choose best move among a set of RootMoves |
1470 | // When playing with strength handicap, choose best move among a set of RootMoves |
1477 | // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. |
1471 | // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. |
1478 | 1472 | ||
1479 | Move Skill::pick_best(size_t multiPV) { |
1473 | Move Skill::pick_best(size_t multiPV) { |
1480 | 1474 | ||
1481 | const |
1475 | const RootMoves& rootMoves = Threads.main()->rootMoves; |
1482 | static PRNG rng(now()); // PRNG sequence should be non-deterministic |
1476 | static PRNG rng(now()); // PRNG sequence should be non-deterministic |
1483 | 1477 | ||
1484 | // RootMoves are already sorted by score in descending order |
1478 | // RootMoves are already sorted by score in descending order |
1485 | Value topScore = rootMoves[0].score; |
1479 | Value topScore = rootMoves[0].score; |
1486 | int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg); |
1480 | int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg); |
Line 1527... | Line 1521... | ||
1527 | if (Limits.ponder) |
1521 | if (Limits.ponder) |
1528 | return; |
1522 | return; |
1529 | 1523 | ||
1530 | if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10) |
1524 | if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10) |
1531 | || (Limits.movetime && elapsed >= Limits.movetime) |
1525 | || (Limits.movetime && elapsed >= Limits.movetime) |
1532 | || (Limits.nodes && Threads.nodes_searched() >= Limits.nodes)) |
1526 | || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes)) |
1533 | Signals.stop = true; |
1527 | Signals.stop = true; |
1534 | } |
1528 | } |
1535 | 1529 | ||
1536 | } // namespace |
1530 | } // namespace |
1537 | 1531 | ||
Line 1541... | Line 1535... | ||
1541 | 1535 | ||
1542 | string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { |
1536 | string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { |
1543 | 1537 | ||
1544 | std::stringstream ss; |
1538 | std::stringstream ss; |
1545 | int elapsed = Time.elapsed() + 1; |
1539 | int elapsed = Time.elapsed() + 1; |
1546 | const |
1540 | const RootMoves& rootMoves = pos.this_thread()->rootMoves; |
1547 | size_t PVIdx = pos.this_thread()->PVIdx; |
1541 | size_t PVIdx = pos.this_thread()->PVIdx; |
1548 | size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size()); |
1542 | size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size()); |
1549 | uint64_t |
1543 | uint64_t nodesSearched = Threads.nodes_searched(); |
- | 1544 | uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0); |
|
1550 | 1545 | ||
1551 | for (size_t i = 0; i < multiPV; ++i) |
1546 | for (size_t i = 0; i < multiPV; ++i) |
1552 | { |
1547 | { |
1553 | bool updated = (i <= PVIdx); |
1548 | bool updated = (i <= PVIdx); |
1554 | 1549 | ||
Line 1571... | Line 1566... | ||
1571 | << " score " << UCI::value(v); |
1566 | << " score " << UCI::value(v); |
1572 | 1567 | ||
1573 | if (!tb && i == PVIdx) |
1568 | if (!tb && i == PVIdx) |
1574 | ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); |
1569 | ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); |
1575 | 1570 | ||
1576 | ss << " nodes " << |
1571 | ss << " nodes " << nodesSearched |
1577 | << " nps " << |
1572 | << " nps " << nodesSearched * 1000 / elapsed; |
1578 | 1573 | ||
1579 | if (elapsed > 1000) // Earlier makes little sense |
1574 | if (elapsed > 1000) // Earlier makes little sense |
1580 | ss << " hashfull " << TT.hashfull(); |
1575 | ss << " hashfull " << TT.hashfull(); |
1581 | 1576 | ||
1582 | ss << " tbhits " << |
1577 | ss << " tbhits " << tbHits |
1583 | << " time " << elapsed |
1578 | << " time " << elapsed |
1584 | << " pv"; |
1579 | << " pv"; |
1585 | 1580 | ||
1586 | for (Move m : rootMoves[i].pv) |
1581 | for (Move m : rootMoves[i].pv) |
1587 | ss << " " << UCI::move(m, pos.is_chess960()); |
1582 | ss << " " << UCI::move(m, pos.is_chess960()); |
1588 | } |
1583 | } |
1589 | 1584 | ||
1590 | return ss.str(); |
1585 | return ss.str(); |
1591 | } |
- | |
1592 | - | ||
1593 | - | ||
1594 | /// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and |
- | |
1595 | /// inserts the PV back into the TT. This makes sure the old PV moves are searched |
- | |
1596 | /// first, even if the old TT entries have been overwritten. |
- | |
1597 | - | ||
1598 | void RootMove::insert_pv_in_tt(Position& pos) { |
- | |
1599 | - | ||
1600 | StateInfo state[MAX_PLY], *st = state; |
- | |
1601 | bool ttHit; |
- | |
1602 | - | ||
1603 | for (Move m : pv) |
- | |
1604 | { |
- | |
1605 | assert(MoveList<LEGAL>(pos).contains(m)); |
- | |
1606 | - | ||
1607 | TTEntry* tte = TT.probe(pos.key(), ttHit); |
- | |
1608 | - | ||
1609 | if (!ttHit || tte->move() != m) // Don't overwrite correct entries |
- | |
1610 | tte->save(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, |
- | |
1611 | m, VALUE_NONE, TT.generation()); |
- | |
1612 | - | ||
1613 | pos.do_move(m, *st++, pos.gives_check(m, CheckInfo(pos))); |
- | |
1614 | } |
- | |
1615 | - | ||
1616 | for (size_t i = pv.size(); i > 0; ) |
- | |
1617 | pos.undo_move(pv[--i]); |
- | |
1618 | } |
1586 | } |
1619 | 1587 | ||
1620 | 1588 | ||
1621 | /// RootMove::extract_ponder_from_tt() is called in case we have no ponder move |
1589 | /// RootMove::extract_ponder_from_tt() is called in case we have no ponder move |
1622 | /// before exiting the search, for instance, in case we stop the search during a |
1590 | /// before exiting the search, for instance, in case we stop the search during a |
1623 | /// fail high at root. We try hard to have a ponder move to return to the GUI, |
1591 | /// fail high at root. We try hard to have a ponder move to return to the GUI, |
1624 | /// otherwise in case of 'ponder on' we have nothing to think on. |
1592 | /// otherwise in case of 'ponder on' we have nothing to think on. |
1625 | 1593 | ||
1626 | bool RootMove::extract_ponder_from_tt(Position& pos) |
1594 | bool RootMove::extract_ponder_from_tt(Position& pos) { |
1627 | { |
1595 | |
1628 | StateInfo st; |
1596 | StateInfo st; |
1629 | bool ttHit; |
1597 | bool ttHit; |
1630 | 1598 | ||
1631 | assert(pv.size() == 1); |
1599 | assert(pv.size() == 1); |
1632 | 1600 | ||
- | 1601 | if (!pv[0]) |
|
- | 1602 | return false; |
|
- | 1603 | ||
1633 | pos.do_move(pv[0], st, pos.gives_check(pv[0] |
1604 | pos.do_move(pv[0], st, pos.gives_check(pv[0])); |
1634 | TTEntry* tte = TT.probe(pos.key(), ttHit); |
1605 | TTEntry* tte = TT.probe(pos.key(), ttHit); |
1635 | pos.undo_move(pv[0]); |
- | |
1636 | 1606 | ||
1637 | if (ttHit) |
1607 | if (ttHit) |
1638 | { |
1608 | { |
1639 | Move m = tte->move(); // Local copy to be SMP safe |
1609 | Move m = tte->move(); // Local copy to be SMP safe |
1640 | if (MoveList<LEGAL>(pos).contains(m)) |
1610 | if (MoveList<LEGAL>(pos).contains(m)) |
1641 |
|
1611 | pv.push_back(m); |
- | 1612 | } |
|
- | 1613 | ||
- | 1614 | pos.undo_move(pv[0]); |
|
- | 1615 | return pv.size() > 1; |
|
- | 1616 | } |
|
- | 1617 | ||
- | 1618 | void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) { |
|
- | 1619 | ||
- | 1620 | RootInTB = false; |
|
- | 1621 | UseRule50 = Options["Syzygy50MoveRule"]; |
|
- | 1622 | ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY; |
|
- | 1623 | Cardinality = Options["SyzygyProbeLimit"]; |
|
- | 1624 | ||
- | 1625 | // Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality |
|
- | 1626 | if (Cardinality > MaxCardinality) |
|
- | 1627 | { |
|
- | 1628 | Cardinality = MaxCardinality; |
|
- | 1629 | ProbeDepth = DEPTH_ZERO; |
|
- | 1630 | } |
|
- | 1631 | ||
- | 1632 | if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING)) |
|
- | 1633 | return; |
|
- | 1634 | ||
- | 1635 | // If the current root position is in the tablebases, then RootMoves |
|
- | 1636 | // contains only moves that preserve the draw or the win. |
|
- | 1637 | RootInTB = root_probe(pos, rootMoves, TB::Score); |
|
- | 1638 | ||
- | 1639 | if (RootInTB) |
|
- | 1640 | Cardinality = 0; // Do not probe tablebases during the search |
|
- | 1641 | ||
- | 1642 | else // If DTZ tables are missing, use WDL tables as a fallback |
|
- | 1643 | { |
|
- | 1644 | // Filter out moves that do not preserve the draw or the win. |
|
- | 1645 | RootInTB = root_probe_wdl(pos, rootMoves, TB::Score); |
|
- | 1646 | ||
- | 1647 | // Only probe during search if winning |
|
- | 1648 | if (RootInTB && TB::Score <= VALUE_DRAW) |
|
- | 1649 | Cardinality = 0; |
|
1642 | } |
1650 | } |
1643 | 1651 | ||
1644 |
|
1652 | if (RootInTB && !UseRule50) |
- | 1653 | TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1 |
|
- | 1654 | : TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1 |
|
- | 1655 | : VALUE_DRAW; |
|
1645 | } |
1656 | } |