Rev 169 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 169 | Rev 185 | ||
---|---|---|---|
Line 4... | Line 4... | ||
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
4 | Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad |
5 | Copyright (C) 2015- |
5 | Copyright (C) 2015-2019 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad |
6 | 6 | ||
7 | Stockfish is free software: you can redistribute it and/or modify |
7 | Stockfish is free software: you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation, either version 3 of the License, or |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. |
10 | (at your option) any later version. |
Line 29... | Line 29... | ||
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 "position.h" |
33 | #include "search.h" |
33 | #include "search.h" |
34 | #include "timeman.h" |
- | |
35 | #include "thread.h" |
34 | #include "thread.h" |
- | 35 | #include "timeman.h" |
|
36 | #include "tt.h" |
36 | #include "tt.h" |
37 | #include "uci.h" |
37 | #include "uci.h" |
38 | #include "syzygy/tbprobe.h" |
38 | #include "syzygy/tbprobe.h" |
39 | 39 | ||
40 | namespace Search { |
40 | namespace Search { |
Line 46... | Line 46... | ||
46 | 46 | ||
47 | int Cardinality; |
47 | int Cardinality; |
48 | bool RootInTB; |
48 | bool RootInTB; |
49 | bool UseRule50; |
49 | bool UseRule50; |
50 | Depth ProbeDepth; |
50 | Depth ProbeDepth; |
51 | Value Score; |
- | |
52 | } |
51 | } |
53 | 52 | ||
54 | namespace TB = Tablebases; |
53 | namespace TB = Tablebases; |
55 | 54 | ||
56 | using std::string; |
55 | using std::string; |
Line 61... | Line 60... | ||
61 | 60 | ||
62 | // Different node types, used as a template parameter |
61 | // Different node types, used as a template parameter |
63 | enum NodeType { NonPV, PV }; |
62 | enum NodeType { NonPV, PV }; |
64 | 63 | ||
65 | // Sizes and phases of the skip-blocks, used for distributing search depths across the threads |
64 | // Sizes and phases of the skip-blocks, used for distributing search depths across the threads |
66 |
|
65 | constexpr int SkipSize[] = { 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; |
67 |
|
66 | constexpr int SkipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 }; |
68 | 67 | ||
69 | // |
68 | // Razor and futility margins |
70 |
|
69 | constexpr int RazorMargin = 600; |
71 | Value futility_margin(Depth |
70 | Value futility_margin(Depth d, bool improving) { |
- | 71 | return Value((175 - 50 * improving) * d / ONE_PLY); |
|
- | 72 | } |
|
72 | 73 | ||
73 | // Futility and reductions lookup tables, initialized at startup |
74 | // Futility and reductions lookup tables, initialized at startup |
74 | int FutilityMoveCounts[2][16]; // [improving][depth] |
75 | int FutilityMoveCounts[2][16]; // [improving][depth] |
75 | int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber] |
76 | int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber] |
76 | 77 | ||
Line 79... | Line 80... | ||
79 | } |
80 | } |
80 | 81 | ||
81 | // History and stats update bonus, based on depth |
82 | // History and stats update bonus, based on depth |
82 | int stat_bonus(Depth depth) { |
83 | int stat_bonus(Depth depth) { |
83 | int d = depth / ONE_PLY; |
84 | int d = depth / ONE_PLY; |
84 | return d > 17 ? 0 : d * d + |
85 | return d > 17 ? 0 : 29 * d * d + 138 * d - 134; |
- | 86 | } |
|
- | 87 | ||
- | 88 | // Add a small random component to draw evaluations to keep search dynamic |
|
- | 89 | // and to avoid 3fold-blindness. |
|
- | 90 | Value value_draw(Depth depth, Thread* thisThread) { |
|
- | 91 | return depth < 4 ? VALUE_DRAW |
|
- | 92 | : VALUE_DRAW + Value(2 * (thisThread->nodes.load(std::memory_order_relaxed) % 2) - 1); |
|
85 | } |
93 | } |
86 | 94 | ||
87 | // Skill structure is used to implement strength limit |
95 | // Skill structure is used to implement strength limit |
88 | struct Skill { |
96 | struct Skill { |
89 | explicit Skill(int l) : level(l) {} |
97 | explicit Skill(int l) : level(l) {} |
Line 94... | Line 102... | ||
94 | int level; |
102 | int level; |
95 | Move best = MOVE_NONE; |
103 | Move best = MOVE_NONE; |
96 | }; |
104 | }; |
97 | 105 | ||
98 | template <NodeType NT> |
106 | template <NodeType NT> |
99 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool |
107 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode); |
100 | 108 | ||
101 | template <NodeType |
109 | template <NodeType NT> |
102 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = DEPTH_ZERO); |
110 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = DEPTH_ZERO); |
103 | 111 | ||
104 | Value value_to_tt(Value v, int ply); |
112 | Value value_to_tt(Value v, int ply); |
105 | Value value_from_tt(Value v, int ply); |
113 | Value value_from_tt(Value v, int ply); |
106 | void update_pv(Move* pv, Move move, Move* childPv); |
114 | void update_pv(Move* pv, Move move, Move* childPv); |
107 | void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); |
115 | void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); |
108 | void |
116 | void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus); |
109 | void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus); |
117 | void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus); |
- | 118 | ||
110 | bool |
119 | inline bool gives_check(const Position& pos, Move move) { |
- | 120 | Color us = pos.side_to_move(); |
|
- | 121 | return type_of(move) == NORMAL && !(pos.blockers_for_king(~us) & pos.pieces(us)) |
|
- | 122 | ? pos.check_squares(type_of(pos.moved_piece(move))) & to_sq(move) |
|
- | 123 | : pos.gives_check(move); |
|
- | 124 | } |
|
111 | 125 | ||
112 | // perft() is our utility to verify move generation. All the leaf nodes up |
126 | // perft() is our utility to verify move generation. All the leaf nodes up |
113 | // to the given depth are generated and counted, and the sum is returned. |
127 | // to the given depth are generated and counted, and the sum is returned. |
114 | template<bool Root> |
128 | template<bool Root> |
115 | uint64_t perft(Position& pos, Depth depth) { |
129 | uint64_t perft(Position& pos, Depth depth) { |
Line 136... | Line 150... | ||
136 | } |
150 | } |
137 | 151 | ||
138 | } // namespace |
152 | } // namespace |
139 | 153 | ||
140 | 154 | ||
141 | /// Search::init() is called |
155 | /// Search::init() is called at startup to initialize various lookup tables |
142 | 156 | ||
143 | void Search::init() { |
157 | void Search::init() { |
144 | 158 | ||
145 | for (int imp = 0; imp <= 1; ++imp) |
159 | for (int imp = 0; imp <= 1; ++imp) |
146 | for (int d = 1; d < 64; ++d) |
160 | for (int d = 1; d < 64; ++d) |
Line 150... | Line 164... | ||
150 | 164 | ||
151 | Reductions[NonPV][imp][d][mc] = int(std::round(r)); |
165 | Reductions[NonPV][imp][d][mc] = int(std::round(r)); |
152 | Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0); |
166 | Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0); |
153 | 167 | ||
154 | // Increase reduction for non-PV nodes when eval is not improving |
168 | // Increase reduction for non-PV nodes when eval is not improving |
155 | if (!imp && |
169 | if (!imp && r > 1.0) |
156 | Reductions[NonPV][imp][d][mc]++; |
170 | Reductions[NonPV][imp][d][mc]++; |
157 | } |
171 | } |
158 | 172 | ||
159 | for (int d = 0; d < 16; ++d) |
173 | for (int d = 0; d < 16; ++d) |
160 | { |
174 | { |
Line 171... | Line 185... | ||
171 | Threads.main()->wait_for_search_finished(); |
185 | Threads.main()->wait_for_search_finished(); |
172 | 186 | ||
173 | Time.availableNodes = 0; |
187 | Time.availableNodes = 0; |
174 | TT.clear(); |
188 | TT.clear(); |
175 | Threads.clear(); |
189 | Threads.clear(); |
- | 190 | Tablebases::init(Options["SyzygyPath"]); // Free up mapped files |
|
176 | } |
191 | } |
177 | 192 | ||
178 | 193 | ||
179 | /// MainThread::search() is called by the main thread when the program receives |
194 | /// MainThread::search() is called by the main thread when the program receives |
180 | /// the UCI 'go' command. It searches from the root position and outputs the "bestmove". |
195 | /// the UCI 'go' command. It searches from the root position and outputs the "bestmove". |
Line 189... | Line 204... | ||
189 | } |
204 | } |
190 | 205 | ||
191 | Color us = rootPos.side_to_move(); |
206 | Color us = rootPos.side_to_move(); |
192 | Time.init(Limits, us, rootPos.game_ply()); |
207 | Time.init(Limits, us, rootPos.game_ply()); |
193 | TT.new_search(); |
208 | TT.new_search(); |
194 | - | ||
195 | int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns |
- | |
196 | - | ||
197 | Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2) |
- | |
198 | : -make_score(contempt, contempt / 2)); |
- | |
199 | 209 | ||
200 | if (rootMoves.empty()) |
210 | if (rootMoves.empty()) |
201 | { |
211 | { |
202 | rootMoves.emplace_back(MOVE_NONE); |
212 | rootMoves.emplace_back(MOVE_NONE); |
203 | sync_cout << "info depth 0 score " |
213 | sync_cout << "info depth 0 score " |
Line 242... | Line 252... | ||
242 | if ( Options["MultiPV"] == 1 |
252 | if ( Options["MultiPV"] == 1 |
243 | && !Limits.depth |
253 | && !Limits.depth |
244 | && !Skill(Options["Skill Level"]).enabled() |
254 | && !Skill(Options["Skill Level"]).enabled() |
245 | && rootMoves[0].pv[0] != MOVE_NONE) |
255 | && rootMoves[0].pv[0] != MOVE_NONE) |
246 | { |
256 | { |
- | 257 | std::map<Move, int> votes; |
|
- | 258 | Value minScore = this->rootMoves[0].score; |
|
- | 259 | ||
- | 260 | // Find out minimum score and reset votes for moves which can be voted |
|
247 | for (Thread* th |
261 | for (Thread* th: Threads) |
248 | { |
262 | { |
249 |
|
263 | minScore = std::min(minScore, th->rootMoves[0].score); |
250 |
|
264 | votes[th->rootMoves[0].pv[0]] = 0; |
- | 265 | } |
|
251 | 266 | ||
- | 267 | // Vote according to score and depth |
|
- | 268 | for (Thread* th : Threads) |
|
- | 269 | votes[th->rootMoves[0].pv[0]] += int(th->rootMoves[0].score - minScore) |
|
252 |
|
270 | + int(th->completedDepth); |
- | 271 | ||
253 |
|
272 | // Select best thread |
- | 273 | int bestVote = votes[this->rootMoves[0].pv[0]]; |
|
- | 274 | for (Thread* th : Threads) |
|
- | 275 | { |
|
- | 276 | if (votes[th->rootMoves[0].pv[0]] > bestVote) |
|
- | 277 | { |
|
254 |
|
278 | bestVote = votes[th->rootMoves[0].pv[0]]; |
255 | bestThread = th; |
279 | bestThread = th; |
- | 280 | } |
|
256 | } |
281 | } |
257 | } |
282 | } |
258 | 283 | ||
259 | previousScore = bestThread->rootMoves[0].score; |
284 | previousScore = bestThread->rootMoves[0].score; |
260 | 285 | ||
261 | // Send |
286 | // Send again PV info if we have a new best thread |
262 | if (bestThread != this) |
287 | if (bestThread != this) |
263 | sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; |
288 | sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl; |
264 | 289 | ||
265 | sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960()); |
290 | sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960()); |
266 | 291 | ||
Line 281... | Line 306... | ||
281 | Value bestValue, alpha, beta, delta; |
306 | Value bestValue, alpha, beta, delta; |
282 | Move lastBestMove = MOVE_NONE; |
307 | Move lastBestMove = MOVE_NONE; |
283 | Depth lastBestMoveDepth = DEPTH_ZERO; |
308 | Depth lastBestMoveDepth = DEPTH_ZERO; |
284 | MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); |
309 | MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); |
285 | double timeReduction = 1.0; |
310 | double timeReduction = 1.0; |
- | 311 | Color us = rootPos.side_to_move(); |
|
- | 312 | bool failedLow; |
|
286 | 313 | ||
287 | std::memset(ss-4, 0, 7 * sizeof(Stack)); |
314 | std::memset(ss-4, 0, 7 * sizeof(Stack)); |
288 | for (int i = 4; i > 0; i--) |
315 | for (int i = 4; i > 0; i--) |
289 | (ss-i)-> |
316 | (ss-i)->continuationHistory = &this->continuationHistory[NO_PIECE][0]; // Use as sentinel |
290 | 317 | ||
291 | bestValue = delta = alpha = -VALUE_INFINITE; |
318 | bestValue = delta = alpha = -VALUE_INFINITE; |
292 | beta = VALUE_INFINITE; |
319 | beta = VALUE_INFINITE; |
293 | 320 | ||
294 | if (mainThread) |
321 | if (mainThread) |
295 | { |
- | |
296 | mainThread->failedLow = false; |
- | |
297 | mainThread->bestMoveChanges = 0; |
322 | mainThread->bestMoveChanges = 0, failedLow = false; |
298 | } |
- | |
299 | 323 | ||
300 | size_t multiPV = Options["MultiPV"]; |
324 | size_t multiPV = Options["MultiPV"]; |
301 | Skill skill(Options["Skill Level"]); |
325 | Skill skill(Options["Skill Level"]); |
302 | 326 | ||
303 | // When playing with strength handicap enable MultiPV search that we will |
327 | // When playing with strength handicap enable MultiPV search that we will |
304 | // use behind the scenes to retrieve a set of possible moves. |
328 | // use behind the scenes to retrieve a set of possible moves. |
305 | if (skill.enabled()) |
329 | if (skill.enabled()) |
306 | multiPV = std::max(multiPV, (size_t)4); |
330 | multiPV = std::max(multiPV, (size_t)4); |
307 | 331 | ||
308 | multiPV = std::min(multiPV, rootMoves.size()); |
332 | multiPV = std::min(multiPV, rootMoves.size()); |
- | 333 | ||
- | 334 | int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns |
|
- | 335 | ||
- | 336 | // In analysis mode, adjust contempt in accordance with user preference |
|
- | 337 | if (Limits.infinite || Options["UCI_AnalyseMode"]) |
|
- | 338 | ct = Options["Analysis Contempt"] == "Off" ? 0 |
|
- | 339 | : Options["Analysis Contempt"] == "Both" ? ct |
|
- | 340 | : Options["Analysis Contempt"] == "White" && us == BLACK ? -ct |
|
- | 341 | : Options["Analysis Contempt"] == "Black" && us == WHITE ? -ct |
|
- | 342 | : ct; |
|
- | 343 | ||
- | 344 | // In evaluate.cpp the evaluation is from the white point of view |
|
- | 345 | contempt = (us == WHITE ? make_score(ct, ct / 2) |
|
- | 346 | : -make_score(ct, ct / 2)); |
|
309 | 347 | ||
310 | // Iterative deepening loop until requested to stop or the target depth is reached |
348 | // Iterative deepening loop until requested to stop or the target depth is reached |
311 | while ( (rootDepth += ONE_PLY) < DEPTH_MAX |
349 | while ( (rootDepth += ONE_PLY) < DEPTH_MAX |
312 | && !Threads.stop |
350 | && !Threads.stop |
313 | && !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth)) |
351 | && !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth)) |
314 | { |
352 | { |
315 | // Distribute search depths across the threads |
353 | // Distribute search depths across the helper threads |
316 | if (idx) |
354 | if (idx > 0) |
317 | { |
355 | { |
318 | int i = (idx - 1) % 20; |
356 | int i = (idx - 1) % 20; |
319 | if (((rootDepth / ONE_PLY + |
357 | if (((rootDepth / ONE_PLY + SkipPhase[i]) / SkipSize[i]) % 2) |
320 | continue; |
358 | continue; // Retry with an incremented rootDepth |
321 | } |
359 | } |
322 | 360 | ||
323 | // Age out PV variability metric |
361 | // Age out PV variability metric |
324 | if (mainThread) |
362 | if (mainThread) |
325 | mainThread->bestMoveChanges *= 0. |
363 | mainThread->bestMoveChanges *= 0.517, failedLow = false; |
326 | 364 | ||
327 | // Save the last iteration's scores before first PV line is searched and |
365 | // Save the last iteration's scores before first PV line is searched and |
328 | // all the move scores except the (new) PV are set to -VALUE_INFINITE. |
366 | // all the move scores except the (new) PV are set to -VALUE_INFINITE. |
329 | for (RootMove& rm : rootMoves) |
367 | for (RootMove& rm : rootMoves) |
330 | rm.previousScore = rm.score; |
368 | rm.previousScore = rm.score; |
- | 369 | ||
- | 370 | size_t pvFirst = 0; |
|
- | 371 | pvLast = 0; |
|
331 | 372 | ||
332 | // MultiPV loop. We perform a full root search for each PV line |
373 | // MultiPV loop. We perform a full root search for each PV line |
333 | for ( |
374 | for (pvIdx = 0; pvIdx < multiPV && !Threads.stop; ++pvIdx) |
334 | { |
375 | { |
- | 376 | if (pvIdx == pvLast) |
|
- | 377 | { |
|
- | 378 | pvFirst = pvLast; |
|
- | 379 | for (pvLast++; pvLast < rootMoves.size(); pvLast++) |
|
- | 380 | if (rootMoves[pvLast].tbRank != rootMoves[pvFirst].tbRank) |
|
- | 381 | break; |
|
- | 382 | } |
|
- | 383 | ||
335 | // Reset UCI info selDepth for each depth and each PV line |
384 | // Reset UCI info selDepth for each depth and each PV line |
336 | selDepth = 0; |
385 | selDepth = 0; |
337 | 386 | ||
338 | // Reset aspiration window starting size |
387 | // Reset aspiration window starting size |
339 | if (rootDepth >= 5 * ONE_PLY) |
388 | if (rootDepth >= 5 * ONE_PLY) |
340 | { |
389 | { |
- | 390 | Value previousScore = rootMoves[pvIdx].previousScore; |
|
341 | delta = Value( |
391 | delta = Value(20); |
342 | alpha = std::max( |
392 | alpha = std::max(previousScore - delta,-VALUE_INFINITE); |
343 | beta = std::min( |
393 | beta = std::min(previousScore + delta, VALUE_INFINITE); |
- | 394 | ||
- | 395 | // Adjust contempt based on root move's previousScore (dynamic contempt) |
|
- | 396 | int dct = ct + 88 * previousScore / (abs(previousScore) + 200); |
|
- | 397 | ||
- | 398 | contempt = (us == WHITE ? make_score(dct, dct / 2) |
|
- | 399 | : -make_score(dct, dct / 2)); |
|
344 | } |
400 | } |
345 | 401 | ||
346 | // Start with a small aspiration window and, in the case of a fail |
402 | // Start with a small aspiration window and, in the case of a fail |
347 | // high/low, re-search with a bigger window until |
403 | // high/low, re-search with a bigger window until we don't fail |
348 | // high/low anymore. |
404 | // high/low anymore. |
- | 405 | int failedHighCnt = 0; |
|
349 | while (true) |
406 | while (true) |
350 | { |
407 | { |
- | 408 | Depth adjustedDepth = std::max(ONE_PLY, rootDepth - failedHighCnt * ONE_PLY); |
|
351 | bestValue = ::search<PV>(rootPos, ss, alpha, beta, |
409 | bestValue = ::search<PV>(rootPos, ss, alpha, beta, adjustedDepth, false); |
352 | 410 | ||
353 | // Bring the best move to the front. It is critical that sorting |
411 | // Bring the best move to the front. It is critical that sorting |
354 | // is done with a stable algorithm because all the values but the |
412 | // is done with a stable algorithm because all the values but the |
355 | // first and eventually the new best one are set to -VALUE_INFINITE |
413 | // first and eventually the new best one are set to -VALUE_INFINITE |
356 | // and we want to keep the same order for all the moves except the |
414 | // and we want to keep the same order for all the moves except the |
357 | // new PV that goes to the front. Note that in case of MultiPV |
415 | // new PV that goes to the front. Note that in case of MultiPV |
358 | // search the already searched PV lines are preserved. |
416 | // search the already searched PV lines are preserved. |
359 | std::stable_sort(rootMoves.begin() + |
417 | std::stable_sort(rootMoves.begin() + pvIdx, rootMoves.begin() + pvLast); |
360 | 418 | ||
361 | // If search has been stopped, we break immediately. Sorting |
419 | // If search has been stopped, we break immediately. Sorting is |
362 | // |
420 | // safe because RootMoves is still valid, although it refers to |
363 | // |
421 | // the previous iteration. |
364 | if (Threads.stop) |
422 | if (Threads.stop) |
365 | break; |
423 | break; |
366 | 424 | ||
367 | // When failing high/low give some update (without cluttering |
425 | // When failing high/low give some update (without cluttering |
368 | // the UI) before a re-search. |
426 | // the UI) before a re-search. |
Line 379... | Line 437... | ||
379 | beta = (alpha + beta) / 2; |
437 | beta = (alpha + beta) / 2; |
380 | alpha = std::max(bestValue - delta, -VALUE_INFINITE); |
438 | alpha = std::max(bestValue - delta, -VALUE_INFINITE); |
381 | 439 | ||
382 | if (mainThread) |
440 | if (mainThread) |
383 | { |
441 | { |
- | 442 | failedHighCnt = 0; |
|
384 |
|
443 | failedLow = true; |
385 | Threads.stopOnPonderhit = false; |
444 | Threads.stopOnPonderhit = false; |
386 | } |
445 | } |
387 | } |
446 | } |
388 | else if (bestValue >= beta) |
447 | else if (bestValue >= beta) |
- | 448 | { |
|
389 | beta = std::min(bestValue + delta, VALUE_INFINITE); |
449 | beta = std::min(bestValue + delta, VALUE_INFINITE); |
- | 450 | if (mainThread) |
|
- | 451 | ++failedHighCnt; |
|
- | 452 | } |
|
390 | else |
453 | else |
391 | break; |
454 | break; |
392 | 455 | ||
393 | delta += delta / 4 + 5; |
456 | delta += delta / 4 + 5; |
394 | 457 | ||
395 | assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); |
458 | assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); |
396 | } |
459 | } |
397 | 460 | ||
398 | // Sort the PV lines searched so far and update the GUI |
461 | // Sort the PV lines searched so far and update the GUI |
399 | std::stable_sort(rootMoves.begin() |
462 | std::stable_sort(rootMoves.begin() + pvFirst, rootMoves.begin() + pvIdx + 1); |
400 | 463 | ||
401 | if ( mainThread |
464 | if ( mainThread |
402 | && (Threads.stop || |
465 | && (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000)) |
403 | sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; |
466 | sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; |
404 | } |
467 | } |
405 | 468 | ||
406 | if (!Threads.stop) |
469 | if (!Threads.stop) |
407 | completedDepth = rootDepth; |
470 | completedDepth = rootDepth; |
Line 423... | Line 486... | ||
423 | // If skill level is enabled and time is up, pick a sub-optimal best move |
486 | // If skill level is enabled and time is up, pick a sub-optimal best move |
424 | if (skill.enabled() && skill.time_to_pick(rootDepth)) |
487 | if (skill.enabled() && skill.time_to_pick(rootDepth)) |
425 | skill.pick_best(multiPV); |
488 | skill.pick_best(multiPV); |
426 | 489 | ||
427 | // Do we have time for the next iteration? Can we stop searching now? |
490 | // Do we have time for the next iteration? Can we stop searching now? |
428 | if (Limits.use_time_management( |
491 | if ( Limits.use_time_management() |
429 |
|
492 | && !Threads.stop |
430 |
|
493 | && !Threads.stopOnPonderhit) |
431 | { |
494 | { |
432 | // Stop the search if only one legal move is available, or if all |
- | |
433 | // of the available time has been used |
- | |
434 | const int F[] = { |
495 | const int F[] = { failedLow, |
435 | bestValue - mainThread->previousScore }; |
496 | bestValue - mainThread->previousScore }; |
436 | int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1])); |
- | |
437 | 497 | ||
438 | Color us = rootPos.side_to_move(); |
- | |
439 | bool thinkHard = bestValue == VALUE_DRAW |
- | |
440 |
|
498 | int improvingFactor = std::max(246, std::min(832, 306 + 119 * F[0] - 6 * F[1])); |
441 | && ::pv_is_draw(rootPos); |
- | |
442 | 499 | ||
443 |
|
500 | // If the bestMove is stable over several iterations, reduce time accordingly |
- | 501 | timeReduction = 1.0; |
|
- | 502 | for (int i : {3, 4, 5}) |
|
- | 503 | if (lastBestMoveDepth * i < completedDepth) |
|
- | 504 | timeReduction *= 1.25; |
|
444 | 505 | ||
445 | // if the bestMove is stable over several iterations, reduce time for this move, |
- | |
446 | // the longer the move has been stable, the more. |
- | |
447 | // Use part of the gained time from a previous stable move for the current move |
506 | // Use part of the gained time from a previous stable move for the current move |
448 | timeReduction = 1; |
- | |
449 | for (int i : {3, 4, 5}) |
- | |
450 |
|
507 | double bestMoveInstability = 1.0 + mainThread->bestMoveChanges; |
451 | timeReduction *= 1.3; |
- | |
452 |
|
508 | bestMoveInstability *= std::pow(mainThread->previousTimeReduction, 0.528) / timeReduction; |
453 | 509 | ||
- | 510 | // Stop the search if we have only one legal move, or if available time elapsed |
|
454 | if ( rootMoves.size() == 1 |
511 | if ( rootMoves.size() == 1 |
455 | || Time.elapsed() > Time.optimum() * |
512 | || Time.elapsed() > Time.optimum() * bestMoveInstability * improvingFactor / 581) |
456 | { |
513 | { |
457 | // If we are allowed to ponder do not stop the search now but |
514 | // If we are allowed to ponder do not stop the search now but |
458 | // keep pondering until the GUI sends "ponderhit" or "stop". |
515 | // keep pondering until the GUI sends "ponderhit" or "stop". |
459 | if (Threads.ponder) |
516 | if (Threads.ponder) |
460 | Threads.stopOnPonderhit = true; |
517 | Threads.stopOnPonderhit = true; |
461 | else |
518 | else |
462 | Threads.stop = true; |
519 | Threads.stop = true; |
463 | } |
520 | } |
464 | } |
521 | } |
465 | } |
- | |
466 | } |
522 | } |
467 | 523 | ||
468 | if (!mainThread) |
524 | if (!mainThread) |
469 | return; |
525 | return; |
470 | 526 | ||
Line 480... | Line 536... | ||
480 | namespace { |
536 | namespace { |
481 | 537 | ||
482 | // search<>() is the main search function for both PV and non-PV nodes |
538 | // search<>() is the main search function for both PV and non-PV nodes |
483 | 539 | ||
484 | template <NodeType NT> |
540 | template <NodeType NT> |
485 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool |
541 | Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) { |
486 | 542 | ||
487 |
|
543 | constexpr bool PvNode = NT == PV; |
488 | const bool rootNode = PvNode && ss->ply == 0; |
544 | const bool rootNode = PvNode && ss->ply == 0; |
- | 545 | ||
- | 546 | // Check if we have an upcoming move which draws by repetition, or |
|
- | 547 | // if the opponent had an alternative move earlier to this position. |
|
- | 548 | if ( pos.rule50_count() >= 3 |
|
- | 549 | && alpha < VALUE_DRAW |
|
- | 550 | && !rootNode |
|
- | 551 | && pos.has_game_cycle(ss->ply)) |
|
- | 552 | { |
|
- | 553 | alpha = value_draw(depth, pos.this_thread()); |
|
- | 554 | if (alpha >= beta) |
|
- | 555 | return alpha; |
|
- | 556 | } |
|
- | 557 | ||
- | 558 | // Dive into quiescence search when the depth reaches zero |
|
- | 559 | if (depth < ONE_PLY) |
|
- | 560 | return qsearch<NT>(pos, ss, alpha, beta); |
|
489 | 561 | ||
490 | assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); |
562 | assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); |
491 | assert(PvNode || (alpha == beta - 1)); |
563 | assert(PvNode || (alpha == beta - 1)); |
492 | assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); |
564 | assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); |
493 | assert(!(PvNode && cutNode)); |
565 | assert(!(PvNode && cutNode)); |
Line 497... | Line 569... | ||
497 | StateInfo st; |
569 | StateInfo st; |
498 | TTEntry* tte; |
570 | TTEntry* tte; |
499 | Key posKey; |
571 | Key posKey; |
500 | Move ttMove, move, excludedMove, bestMove; |
572 | Move ttMove, move, excludedMove, bestMove; |
501 | Depth extension, newDepth; |
573 | Depth extension, newDepth; |
502 | Value bestValue, value, ttValue, eval, |
574 | Value bestValue, value, ttValue, eval, maxValue, pureStaticEval; |
503 | bool ttHit, inCheck, givesCheck, |
575 | bool ttHit, inCheck, givesCheck, improving; |
504 | bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; |
576 | bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; |
505 | Piece movedPiece; |
577 | Piece movedPiece; |
506 | int moveCount, captureCount, quietCount; |
578 | int moveCount, captureCount, quietCount; |
507 | 579 | ||
508 | // Step 1. Initialize node |
580 | // Step 1. Initialize node |
509 | Thread* thisThread = pos.this_thread(); |
581 | Thread* thisThread = pos.this_thread(); |
510 | inCheck = pos.checkers(); |
582 | inCheck = pos.checkers(); |
- | 583 | Color us = pos.side_to_move(); |
|
511 | moveCount = captureCount = quietCount = ss->moveCount = 0; |
584 | moveCount = captureCount = quietCount = ss->moveCount = 0; |
512 | ss->statScore = 0; |
- | |
513 | bestValue = -VALUE_INFINITE; |
585 | bestValue = -VALUE_INFINITE; |
514 | maxValue = VALUE_INFINITE; |
586 | maxValue = VALUE_INFINITE; |
515 | 587 | ||
516 | // Check for the available remaining time |
588 | // Check for the available remaining time |
517 | if (thisThread == Threads.main()) |
589 | if (thisThread == Threads.main()) |
Line 522... | Line 594... | ||
522 | thisThread->selDepth = ss->ply + 1; |
594 | thisThread->selDepth = ss->ply + 1; |
523 | 595 | ||
524 | if (!rootNode) |
596 | if (!rootNode) |
525 | { |
597 | { |
526 | // Step 2. Check for aborted search and immediate draw |
598 | // Step 2. Check for aborted search and immediate draw |
527 | if ( |
599 | if ( Threads.stop.load(std::memory_order_relaxed) |
- | 600 | || pos.is_draw(ss->ply) |
|
- | 601 | || ss->ply >= MAX_PLY) |
|
528 | return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) |
602 | return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) |
- | 603 | : value_draw(depth, pos.this_thread()); |
|
529 | 604 | ||
530 | // Step 3. Mate distance pruning. Even if we mate at the next move our score |
605 | // Step 3. Mate distance pruning. Even if we mate at the next move our score |
531 | // would be at best mate_in(ss->ply+1), but if alpha is already bigger because |
606 | // would be at best mate_in(ss->ply+1), but if alpha is already bigger because |
532 | // a shorter mate was found upward in the tree then there is no need to search |
607 | // a shorter mate was found upward in the tree then there is no need to search |
533 | // because we will never beat the current alpha. Same logic but with reversed |
608 | // because we will never beat the current alpha. Same logic but with reversed |
Line 541... | Line 616... | ||
541 | 616 | ||
542 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
617 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
543 | 618 | ||
544 | (ss+1)->ply = ss->ply + 1; |
619 | (ss+1)->ply = ss->ply + 1; |
545 | ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; |
620 | ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; |
546 | ss-> |
621 | ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; |
547 | (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; |
622 | (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; |
548 | Square prevSq = to_sq((ss-1)->currentMove); |
623 | Square prevSq = to_sq((ss-1)->currentMove); |
- | 624 | ||
- | 625 | // Initialize statScore to zero for the grandchildren of the current position. |
|
- | 626 | // So statScore is shared between all grandchildren and only the first grandchild |
|
- | 627 | // starts with statScore = 0. Later grandchildren start with the last calculated |
|
- | 628 | // statScore of the previous grandchild. This influences the reduction rules in |
|
- | 629 | // LMR which are based on the statScore of parent position. |
|
- | 630 | (ss+2)->statScore = 0; |
|
549 | 631 | ||
550 | // Step 4. Transposition table lookup. We don't want the score of a partial |
632 | // Step 4. Transposition table lookup. We don't want the score of a partial |
551 | // search to overwrite a previous full search TT value, so we use a different |
633 | // search to overwrite a previous full search TT value, so we use a different |
552 | // position key in case of an excluded move. |
634 | // position key in case of an excluded move. |
553 | excludedMove = ss->excludedMove; |
635 | excludedMove = ss->excludedMove; |
554 | posKey = pos.key() ^ Key(excludedMove << 16); // |
636 | posKey = pos.key() ^ Key(excludedMove << 16); // Isn't a very good hash |
555 | tte = TT.probe(posKey, ttHit); |
637 | tte = TT.probe(posKey, ttHit); |
556 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
638 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
557 | ttMove = rootNode ? thisThread->rootMoves[thisThread-> |
639 | ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] |
558 | : ttHit ? tte->move() : MOVE_NONE; |
640 | : ttHit ? tte->move() : MOVE_NONE; |
559 | 641 | ||
560 | // At non-PV nodes we check for an early TT cutoff |
642 | // At non-PV nodes we check for an early TT cutoff |
561 | if ( !PvNode |
643 | if ( !PvNode |
562 | && ttHit |
644 | && ttHit |
Line 569... | Line 651... | ||
569 | if (ttMove) |
651 | if (ttMove) |
570 | { |
652 | { |
571 | if (ttValue >= beta) |
653 | if (ttValue >= beta) |
572 | { |
654 | { |
573 | if (!pos.capture_or_promotion(ttMove)) |
655 | if (!pos.capture_or_promotion(ttMove)) |
574 |
|
656 | update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); |
575 | 657 | ||
576 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
658 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
577 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
659 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
578 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); |
660 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); |
579 | } |
661 | } |
580 | // Penalty for a quiet ttMove that fails low |
662 | // Penalty for a quiet ttMove that fails low |
581 | else if (!pos.capture_or_promotion(ttMove)) |
663 | else if (!pos.capture_or_promotion(ttMove)) |
582 | { |
664 | { |
583 | int penalty = -stat_bonus(depth); |
665 | int penalty = -stat_bonus(depth); |
584 | thisThread->mainHistory |
666 | thisThread->mainHistory[us][from_to(ttMove)] << penalty; |
585 | update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); |
667 | update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); |
586 | } |
668 | } |
587 | } |
669 | } |
588 | return ttValue; |
670 | return ttValue; |
589 | } |
671 | } |
590 | 672 | ||
591 | // Step |
673 | // Step 5. Tablebases probe |
592 | if (!rootNode && TB::Cardinality) |
674 | if (!rootNode && TB::Cardinality) |
593 | { |
675 | { |
594 | int piecesCount = pos.count<ALL_PIECES>(); |
676 | int piecesCount = pos.count<ALL_PIECES>(); |
595 | 677 | ||
596 | if ( piecesCount <= TB::Cardinality |
678 | if ( piecesCount <= TB::Cardinality |
Line 598... | Line 680... | ||
598 | && pos.rule50_count() == 0 |
680 | && pos.rule50_count() == 0 |
599 | && !pos.can_castle(ANY_CASTLING)) |
681 | && !pos.can_castle(ANY_CASTLING)) |
600 | { |
682 | { |
601 | TB::ProbeState err; |
683 | TB::ProbeState err; |
602 | TB::WDLScore wdl = Tablebases::probe_wdl(pos, &err); |
684 | TB::WDLScore wdl = Tablebases::probe_wdl(pos, &err); |
- | 685 | ||
- | 686 | // Force check of time on the next occasion |
|
- | 687 | if (thisThread == Threads.main()) |
|
- | 688 | static_cast<MainThread*>(thisThread)->callsCnt = 0; |
|
603 | 689 | ||
604 | if (err != TB::ProbeState::FAIL) |
690 | if (err != TB::ProbeState::FAIL) |
605 | { |
691 | { |
606 | thisThread->tbHits.fetch_add(1, std::memory_order_relaxed); |
692 | thisThread->tbHits.fetch_add(1, std::memory_order_relaxed); |
607 | 693 | ||
Line 617... | Line 703... | ||
617 | if ( b == BOUND_EXACT |
703 | if ( b == BOUND_EXACT |
618 | || (b == BOUND_LOWER ? value >= beta : value <= alpha)) |
704 | || (b == BOUND_LOWER ? value >= beta : value <= alpha)) |
619 | { |
705 | { |
620 | tte->save(posKey, value_to_tt(value, ss->ply), b, |
706 | tte->save(posKey, value_to_tt(value, ss->ply), b, |
621 | std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), |
707 | std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY), |
622 | MOVE_NONE, |
708 | MOVE_NONE, VALUE_NONE); |
623 | 709 | ||
624 | return value; |
710 | return value; |
625 | } |
711 | } |
626 | 712 | ||
627 | if (PvNode) |
713 | if (PvNode) |
Line 633... | Line 719... | ||
633 | } |
719 | } |
634 | } |
720 | } |
635 | } |
721 | } |
636 | } |
722 | } |
637 | 723 | ||
638 | // Step |
724 | // Step 6. Static evaluation of the position |
639 | if (inCheck) |
725 | if (inCheck) |
640 | { |
726 | { |
641 | ss->staticEval = eval = VALUE_NONE; |
727 | ss->staticEval = eval = pureStaticEval = VALUE_NONE; |
642 |
|
728 | improving = false; |
- | 729 | goto moves_loop; // Skip early pruning when in check |
|
643 | } |
730 | } |
644 | - | ||
645 | else if (ttHit) |
731 | else if (ttHit) |
646 | { |
732 | { |
647 | // Never assume anything on values stored in TT |
733 | // Never assume anything on values stored in TT |
648 |
|
734 | ss->staticEval = eval = pureStaticEval = tte->eval(); |
- | 735 | if (eval == VALUE_NONE) |
|
649 |
|
736 | ss->staticEval = eval = pureStaticEval = evaluate(pos); |
650 | 737 | ||
651 | // Can ttValue be used as a better position evaluation? |
738 | // Can ttValue be used as a better position evaluation? |
652 | if ( ttValue != VALUE_NONE |
739 | if ( ttValue != VALUE_NONE |
653 | && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))) |
740 | && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))) |
654 | eval = ttValue; |
741 | eval = ttValue; |
655 | } |
742 | } |
656 | else |
743 | else |
657 | { |
744 | { |
- | 745 | if ((ss-1)->currentMove != MOVE_NULL) |
|
- | 746 | { |
|
658 |
|
747 | int p = (ss-1)->statScore; |
659 |
|
748 | int bonus = p > 0 ? (-p - 2500) / 512 : |
660 |
|
749 | p < 0 ? (-p + 2500) / 512 : 0; |
661 | 750 | ||
662 |
|
751 | pureStaticEval = evaluate(pos); |
663 |
|
752 | ss->staticEval = eval = pureStaticEval + bonus; |
- | 753 | } |
|
- | 754 | else |
|
- | 755 | ss->staticEval = eval = pureStaticEval = -(ss-1)->staticEval + 2 * Eval::Tempo; |
|
- | 756 | ||
- | 757 | tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, pureStaticEval); |
|
664 | } |
758 | } |
665 | 759 | ||
666 |
|
760 | // Step 7. Razoring (~2 Elo) |
667 |
|
761 | if ( depth < 2 * ONE_PLY |
- | 762 | && eval <= alpha - RazorMargin) |
|
- | 763 | return qsearch<NT>(pos, ss, alpha, beta); |
|
668 | 764 | ||
669 | // Step 6. Razoring (skipped when in check) |
- | |
670 | if ( !PvNode |
- | |
671 | && depth < 4 * ONE_PLY |
- | |
672 |
|
765 | improving = ss->staticEval >= (ss-2)->staticEval |
673 | { |
- | |
674 | if (depth <= ONE_PLY) |
- | |
675 | return qsearch<NonPV, false>(pos, ss, alpha, alpha+1); |
- | |
676 | - | ||
677 |
|
766 | || (ss-2)->staticEval == VALUE_NONE; |
678 | Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1); |
- | |
679 | if (v <= ralpha) |
- | |
680 | return v; |
- | |
681 | } |
- | |
682 | 767 | ||
683 | // Step |
768 | // Step 8. Futility pruning: child node (~30 Elo) |
684 | if ( !rootNode |
769 | if ( !rootNode |
685 | && depth < 7 * ONE_PLY |
770 | && depth < 7 * ONE_PLY |
686 | && eval - futility_margin( |
771 | && eval - futility_margin(depth, improving) >= beta |
687 | && eval < VALUE_KNOWN_WIN) |
772 | && eval < VALUE_KNOWN_WIN) // Do not return unproven wins |
688 | return eval; |
773 | return eval; |
689 | 774 | ||
690 | // Step |
775 | // Step 9. Null move search with verification search (~40 Elo) |
691 | if ( !PvNode |
776 | if ( !PvNode |
- | 777 | && (ss-1)->currentMove != MOVE_NULL |
|
- | 778 | && (ss-1)->statScore < 23200 |
|
692 | && eval >= beta |
779 | && eval >= beta |
693 | && |
780 | && pureStaticEval >= beta - 36 * depth / ONE_PLY + 225 |
- | 781 | && !excludedMove |
|
- | 782 | && pos.non_pawn_material(us) |
|
694 | && (ss->ply >= thisThread-> |
783 | && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) |
695 | { |
784 | { |
696 | - | ||
697 | assert(eval - beta >= 0); |
785 | assert(eval - beta >= 0); |
698 | 786 | ||
699 | // Null move dynamic reduction based on depth and value |
787 | // Null move dynamic reduction based on depth and value |
700 | Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min((eval - beta) / |
788 | Depth R = ((823 + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY; |
701 | 789 | ||
702 | ss->currentMove = MOVE_NULL; |
790 | ss->currentMove = MOVE_NULL; |
703 | ss-> |
791 | ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; |
704 | 792 | ||
705 | pos.do_null_move(st); |
793 | pos.do_null_move(st); |
706 | Value nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1) |
- | |
- | 794 | ||
707 |
|
795 | Value nullValue = -search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode); |
- | 796 | ||
708 | pos.undo_null_move(); |
797 | pos.undo_null_move(); |
709 | 798 | ||
710 | if (nullValue >= beta) |
799 | if (nullValue >= beta) |
711 | { |
800 | { |
712 | // Do not return unproven mate scores |
801 | // Do not return unproven mate scores |
713 | if (nullValue >= VALUE_MATE_IN_MAX_PLY) |
802 | if (nullValue >= VALUE_MATE_IN_MAX_PLY) |
714 | nullValue = beta; |
803 | nullValue = beta; |
715 | 804 | ||
716 | if (abs(beta) < VALUE_KNOWN_WIN && |
805 | if (thisThread->nmpMinPly || (abs(beta) < VALUE_KNOWN_WIN && depth < 12 * ONE_PLY)) |
717 | return nullValue; |
806 | return nullValue; |
718 | 807 | ||
719 | // Do verification search at high depths |
- | |
720 | // disable null move pruning for side to move for the first part of the remaining search tree |
- | |
721 |
|
808 | assert(!thisThread->nmpMinPly); // Recursive verification is not allowed |
722 | thisThread->nmp_odd = ss->ply % 2; |
- | |
723 | 809 | ||
724 |
|
810 | // Do verification search at high depths, with null move pruning disabled |
- | 811 | // for us, until ply exceeds nmpMinPly. |
|
725 |
|
812 | thisThread->nmpMinPly = ss->ply + 3 * (depth-R) / 4; |
- | 813 | thisThread->nmpColor = us; |
|
726 | 814 | ||
- | 815 | Value v = search<NonPV>(pos, ss, beta-1, beta, depth-R, false); |
|
- | 816 | ||
727 | thisThread-> |
817 | thisThread->nmpMinPly = 0; |
728 | 818 | ||
729 | if (v >= beta) |
819 | if (v >= beta) |
730 | return nullValue; |
820 | return nullValue; |
731 | } |
821 | } |
732 | } |
822 | } |
733 | 823 | ||
734 | // Step |
824 | // Step 10. ProbCut (~10 Elo) |
735 | // If we have a good enough capture and a reduced search returns a value |
825 | // If we have a good enough capture and a reduced search returns a value |
736 | // much above beta, we can (almost) safely prune the previous move. |
826 | // much above beta, we can (almost) safely prune the previous move. |
737 | if ( !PvNode |
827 | if ( !PvNode |
738 | && depth >= 5 * ONE_PLY |
828 | && depth >= 5 * ONE_PLY |
739 | && abs(beta) < VALUE_MATE_IN_MAX_PLY) |
829 | && abs(beta) < VALUE_MATE_IN_MAX_PLY) |
740 | { |
830 | { |
741 | Value rbeta = std::min(beta + |
831 | Value rbeta = std::min(beta + 216 - 48 * improving, VALUE_INFINITE); |
742 | - | ||
743 | assert(is_ok((ss-1)->currentMove)); |
- | |
744 | - | ||
745 | MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory); |
832 | MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory); |
- | 833 | int probCutCount = 0; |
|
746 | 834 | ||
747 | while ((move = mp.next_move()) != MOVE_NONE |
835 | while ( (move = mp.next_move()) != MOVE_NONE |
- | 836 | && probCutCount < 3) |
|
748 | if (pos.legal(move)) |
837 | if (move != excludedMove && pos.legal(move)) |
749 | { |
838 | { |
- | 839 | probCutCount++; |
|
- | 840 | ||
750 | ss->currentMove = move; |
841 | ss->currentMove = move; |
751 | ss-> |
842 | ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)]; |
752 | 843 | ||
753 | assert(depth >= 5 * ONE_PLY); |
844 | assert(depth >= 5 * ONE_PLY); |
- | 845 | ||
754 | pos.do_move(move, st); |
846 | pos.do_move(move, st); |
- | 847 | ||
- | 848 | // Perform a preliminary qsearch to verify that the move holds |
|
- | 849 | value = -qsearch<NonPV>(pos, ss+1, -rbeta, -rbeta+1); |
|
- | 850 | ||
- | 851 | // If the qsearch held perform the regular search |
|
- | 852 | if (value >= rbeta) |
|
755 | value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, depth - 4 * ONE_PLY, ! |
853 | value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, depth - 4 * ONE_PLY, !cutNode); |
- | 854 | ||
756 | pos.undo_move(move); |
855 | pos.undo_move(move); |
- | 856 | ||
757 | if (value >= rbeta) |
857 | if (value >= rbeta) |
758 | return value; |
858 | return value; |
759 | } |
859 | } |
760 | } |
860 | } |
761 | 861 | ||
762 | // Step |
862 | // Step 11. Internal iterative deepening (~2 Elo) |
763 | if ( depth >= |
863 | if ( depth >= 8 * ONE_PLY |
764 | && !ttMove |
864 | && !ttMove) |
765 | && (PvNode || ss->staticEval + 256 >= beta)) |
- | |
766 | { |
865 | { |
767 | Depth d = (3 * depth / (4 * ONE_PLY) - 2) * ONE_PLY; |
- | |
768 | search<NT>(pos, ss, alpha, beta, |
866 | search<NT>(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode); |
769 | 867 | ||
770 | tte = TT.probe(posKey, ttHit); |
868 | tte = TT.probe(posKey, ttHit); |
- | 869 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
|
771 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
870 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
772 | } |
871 | } |
773 | 872 | ||
774 | moves_loop: // When in |
873 | moves_loop: // When in check, search starts from here |
775 | 874 | ||
776 | const PieceToHistory* contHist[] = { (ss-1)-> |
875 | const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, nullptr, (ss-4)->continuationHistory }; |
777 | Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; |
876 | Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; |
778 | 877 | ||
779 | MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, |
878 | MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, |
- | 879 | &thisThread->captureHistory, |
|
- | 880 | contHist, |
|
- | 881 | countermove, |
|
- | 882 | ss->killers); |
|
780 | value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc |
883 | value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc |
781 | improving = ss->staticEval >= (ss-2)->staticEval |
- | |
782 | /* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */ |
- | |
783 | ||(ss-2)->staticEval == VALUE_NONE; |
- | |
784 | 884 | ||
785 | singularExtensionNode = !rootNode |
- | |
786 | && depth >= 8 * ONE_PLY |
- | |
787 | && ttMove != MOVE_NONE |
- | |
788 | && ttValue != VALUE_NONE |
- | |
789 | && !excludedMove // Recursive singular search is not allowed |
- | |
790 | && (tte->bound() & BOUND_LOWER) |
- | |
791 | && tte->depth() >= depth - 3 * ONE_PLY; |
- | |
792 | skipQuiets = false; |
885 | skipQuiets = false; |
793 | ttCapture = |
886 | ttCapture = ttMove && pos.capture_or_promotion(ttMove); |
794 | pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT; |
887 | pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT; |
795 | 888 | ||
796 | // Step |
889 | // Step 12. Loop through all pseudo-legal moves until no moves remain |
797 | // |
890 | // or a beta cutoff occurs. |
798 | while ((move = mp.next_move(skipQuiets)) != MOVE_NONE) |
891 | while ((move = mp.next_move(skipQuiets)) != MOVE_NONE) |
799 | { |
892 | { |
800 | assert(is_ok(move)); |
893 | assert(is_ok(move)); |
801 | 894 | ||
802 | if (move == excludedMove) |
895 | if (move == excludedMove) |
803 | continue; |
896 | continue; |
804 | 897 | ||
805 | // At root obey the "searchmoves" option and skip moves not listed in Root |
898 | // At root obey the "searchmoves" option and skip moves not listed in Root |
806 | // Move List. As a consequence any illegal move is also skipped. In MultiPV |
899 | // Move List. As a consequence any illegal move is also skipped. In MultiPV |
807 | // mode we also skip PV moves which have been already searched |
900 | // mode we also skip PV moves which have been already searched and those |
- | 901 | // of lower "TB rank" if we are in a TB root position. |
|
808 | if (rootNode && !std::count(thisThread->rootMoves.begin() + thisThread-> |
902 | if (rootNode && !std::count(thisThread->rootMoves.begin() + thisThread->pvIdx, |
809 | thisThread->rootMoves. |
903 | thisThread->rootMoves.begin() + thisThread->pvLast, move)) |
810 | continue; |
904 | continue; |
811 | 905 | ||
812 | ss->moveCount = ++moveCount; |
906 | ss->moveCount = ++moveCount; |
813 | 907 | ||
814 | if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000) |
908 | if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000) |
815 | sync_cout << "info depth " << depth / ONE_PLY |
909 | sync_cout << "info depth " << depth / ONE_PLY |
816 | << " currmove " << UCI::move(move, pos.is_chess960()) |
910 | << " currmove " << UCI::move(move, pos.is_chess960()) |
817 | << " currmovenumber " << moveCount + thisThread-> |
911 | << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; |
818 | - | ||
819 | if (PvNode) |
912 | if (PvNode) |
820 | (ss+1)->pv = nullptr; |
913 | (ss+1)->pv = nullptr; |
821 | 914 | ||
822 | extension = DEPTH_ZERO; |
915 | extension = DEPTH_ZERO; |
823 | captureOrPromotion = pos.capture_or_promotion(move); |
916 | captureOrPromotion = pos.capture_or_promotion(move); |
824 | movedPiece = pos.moved_piece(move); |
917 | movedPiece = pos.moved_piece(move); |
825 | - | ||
826 | givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates() |
- | |
827 | ? pos.check_squares(type_of(movedPiece)) & to_sq(move) |
- | |
828 |
|
918 | givesCheck = gives_check(pos, move); |
829 | 919 | ||
830 | moveCountPruning = depth < 16 * ONE_PLY |
920 | moveCountPruning = depth < 16 * ONE_PLY |
831 | && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; |
921 | && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; |
832 | 922 | ||
833 | // Step |
923 | // Step 13. Extensions (~70 Elo) |
834 | 924 | ||
835 | // Singular extension search. If all moves but one fail low on a |
925 | // Singular extension search (~60 Elo). If all moves but one fail low on a |
836 | // (alpha-s, beta-s), and just one fails high on (alpha, beta), |
926 | // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), |
837 | // is singular and should be extended. To verify this we do |
927 | // then that move is singular and should be extended. To verify this we do |
838 | // |
928 | // a reduced search on all the other moves but the ttMove and if the |
839 | // ttValue minus a margin then we will extend the ttMove. |
929 | // result is lower than ttValue minus a margin then we will extend the ttMove. |
840 | if ( |
930 | if ( depth >= 8 * ONE_PLY |
841 | && move == ttMove |
931 | && move == ttMove |
- | 932 | && !rootNode |
|
- | 933 | && !excludedMove // Recursive singular search is not allowed |
|
- | 934 | && ttValue != VALUE_NONE |
|
- | 935 | && (tte->bound() & BOUND_LOWER) |
|
- | 936 | && tte->depth() >= depth - 3 * ONE_PLY |
|
842 | && pos.legal(move)) |
937 | && pos.legal(move)) |
843 | { |
938 | { |
844 | Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); |
939 | Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); |
845 | Depth d = (depth / (2 * ONE_PLY)) * ONE_PLY; |
- | |
846 | ss->excludedMove = move; |
940 | ss->excludedMove = move; |
847 | value = search<NonPV>(pos, ss, rBeta - 1, rBeta, |
941 | value = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode); |
848 | ss->excludedMove = MOVE_NONE; |
942 | ss->excludedMove = MOVE_NONE; |
849 | 943 | ||
850 | if (value < rBeta) |
944 | if (value < rBeta) |
851 | extension = ONE_PLY; |
945 | extension = ONE_PLY; |
852 | } |
946 | } |
853 | else if ( givesCheck |
947 | else if ( givesCheck // Check extension (~2 Elo) |
854 | && !moveCountPruning |
- | |
855 | && pos.see_ge(move)) |
948 | && pos.see_ge(move)) |
- | 949 | extension = ONE_PLY; |
|
- | 950 | ||
- | 951 | // Extension if castling |
|
- | 952 | else if (type_of(move) == CASTLING) |
|
856 | extension = ONE_PLY; |
953 | extension = ONE_PLY; |
857 | 954 | ||
858 | // Calculate new depth for this move |
955 | // Calculate new depth for this move |
859 | newDepth = depth - ONE_PLY + extension; |
956 | newDepth = depth - ONE_PLY + extension; |
860 | 957 | ||
861 | // Step |
958 | // Step 14. Pruning at shallow depth (~170 Elo) |
862 | if ( !rootNode |
959 | if ( !rootNode |
863 | && pos.non_pawn_material( |
960 | && pos.non_pawn_material(us) |
864 | && bestValue > VALUE_MATED_IN_MAX_PLY) |
961 | && bestValue > VALUE_MATED_IN_MAX_PLY) |
865 | { |
962 | { |
866 | if ( !captureOrPromotion |
963 | if ( !captureOrPromotion |
867 | && !givesCheck |
964 | && !givesCheck |
868 | && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= Value(5000))) |
965 | && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= Value(5000))) |
869 | { |
966 | { |
870 | // Move count based pruning |
967 | // Move count based pruning (~30 Elo) |
871 | if (moveCountPruning) |
968 | if (moveCountPruning) |
872 | { |
969 | { |
873 | skipQuiets = true; |
970 | skipQuiets = true; |
874 | continue; |
971 | continue; |
875 | } |
972 | } |
876 | 973 | ||
877 | // Reduced depth of the next LMR search |
974 | // Reduced depth of the next LMR search |
878 | int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY; |
975 | int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY; |
879 | 976 | ||
880 | // Countermoves based pruning |
977 | // Countermoves based pruning (~20 Elo) |
881 | if ( lmrDepth < 3 |
978 | if ( lmrDepth < 3 + ((ss-1)->statScore > 0) |
882 | && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold |
979 | && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold |
883 | && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) |
980 | && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) |
884 | continue; |
981 | continue; |
885 | 982 | ||
886 | // Futility pruning: parent node |
983 | // Futility pruning: parent node (~2 Elo) |
887 | if ( lmrDepth < 7 |
984 | if ( lmrDepth < 7 |
888 | && !inCheck |
985 | && !inCheck |
889 | && ss->staticEval + 256 + 200 * lmrDepth <= alpha) |
986 | && ss->staticEval + 256 + 200 * lmrDepth <= alpha) |
890 | continue; |
987 | continue; |
891 | 988 | ||
892 | // Prune moves with negative SEE |
989 | // Prune moves with negative SEE (~10 Elo) |
893 | if ( lmrDepth < 8 |
- | |
894 |
|
990 | if (!pos.see_ge(move, Value(-29 * lmrDepth * lmrDepth))) |
895 | continue; |
991 | continue; |
896 | } |
992 | } |
897 | else if ( |
993 | else if ( !extension // (~20 Elo) |
898 | && !extension |
- | |
899 | && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) |
994 | && !pos.see_ge(move, -PawnValueEg * (depth / ONE_PLY))) |
900 | continue; |
995 | continue; |
901 | } |
996 | } |
902 | 997 | ||
903 | // Speculative prefetch as early as possible |
998 | // Speculative prefetch as early as possible |
Line 907... | Line 1002... | ||
907 | if (!rootNode && !pos.legal(move)) |
1002 | if (!rootNode && !pos.legal(move)) |
908 | { |
1003 | { |
909 | ss->moveCount = --moveCount; |
1004 | ss->moveCount = --moveCount; |
910 | continue; |
1005 | continue; |
911 | } |
1006 | } |
912 | - | ||
913 | if (move == ttMove && captureOrPromotion) |
- | |
914 | ttCapture = true; |
- | |
915 | 1007 | ||
916 | // Update the current move (this must be done after singular extension search) |
1008 | // Update the current move (this must be done after singular extension search) |
917 | ss->currentMove = move; |
1009 | ss->currentMove = move; |
918 | ss-> |
1010 | ss->continuationHistory = &thisThread->continuationHistory[movedPiece][to_sq(move)]; |
919 | 1011 | ||
920 | // Step |
1012 | // Step 15. Make the move |
921 | pos.do_move(move, st, givesCheck); |
1013 | pos.do_move(move, st, givesCheck); |
922 | 1014 | ||
923 | // Step |
1015 | // Step 16. Reduced depth search (LMR). If the move fails high it will be |
924 | // re-searched at full depth. |
1016 | // re-searched at full depth. |
925 | if ( depth >= 3 * ONE_PLY |
1017 | if ( depth >= 3 * ONE_PLY |
926 | && moveCount > 1 |
1018 | && moveCount > 1 |
927 | && (!captureOrPromotion || moveCountPruning)) |
1019 | && (!captureOrPromotion || moveCountPruning)) |
928 | { |
1020 | { |
929 | Depth r = reduction<PvNode>(improving, depth, moveCount); |
1021 | Depth r = reduction<PvNode>(improving, depth, moveCount); |
930 | 1022 | ||
- | 1023 | // Decrease reduction if opponent's move count is high (~10 Elo) |
|
931 | if ( |
1024 | if ((ss-1)->moveCount > 15) |
932 | r -= |
1025 | r -= ONE_PLY; |
- | 1026 | ||
933 | |
1027 | if (!captureOrPromotion) |
934 | { |
1028 | { |
935 | // Decrease reduction if opponent's move count is high |
- | |
936 | if ((ss-1)->moveCount > 15) |
- | |
937 | r -= ONE_PLY; |
- | |
938 | - | ||
939 | // Decrease reduction for exact PV nodes |
1029 | // Decrease reduction for exact PV nodes (~0 Elo) |
940 | if (pvExact) |
1030 | if (pvExact) |
941 | r -= ONE_PLY; |
1031 | r -= ONE_PLY; |
942 | 1032 | ||
943 | // Increase reduction if ttMove is a capture |
1033 | // Increase reduction if ttMove is a capture (~0 Elo) |
944 | if (ttCapture) |
1034 | if (ttCapture) |
945 | r += ONE_PLY; |
1035 | r += ONE_PLY; |
946 | 1036 | ||
947 | // Increase reduction for cut nodes |
1037 | // Increase reduction for cut nodes (~5 Elo) |
948 | if (cutNode) |
1038 | if (cutNode) |
949 | r += 2 * ONE_PLY; |
1039 | r += 2 * ONE_PLY; |
950 | 1040 | ||
951 | // Decrease reduction for moves that escape a capture. Filter out |
1041 | // Decrease reduction for moves that escape a capture. Filter out |
952 | // castling moves, because they are coded as "king captures rook" and |
1042 | // castling moves, because they are coded as "king captures rook" and |
953 | // hence break make_move(). |
1043 | // hence break make_move(). (~5 Elo) |
954 | else if ( type_of(move) == NORMAL |
1044 | else if ( type_of(move) == NORMAL |
955 | && !pos.see_ge(make_move(to_sq(move), from_sq(move)))) |
1045 | && !pos.see_ge(make_move(to_sq(move), from_sq(move)))) |
956 | r -= 2 * ONE_PLY; |
1046 | r -= 2 * ONE_PLY; |
957 | 1047 | ||
958 | ss->statScore = thisThread->mainHistory[ |
1048 | ss->statScore = thisThread->mainHistory[us][from_to(move)] |
959 | + (*contHist[0])[movedPiece][to_sq(move)] |
1049 | + (*contHist[0])[movedPiece][to_sq(move)] |
960 | + (*contHist[1])[movedPiece][to_sq(move)] |
1050 | + (*contHist[1])[movedPiece][to_sq(move)] |
961 | + (*contHist[3])[movedPiece][to_sq(move)] |
1051 | + (*contHist[3])[movedPiece][to_sq(move)] |
962 | - 4000; |
1052 | - 4000; |
963 | 1053 | ||
964 | // Decrease/increase reduction by comparing opponent's stat score |
1054 | // Decrease/increase reduction by comparing opponent's stat score (~10 Elo) |
965 | if (ss->statScore >= 0 && (ss-1)->statScore < 0) |
1055 | if (ss->statScore >= 0 && (ss-1)->statScore < 0) |
966 | r -= ONE_PLY; |
1056 | r -= ONE_PLY; |
967 | 1057 | ||
968 | else if ((ss-1)->statScore >= 0 && ss->statScore < 0) |
1058 | else if ((ss-1)->statScore >= 0 && ss->statScore < 0) |
969 | r += ONE_PLY; |
1059 | r += ONE_PLY; |
970 | 1060 | ||
971 | // Decrease/increase reduction for moves with a good/bad history |
1061 | // Decrease/increase reduction for moves with a good/bad history (~30 Elo) |
972 |
|
1062 | r -= ss->statScore / 20000 * ONE_PLY; |
973 | } |
1063 | } |
974 | 1064 | ||
975 | Depth d = std::max(newDepth - r, ONE_PLY); |
1065 | Depth d = std::max(newDepth - std::max(r, DEPTH_ZERO), ONE_PLY); |
976 | 1066 | ||
977 | value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true |
1067 | value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true); |
978 | 1068 | ||
979 | doFullDepthSearch = (value > alpha && d != newDepth); |
1069 | doFullDepthSearch = (value > alpha && d != newDepth); |
980 | } |
1070 | } |
981 | else |
1071 | else |
982 | doFullDepthSearch = !PvNode || moveCount > 1; |
1072 | doFullDepthSearch = !PvNode || moveCount > 1; |
983 | 1073 | ||
984 | // Step |
1074 | // Step 17. Full depth search when LMR is skipped or fails high |
985 | if (doFullDepthSearch) |
1075 | if (doFullDepthSearch) |
986 | value = newDepth < ONE_PLY ? |
- | |
987 | givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha) |
- | |
988 | : -qsearch<NonPV, false>(pos, ss+1, -(alpha+1), -alpha) |
- | |
989 |
|
1076 | value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); |
990 | 1077 | ||
991 | // For PV nodes only, do a full PV search on the first move or after a fail |
1078 | // For PV nodes only, do a full PV search on the first move or after a fail |
992 | // high (in the latter case search only if value < beta), otherwise let the |
1079 | // high (in the latter case search only if value < beta), otherwise let the |
993 | // parent node fail low with value <= alpha and try another move. |
1080 | // parent node fail low with value <= alpha and try another move. |
994 | if (PvNode && (moveCount == 1 || (value > alpha && (rootNode || value < beta)))) |
1081 | if (PvNode && (moveCount == 1 || (value > alpha && (rootNode || value < beta)))) |
995 | { |
1082 | { |
996 | (ss+1)->pv = pv; |
1083 | (ss+1)->pv = pv; |
997 | (ss+1)->pv[0] = MOVE_NONE; |
1084 | (ss+1)->pv[0] = MOVE_NONE; |
998 | 1085 | ||
999 | value = newDepth < ONE_PLY ? |
- | |
1000 | givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha) |
- | |
1001 | : -qsearch<PV, false>(pos, ss+1, -beta, -alpha) |
- | |
1002 |
|
1086 | value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, false); |
1003 | } |
1087 | } |
1004 | 1088 | ||
1005 | // Step |
1089 | // Step 18. Undo move |
1006 | pos.undo_move(move); |
1090 | pos.undo_move(move); |
1007 | 1091 | ||
1008 | assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); |
1092 | assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); |
1009 | 1093 | ||
1010 | // Step |
1094 | // Step 19. Check for a new best move |
1011 | // Finished searching the move. If a stop occurred, the return value of |
1095 | // Finished searching the move. If a stop occurred, the return value of |
1012 | // the search cannot be trusted, and we return immediately without |
1096 | // the search cannot be trusted, and we return immediately without |
1013 | // updating best move, PV and TT. |
1097 | // updating best move, PV and TT. |
1014 | if (Threads.stop.load(std::memory_order_relaxed)) |
1098 | if (Threads.stop.load(std::memory_order_relaxed)) |
1015 | return VALUE_ZERO; |
1099 | return VALUE_ZERO; |
Line 1017... | Line 1101... | ||
1017 | if (rootNode) |
1101 | if (rootNode) |
1018 | { |
1102 | { |
1019 | RootMove& rm = *std::find(thisThread->rootMoves.begin(), |
1103 | RootMove& rm = *std::find(thisThread->rootMoves.begin(), |
1020 | thisThread->rootMoves.end(), move); |
1104 | thisThread->rootMoves.end(), move); |
1021 | 1105 | ||
1022 | // PV move or new best move |
1106 | // PV move or new best move? |
1023 | if (moveCount == 1 || value > alpha) |
1107 | if (moveCount == 1 || value > alpha) |
1024 | { |
1108 | { |
1025 | rm.score = value; |
1109 | rm.score = value; |
1026 | rm.selDepth = thisThread->selDepth; |
1110 | rm.selDepth = thisThread->selDepth; |
1027 | rm.pv.resize(1); |
1111 | rm.pv.resize(1); |
Line 1058... | Line 1142... | ||
1058 | if (PvNode && value < beta) // Update alpha! Always alpha < beta |
1142 | if (PvNode && value < beta) // Update alpha! Always alpha < beta |
1059 | alpha = value; |
1143 | alpha = value; |
1060 | else |
1144 | else |
1061 | { |
1145 | { |
1062 | assert(value >= beta); // Fail high |
1146 | assert(value >= beta); // Fail high |
- | 1147 | ss->statScore = 0; |
|
1063 | break; |
1148 | break; |
1064 | } |
1149 | } |
1065 | } |
1150 | } |
1066 | } |
1151 | } |
1067 | 1152 | ||
- | 1153 | if (move != bestMove) |
|
- | 1154 | { |
|
1068 |
|
1155 | if (captureOrPromotion && captureCount < 32) |
1069 |
|
1156 | capturesSearched[captureCount++] = move; |
- | 1157 | ||
1070 |
|
1158 | else if (!captureOrPromotion && quietCount < 64) |
1071 |
|
1159 | quietsSearched[quietCount++] = move; |
- | 1160 | } |
|
1072 | } |
1161 | } |
1073 | 1162 | ||
1074 | // The following condition would detect a stop only after move loop has been |
1163 | // The following condition would detect a stop only after move loop has been |
1075 | // completed. But in this case bestValue is valid because we have fully |
1164 | // completed. But in this case bestValue is valid because we have fully |
1076 | // searched our subtree, and we can anyhow save the result in TT. |
1165 | // searched our subtree, and we can anyhow save the result in TT. |
Line 1091... | Line 1180... | ||
1091 | : inCheck ? mated_in(ss->ply) : VALUE_DRAW; |
1180 | : inCheck ? mated_in(ss->ply) : VALUE_DRAW; |
1092 | else if (bestMove) |
1181 | else if (bestMove) |
1093 | { |
1182 | { |
1094 | // Quiet best move: update move sorting heuristics |
1183 | // Quiet best move: update move sorting heuristics |
1095 | if (!pos.capture_or_promotion(bestMove)) |
1184 | if (!pos.capture_or_promotion(bestMove)) |
1096 |
|
1185 | update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount, |
- | 1186 | stat_bonus(depth + (bestValue > beta + PawnValueMg ? ONE_PLY : DEPTH_ZERO))); |
|
1097 | else |
1187 | |
1098 |
|
1188 | update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + ONE_PLY)); |
1099 | 1189 | ||
1100 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
1190 | // Extra penalty for a quiet TT move in previous ply when it gets refuted |
1101 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
1191 | if ((ss-1)->moveCount == 1 && !pos.captured_piece()) |
1102 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); |
1192 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); |
1103 | } |
1193 | } |
1104 | // Bonus for prior countermove that caused the fail low |
1194 | // Bonus for prior countermove that caused the fail low |
1105 | else if ( |
1195 | else if ( (depth >= 3 * ONE_PLY || PvNode) |
1106 | && !pos.captured_piece() |
1196 | && !pos.captured_piece() |
1107 | && is_ok((ss-1)->currentMove)) |
1197 | && is_ok((ss-1)->currentMove)) |
1108 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth)); |
1198 | update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth)); |
1109 | 1199 | ||
1110 | if (PvNode) |
1200 | if (PvNode) |
Line 1112... | Line 1202... | ||
1112 | 1202 | ||
1113 | if (!excludedMove) |
1203 | if (!excludedMove) |
1114 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
1204 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
1115 | bestValue >= beta ? BOUND_LOWER : |
1205 | bestValue >= beta ? BOUND_LOWER : |
1116 | PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, |
1206 | PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, |
1117 | depth, bestMove, |
1207 | depth, bestMove, pureStaticEval); |
1118 | 1208 | ||
1119 | assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); |
1209 | assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); |
1120 | 1210 | ||
1121 | return bestValue; |
1211 | return bestValue; |
1122 | } |
1212 | } |
1123 | 1213 | ||
1124 | 1214 | ||
1125 | // qsearch() is the quiescence search function, which is called by the main |
1215 | // qsearch() is the quiescence search function, which is called by the main |
1126 | // search function with depth zero, or recursively with depth less than ONE_PLY. |
1216 | // search function with depth zero, or recursively with depth less than ONE_PLY. |
1127 | - | ||
1128 | template <NodeType |
1217 | template <NodeType NT> |
1129 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) { |
1218 | Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) { |
1130 | 1219 | ||
1131 |
|
1220 | constexpr bool PvNode = NT == PV; |
1132 | 1221 | ||
1133 | assert(InCheck == bool(pos.checkers())); |
- | |
1134 | assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); |
1222 | assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); |
1135 | assert(PvNode || (alpha == beta - 1)); |
1223 | assert(PvNode || (alpha == beta - 1)); |
1136 | assert(depth <= DEPTH_ZERO); |
1224 | assert(depth <= DEPTH_ZERO); |
1137 | assert(depth / ONE_PLY * ONE_PLY == depth); |
1225 | assert(depth / ONE_PLY * ONE_PLY == depth); |
1138 | 1226 | ||
1139 | Move pv[MAX_PLY+1]; |
1227 | Move pv[MAX_PLY+1]; |
1140 | StateInfo st; |
1228 | StateInfo st; |
1141 | TTEntry* tte; |
1229 | TTEntry* tte; |
1142 | Key posKey; |
1230 | Key posKey; |
1143 | Move ttMove, move, bestMove; |
1231 | Move ttMove, move, bestMove; |
1144 | Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; |
- | |
1145 | bool ttHit, givesCheck, evasionPrunable; |
- | |
1146 | Depth ttDepth; |
1232 | Depth ttDepth; |
- | 1233 | Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; |
|
- | 1234 | bool ttHit, inCheck, givesCheck, evasionPrunable; |
|
1147 | int moveCount; |
1235 | int moveCount; |
1148 | 1236 | ||
1149 | if (PvNode) |
1237 | if (PvNode) |
1150 | { |
1238 | { |
1151 | oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves |
1239 | oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves |
1152 | (ss+1)->pv = pv; |
1240 | (ss+1)->pv = pv; |
1153 | ss->pv[0] = MOVE_NONE; |
1241 | ss->pv[0] = MOVE_NONE; |
1154 | } |
1242 | } |
1155 | 1243 | ||
1156 |
|
1244 | Thread* thisThread = pos.this_thread(); |
1157 | (ss+1)->ply = ss->ply + 1; |
1245 | (ss+1)->ply = ss->ply + 1; |
- | 1246 | ss->currentMove = bestMove = MOVE_NONE; |
|
- | 1247 | ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; |
|
- | 1248 | inCheck = pos.checkers(); |
|
1158 | moveCount = 0; |
1249 | moveCount = 0; |
1159 | 1250 | ||
1160 | // Check for an |
1251 | // Check for an immediate draw or maximum ply reached |
- | 1252 | if ( pos.is_draw(ss->ply) |
|
1161 |
|
1253 | || ss->ply >= MAX_PLY) |
1162 | return ss->ply >= MAX_PLY && ! |
1254 | return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : VALUE_DRAW; |
1163 | 1255 | ||
1164 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
1256 | assert(0 <= ss->ply && ss->ply < MAX_PLY); |
1165 | 1257 | ||
1166 | // Decide whether or not to include checks: this fixes also the type of |
1258 | // Decide whether or not to include checks: this fixes also the type of |
1167 | // TT entry depth that we are going to use. Note that in qsearch we use |
1259 | // TT entry depth that we are going to use. Note that in qsearch we use |
1168 | // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. |
1260 | // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. |
1169 | ttDepth = |
1261 | ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS |
1170 | : DEPTH_QS_NO_CHECKS; |
1262 | : DEPTH_QS_NO_CHECKS; |
1171 | // Transposition table lookup |
1263 | // Transposition table lookup |
1172 | posKey = pos.key(); |
1264 | posKey = pos.key(); |
1173 | tte = TT.probe(posKey, ttHit); |
1265 | tte = TT.probe(posKey, ttHit); |
1174 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
- | |
1175 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
1266 | ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; |
- | 1267 | ttMove = ttHit ? tte->move() : MOVE_NONE; |
|
1176 | 1268 | ||
1177 | if ( !PvNode |
1269 | if ( !PvNode |
1178 | && ttHit |
1270 | && ttHit |
1179 | && tte->depth() >= ttDepth |
1271 | && tte->depth() >= ttDepth |
1180 | && ttValue != VALUE_NONE // Only in case of TT access race |
1272 | && ttValue != VALUE_NONE // Only in case of TT access race |
1181 | && (ttValue >= beta ? (tte->bound() & |
1273 | && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) |
1182 | : (tte->bound() & |
1274 | : (tte->bound() & BOUND_UPPER))) |
1183 | return ttValue; |
1275 | return ttValue; |
1184 | 1276 | ||
1185 | // Evaluate the position statically |
1277 | // Evaluate the position statically |
1186 | if ( |
1278 | if (inCheck) |
1187 | { |
1279 | { |
1188 | ss->staticEval = VALUE_NONE; |
1280 | ss->staticEval = VALUE_NONE; |
1189 | bestValue = futilityBase = -VALUE_INFINITE; |
1281 | bestValue = futilityBase = -VALUE_INFINITE; |
1190 | } |
1282 | } |
1191 | else |
1283 | else |
Line 1195... | Line 1287... | ||
1195 | // Never assume anything on values stored in TT |
1287 | // Never assume anything on values stored in TT |
1196 | if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) |
1288 | if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) |
1197 | ss->staticEval = bestValue = evaluate(pos); |
1289 | ss->staticEval = bestValue = evaluate(pos); |
1198 | 1290 | ||
1199 | // Can ttValue be used as a better position evaluation? |
1291 | // Can ttValue be used as a better position evaluation? |
1200 | if ( ttValue != VALUE_NONE |
1292 | if ( ttValue != VALUE_NONE |
1201 | && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))) |
1293 | && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))) |
1202 | bestValue = ttValue; |
1294 | bestValue = ttValue; |
1203 | } |
1295 | } |
1204 | else |
1296 | else |
1205 | ss->staticEval = bestValue = |
1297 | ss->staticEval = bestValue = |
Line 1209... | Line 1301... | ||
1209 | // Stand pat. Return immediately if static value is at least beta |
1301 | // Stand pat. Return immediately if static value is at least beta |
1210 | if (bestValue >= beta) |
1302 | if (bestValue >= beta) |
1211 | { |
1303 | { |
1212 | if (!ttHit) |
1304 | if (!ttHit) |
1213 | tte->save(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, |
1305 | tte->save(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, |
1214 | DEPTH_NONE, MOVE_NONE, ss-> |
1306 | DEPTH_NONE, MOVE_NONE, ss->staticEval); |
1215 | 1307 | ||
1216 | return bestValue; |
1308 | return bestValue; |
1217 | } |
1309 | } |
1218 | 1310 | ||
1219 | if (PvNode && bestValue > alpha) |
1311 | if (PvNode && bestValue > alpha) |
1220 | alpha = bestValue; |
1312 | alpha = bestValue; |
1221 | 1313 | ||
1222 | futilityBase = bestValue + 128; |
1314 | futilityBase = bestValue + 128; |
1223 | } |
1315 | } |
- | 1316 | ||
- | 1317 | const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, nullptr, (ss-4)->continuationHistory }; |
|
1224 | 1318 | ||
1225 | // Initialize a MovePicker object for the current position, and prepare |
1319 | // Initialize a MovePicker object for the current position, and prepare |
1226 | // to search the moves. Because the depth is <= 0 here, only captures, |
1320 | // to search the moves. Because the depth is <= 0 here, only captures, |
1227 | // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will |
1321 | // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will |
1228 | // be generated. |
1322 | // be generated. |
1229 | MovePicker mp(pos, ttMove, depth, & |
1323 | MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, |
- | 1324 | &thisThread->captureHistory, |
|
- | 1325 | contHist, |
|
- | 1326 | to_sq((ss-1)->currentMove)); |
|
1230 | 1327 | ||
1231 | // Loop through the moves until no moves remain or a beta cutoff occurs |
1328 | // Loop through the moves until no moves remain or a beta cutoff occurs |
1232 | while ((move = mp.next_move()) != MOVE_NONE) |
1329 | while ((move = mp.next_move()) != MOVE_NONE) |
1233 | { |
1330 | { |
1234 | assert(is_ok(move)); |
1331 | assert(is_ok(move)); |
1235 | 1332 | ||
1236 | givesCheck = type_of(move) == NORMAL && !pos.discovered_check_candidates() |
- | |
1237 | ? pos.check_squares(type_of(pos.moved_piece(move))) & to_sq(move) |
- | |
1238 |
|
1333 | givesCheck = gives_check(pos, move); |
1239 | 1334 | ||
1240 | moveCount++; |
1335 | moveCount++; |
1241 | 1336 | ||
1242 | // Futility pruning |
1337 | // Futility pruning |
1243 | if ( ! |
1338 | if ( !inCheck |
1244 | && !givesCheck |
1339 | && !givesCheck |
1245 | && futilityBase > -VALUE_KNOWN_WIN |
1340 | && futilityBase > -VALUE_KNOWN_WIN |
1246 | && !pos.advanced_pawn_push(move)) |
1341 | && !pos.advanced_pawn_push(move)) |
1247 | { |
1342 | { |
1248 | assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push |
1343 | assert(type_of(move) != ENPASSANT); // Due to !pos.advanced_pawn_push |
Line 1261... | Line 1356... | ||
1261 | continue; |
1356 | continue; |
1262 | } |
1357 | } |
1263 | } |
1358 | } |
1264 | 1359 | ||
1265 | // Detect non-capture evasions that are candidates to be pruned |
1360 | // Detect non-capture evasions that are candidates to be pruned |
1266 | evasionPrunable = |
1361 | evasionPrunable = inCheck |
1267 | && (depth != DEPTH_ZERO || moveCount > 2) |
1362 | && (depth != DEPTH_ZERO || moveCount > 2) |
1268 | && bestValue > VALUE_MATED_IN_MAX_PLY |
1363 | && bestValue > VALUE_MATED_IN_MAX_PLY |
1269 | && !pos.capture(move); |
1364 | && !pos.capture(move); |
1270 | 1365 | ||
1271 | // Don't search moves with negative SEE values |
1366 | // Don't search moves with negative SEE values |
1272 | if ( (! |
1367 | if ( (!inCheck || evasionPrunable) |
1273 | && |
1368 | && !pos.see_ge(move)) |
1274 | continue; |
1369 | continue; |
1275 | 1370 | ||
1276 | // Speculative prefetch as early as possible |
1371 | // Speculative prefetch as early as possible |
1277 | prefetch(TT.first_entry(pos.key_after(move))); |
1372 | prefetch(TT.first_entry(pos.key_after(move))); |
1278 | 1373 | ||
Line 1282... | Line 1377... | ||
1282 | moveCount--; |
1377 | moveCount--; |
1283 | continue; |
1378 | continue; |
1284 | } |
1379 | } |
1285 | 1380 | ||
1286 | ss->currentMove = move; |
1381 | ss->currentMove = move; |
- | 1382 | ss->continuationHistory = &thisThread->continuationHistory[pos.moved_piece(move)][to_sq(move)]; |
|
1287 | 1383 | ||
1288 | // Make and search the move |
1384 | // Make and search the move |
1289 | pos.do_move(move, st, givesCheck); |
1385 | pos.do_move(move, st, givesCheck); |
1290 | value = |
1386 | value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth - ONE_PLY); |
1291 | : -qsearch<NT, false>(pos, ss+1, -beta, -alpha, depth - ONE_PLY); |
- | |
1292 | pos.undo_move(move); |
1387 | pos.undo_move(move); |
1293 | 1388 | ||
1294 | assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); |
1389 | assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); |
1295 | 1390 | ||
1296 | // Check for a new best move |
1391 | // Check for a new best move |
Line 1298... | Line 1393... | ||
1298 | { |
1393 | { |
1299 | bestValue = value; |
1394 | bestValue = value; |
1300 | 1395 | ||
1301 | if (value > alpha) |
1396 | if (value > alpha) |
1302 | { |
1397 | { |
- | 1398 | bestMove = move; |
|
- | 1399 | ||
1303 | if (PvNode) // Update pv even in fail-high case |
1400 | if (PvNode) // Update pv even in fail-high case |
1304 | update_pv(ss->pv, move, (ss+1)->pv); |
1401 | update_pv(ss->pv, move, (ss+1)->pv); |
1305 | 1402 | ||
1306 | if (PvNode && value < beta) // Update alpha here! |
1403 | if (PvNode && value < beta) // Update alpha here! |
1307 | { |
- | |
1308 | alpha = value; |
1404 | alpha = value; |
1309 | bestMove = move; |
- | |
1310 |
|
1405 | else |
1311 |
|
1406 | break; // Fail high |
1312 | { |
- | |
1313 | tte->save(posKey, value_to_tt(value, ss->ply), BOUND_LOWER, |
- | |
1314 | ttDepth, move, ss->staticEval, TT.generation()); |
- | |
1315 | - | ||
1316 | return value; |
- | |
1317 | } |
- | |
1318 | } |
1407 | } |
1319 | } |
1408 | } |
1320 | } |
1409 | } |
1321 | 1410 | ||
1322 | // All legal moves have been searched. A special case: If we're in check |
1411 | // All legal moves have been searched. A special case: If we're in check |
1323 | // and no legal moves were found, it is checkmate. |
1412 | // and no legal moves were found, it is checkmate. |
1324 | if ( |
1413 | if (inCheck && bestValue == -VALUE_INFINITE) |
1325 | return mated_in(ss->ply); // Plies to mate from the root |
1414 | return mated_in(ss->ply); // Plies to mate from the root |
1326 | 1415 | ||
1327 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
1416 | tte->save(posKey, value_to_tt(bestValue, ss->ply), |
- | 1417 | bestValue >= beta ? BOUND_LOWER : |
|
1328 | PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, |
1418 | PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, |
1329 | ttDepth, bestMove, ss-> |
1419 | ttDepth, bestMove, ss->staticEval); |
1330 | 1420 | ||
1331 | assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); |
1421 | assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); |
1332 | 1422 | ||
1333 | return bestValue; |
1423 | return bestValue; |
1334 | } |
1424 | } |
Line 1374... | Line 1464... | ||
1374 | 1464 | ||
1375 | void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { |
1465 | void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { |
1376 | 1466 | ||
1377 | for (int i : {1, 2, 4}) |
1467 | for (int i : {1, 2, 4}) |
1378 | if (is_ok((ss-i)->currentMove)) |
1468 | if (is_ok((ss-i)->currentMove)) |
1379 | (ss-i)-> |
1469 | (*(ss-i)->continuationHistory)[pc][to] << bonus; |
1380 | } |
1470 | } |
1381 | 1471 | ||
1382 | 1472 | ||
1383 | // update_capture_stats() updates move sorting heuristics when a new capture best move is found |
1473 | // update_capture_stats() updates move sorting heuristics when a new capture best move is found |
1384 | 1474 | ||
Line 1386... | Line 1476... | ||
1386 | Move* captures, int captureCnt, int bonus) { |
1476 | Move* captures, int captureCnt, int bonus) { |
1387 | 1477 | ||
1388 | CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; |
1478 | CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; |
1389 | Piece moved_piece = pos.moved_piece(move); |
1479 | Piece moved_piece = pos.moved_piece(move); |
1390 | PieceType captured = type_of(pos.piece_on(to_sq(move))); |
1480 | PieceType captured = type_of(pos.piece_on(to_sq(move))); |
- | 1481 | ||
- | 1482 | if (pos.capture_or_promotion(move)) |
|
1391 | captureHistory |
1483 | captureHistory[moved_piece][to_sq(move)][captured] << bonus; |
1392 | 1484 | ||
1393 | // Decrease all the other played capture moves |
1485 | // Decrease all the other played capture moves |
1394 | for (int i = 0; i < captureCnt; ++i) |
1486 | for (int i = 0; i < captureCnt; ++i) |
1395 | { |
1487 | { |
1396 | moved_piece = pos.moved_piece(captures[i]); |
1488 | moved_piece = pos.moved_piece(captures[i]); |
1397 | captured = type_of(pos.piece_on(to_sq(captures[i]))); |
1489 | captured = type_of(pos.piece_on(to_sq(captures[i]))); |
1398 | captureHistory |
1490 | captureHistory[moved_piece][to_sq(captures[i])][captured] << -bonus; |
1399 | } |
1491 | } |
1400 | } |
1492 | } |
1401 | 1493 | ||
1402 | 1494 | ||
1403 | // |
1495 | // update_quiet_stats() updates move sorting heuristics when a new quiet best move is found |
1404 | 1496 | ||
1405 | void |
1497 | void update_quiet_stats(const Position& pos, Stack* ss, Move move, |
1406 | Move* quiets, int quietsCnt, int bonus) { |
1498 | Move* quiets, int quietsCnt, int bonus) { |
1407 | 1499 | ||
1408 | if (ss->killers[0] != move) |
1500 | if (ss->killers[0] != move) |
1409 | { |
1501 | { |
1410 | ss->killers[1] = ss->killers[0]; |
1502 | ss->killers[1] = ss->killers[0]; |
1411 | ss->killers[0] = move; |
1503 | ss->killers[0] = move; |
1412 | } |
1504 | } |
1413 | 1505 | ||
1414 | Color |
1506 | Color us = pos.side_to_move(); |
1415 | Thread* thisThread = pos.this_thread(); |
1507 | Thread* thisThread = pos.this_thread(); |
1416 | thisThread->mainHistory |
1508 | thisThread->mainHistory[us][from_to(move)] << bonus; |
1417 | update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus); |
1509 | update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus); |
1418 | 1510 | ||
1419 | if (is_ok((ss-1)->currentMove)) |
1511 | if (is_ok((ss-1)->currentMove)) |
1420 | { |
1512 | { |
1421 | Square prevSq = to_sq((ss-1)->currentMove); |
1513 | Square prevSq = to_sq((ss-1)->currentMove); |
Line 1423... | Line 1515... | ||
1423 | } |
1515 | } |
1424 | 1516 | ||
1425 | // Decrease all the other played quiet moves |
1517 | // Decrease all the other played quiet moves |
1426 | for (int i = 0; i < quietsCnt; ++i) |
1518 | for (int i = 0; i < quietsCnt; ++i) |
1427 | { |
1519 | { |
1428 | thisThread->mainHistory |
1520 | thisThread->mainHistory[us][from_to(quiets[i])] << -bonus; |
1429 | update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); |
1521 | update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); |
1430 | } |
1522 | } |
1431 | } |
1523 | } |
1432 | - | ||
1433 | - | ||
1434 | // Is the PV leading to a draw position? Assumes all pv moves are legal |
- | |
1435 | bool pv_is_draw(Position& pos) { |
- | |
1436 | - | ||
1437 | StateInfo st[MAX_PLY]; |
- | |
1438 | auto& pv = pos.this_thread()->rootMoves[0].pv; |
- | |
1439 | - | ||
1440 | for (size_t i = 0; i < pv.size(); ++i) |
- | |
1441 | pos.do_move(pv[i], st[i]); |
- | |
1442 | - | ||
1443 | bool isDraw = pos.is_draw(pv.size()); |
- | |
1444 | - | ||
1445 | for (size_t i = pv.size(); i > 0; --i) |
- | |
1446 | pos.undo_move(pv[i-1]); |
- | |
1447 | - | ||
1448 | return isDraw; |
- | |
1449 | } |
- | |
1450 | - | ||
1451 | 1524 | ||
1452 | // When playing with strength handicap, choose best move among a set of RootMoves |
1525 | // When playing with strength handicap, choose best move among a set of RootMoves |
1453 | // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. |
1526 | // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. |
1454 | 1527 | ||
1455 | Move Skill::pick_best(size_t multiPV) { |
1528 | Move Skill::pick_best(size_t multiPV) { |
Line 1482... | Line 1555... | ||
1482 | return best; |
1555 | return best; |
1483 | } |
1556 | } |
1484 | 1557 | ||
1485 | } // namespace |
1558 | } // namespace |
1486 | 1559 | ||
1487 |
|
1560 | /// MainThread::check_time() is used to print debug info and, more importantly, |
1488 |
|
1561 | /// to detect when we are out of available time and thus stop the search. |
1489 | 1562 | ||
1490 |
|
1563 | void MainThread::check_time() { |
1491 | 1564 | ||
1492 |
|
1565 | if (--callsCnt > 0) |
1493 |
|
1566 | return; |
1494 | 1567 | ||
1495 |
|
1568 | // When using nodes, ensure checking rate is not lower than 0.1% of nodes |
1496 | // otherwise use a default value. |
- | |
1497 |
|
1569 | callsCnt = Limits.nodes ? std::min(1024, int(Limits.nodes / 1024)) : 1024; |
1498 | 1570 | ||
1499 |
|
1571 | static TimePoint lastInfoTime = now(); |
1500 | 1572 | ||
1501 |
|
1573 | TimePoint elapsed = Time.elapsed(); |
1502 |
|
1574 | TimePoint tick = Limits.startTime + elapsed; |
1503 | 1575 | ||
1504 |
|
1576 | if (tick - lastInfoTime >= 1000) |
1505 |
|
1577 | { |
1506 |
|
1578 | lastInfoTime = tick; |
1507 |
|
1579 | dbg_print(); |
1508 |
|
1580 | } |
1509 | 1581 | ||
1510 |
|
1582 | // We should not stop pondering until told so by the GUI |
1511 |
|
1583 | if (Threads.ponder) |
1512 |
|
1584 | return; |
1513 | 1585 | ||
1514 |
|
1586 | if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10) |
1515 |
|
1587 | || (Limits.movetime && elapsed >= Limits.movetime) |
1516 |
|
1588 | || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes)) |
1517 |
|
1589 | Threads.stop = true; |
1518 |
|
1590 | } |
1519 | 1591 | ||
1520 | 1592 | ||
1521 | /// UCI::pv() formats PV information according to the UCI protocol. UCI requires |
1593 | /// UCI::pv() formats PV information according to the UCI protocol. UCI requires |
1522 | /// that all (if any) unsearched PV lines are sent using a previous search score. |
1594 | /// that all (if any) unsearched PV lines are sent using a previous search score. |
1523 | 1595 | ||
1524 | string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { |
1596 | string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { |
1525 | 1597 | ||
1526 | std::stringstream ss; |
1598 | std::stringstream ss; |
1527 |
|
1599 | TimePoint elapsed = Time.elapsed() + 1; |
1528 | const RootMoves& rootMoves = pos.this_thread()->rootMoves; |
1600 | const RootMoves& rootMoves = pos.this_thread()->rootMoves; |
1529 | size_t |
1601 | size_t pvIdx = pos.this_thread()->pvIdx; |
1530 | size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size()); |
1602 | size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size()); |
1531 | uint64_t nodesSearched = Threads.nodes_searched(); |
1603 | uint64_t nodesSearched = Threads.nodes_searched(); |
1532 | uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0); |
1604 | uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0); |
1533 | 1605 | ||
1534 | for (size_t i = 0; i < multiPV; ++i) |
1606 | for (size_t i = 0; i < multiPV; ++i) |
1535 | { |
1607 | { |
1536 | bool updated = (i <= |
1608 | bool updated = (i <= pvIdx && rootMoves[i].score != -VALUE_INFINITE); |
1537 | 1609 | ||
1538 | if (depth == ONE_PLY && !updated) |
1610 | if (depth == ONE_PLY && !updated) |
1539 | continue; |
1611 | continue; |
1540 | 1612 | ||
1541 | Depth d = updated ? depth : depth - ONE_PLY; |
1613 | Depth d = updated ? depth : depth - ONE_PLY; |
1542 | Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; |
1614 | Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; |
1543 | 1615 | ||
1544 | bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; |
1616 | bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; |
1545 | v = tb ? |
1617 | v = tb ? rootMoves[i].tbScore : v; |
1546 | 1618 | ||
1547 | if (ss.rdbuf()->in_avail()) // Not at first line |
1619 | if (ss.rdbuf()->in_avail()) // Not at first line |
1548 | ss << "\n"; |
1620 | ss << "\n"; |
1549 | 1621 | ||
1550 | ss << "info" |
1622 | ss << "info" |
1551 | << " depth " << d / ONE_PLY |
1623 | << " depth " << d / ONE_PLY |
1552 | << " seldepth " << rootMoves[i].selDepth |
1624 | << " seldepth " << rootMoves[i].selDepth |
1553 | << " multipv " << i + 1 |
1625 | << " multipv " << i + 1 |
1554 | << " score " << UCI::value(v); |
1626 | << " score " << UCI::value(v); |
1555 | 1627 | ||
1556 | if (!tb && i == |
1628 | if (!tb && i == pvIdx) |
1557 | ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); |
1629 | ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); |
1558 | 1630 | ||
1559 | ss << " nodes " << nodesSearched |
1631 | ss << " nodes " << nodesSearched |
1560 | << " nps " << nodesSearched * 1000 / elapsed; |
1632 | << " nps " << nodesSearched * 1000 / elapsed; |
1561 | 1633 | ||
Line 1601... | Line 1673... | ||
1601 | 1673 | ||
1602 | pos.undo_move(pv[0]); |
1674 | pos.undo_move(pv[0]); |
1603 | return pv.size() > 1; |
1675 | return pv.size() > 1; |
1604 | } |
1676 | } |
1605 | 1677 | ||
1606 | void Tablebases:: |
1678 | void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { |
1607 | 1679 | ||
1608 | RootInTB = false; |
1680 | RootInTB = false; |
1609 | UseRule50 = Options["Syzygy50MoveRule"]; |
1681 | UseRule50 = bool(Options["Syzygy50MoveRule"]); |
1610 | ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY; |
1682 | ProbeDepth = int(Options["SyzygyProbeDepth"]) * ONE_PLY; |
1611 | Cardinality = Options["SyzygyProbeLimit"]; |
1683 | Cardinality = int(Options["SyzygyProbeLimit"]); |
- | 1684 | bool dtz_available = true; |
|
1612 | 1685 | ||
1613 | // |
1686 | // Tables with fewer pieces than SyzygyProbeLimit are searched with |
- | 1687 | // ProbeDepth == DEPTH_ZERO |
|
1614 | if (Cardinality > MaxCardinality) |
1688 | if (Cardinality > MaxCardinality) |
1615 | { |
1689 | { |
1616 | Cardinality = MaxCardinality; |
1690 | Cardinality = MaxCardinality; |
1617 | ProbeDepth = DEPTH_ZERO; |
1691 | ProbeDepth = DEPTH_ZERO; |
1618 | } |
1692 | } |
1619 | 1693 | ||
1620 | if (Cardinality |
1694 | if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) |
1621 |
|
1695 | { |
- | 1696 | // Rank moves using DTZ tables |
|
- | 1697 | RootInTB = root_probe(pos, rootMoves); |
|
1622 | 1698 | ||
1623 | // Don't filter any moves if the user requested analysis on multiple |
- | |
1624 |
|
1699 | if (!RootInTB) |
1625 |
|
1700 | { |
1626 | - | ||
1627 | // |
1701 | // DTZ tables are missing; try to rank moves using WDL tables |
1628 |
|
1702 | dtz_available = false; |
1629 | RootInTB = |
1703 | RootInTB = root_probe_wdl(pos, rootMoves); |
- | 1704 | } |
|
- | 1705 | } |
|
1630 | 1706 | ||
1631 | if (RootInTB) |
1707 | if (RootInTB) |
1632 | Cardinality = 0; // Do not probe tablebases during the search |
- | |
1633 | - | ||
1634 | else // If DTZ tables are missing, use WDL tables as a fallback |
- | |
1635 | { |
1708 | { |
1636 | // |
1709 | // Sort moves according to TB rank |
1637 |
|
1710 | std::sort(rootMoves.begin(), rootMoves.end(), |
- | 1711 | [](const RootMove &a, const RootMove &b) { return a.tbRank > b.tbRank; } ); |
|
1638 | 1712 | ||
1639 | // |
1713 | // Probe during search only if DTZ is not available and we are winning |
1640 | if ( |
1714 | if (dtz_available || rootMoves[0].tbScore <= VALUE_DRAW) |
1641 | Cardinality = 0; |
1715 | Cardinality = 0; |
1642 | } |
1716 | } |
1643 | - | ||
1644 |
|
1717 | else |
1645 | TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1 |
- | |
1646 | : TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1 |
- | |
1647 | : VALUE_DRAW; |
- | |
1648 | 1718 | { |
|
1649 | // Since root_probe() and root_probe_wdl() dirty the root move scores, |
- | |
1650 | // |
1719 | // Assign the same rank to all moves |
1651 | for ( |
1720 | for (auto& m : rootMoves) |
1652 |
|
1721 | m.tbRank = 0; |
- | 1722 | } |
|
1653 | } |
1723 | } |