// Different node types, used as a template parameter
enum NodeType { NonPV, PV };
+ // Sizes and phases of the skip-blocks, used for distributing search depths across the threads
+ const int skipSize[] = { 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
+ const int skipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 };
+
// Razoring and futility margin based on depth
const int razor_margin[4] = { 483, 570, 603, 554 };
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
// History and stats update bonus, based on depth
Value stat_bonus(Depth depth) {
int d = depth / ONE_PLY ;
- return Value(d * d + 2 * d - 2);
+ return d > 17 ? VALUE_ZERO : Value(d * d + 2 * d - 2);
}
// Skill structure is used to implement strength limit
for (int d = 1; d < 64; ++d)
for (int mc = 1; mc < 64; ++mc)
{
- double r = log(d) * log(mc) / 2;
+ double r = log(d) * log(mc) / 1.95;
Reductions[NonPV][imp][d][mc] = int(std::round(r));
Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0);
std::cout << sync_endl;
}
-// Sizes and phases of the skip-blocks, used for distributing search depths across the threads.
-static int skipsize[20] = {1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4};
-static int phase [20] = {0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7};
-// Thread::search() is the main iterative deepening loop. It calls search()
-// repeatedly with increasing depth until the allocated thinking time has been
-// consumed, the user stops the search, or the maximum search depth is reached.
+/// Thread::search() is the main iterative deepening loop. It calls search()
+/// repeatedly with increasing depth until the allocated thinking time has been
+/// consumed, the user stops the search, or the maximum search depth is reached.
void Thread::search() {
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
std::memset(ss-4, 0, 7 * sizeof(Stack));
- for(int i = -4; i < 0; i++)
- (ss+i)->counterMoves = &this->counterMoveHistory[NO_PIECE][0]; // use as sentinel.
+ for(int i = 4; i > 0; i--)
+ (ss-i)->counterMoves = &this->counterMoveHistory[NO_PIECE][0]; // Use as sentinel
bestValue = delta = alpha = -VALUE_INFINITE;
beta = VALUE_INFINITE;
multiPV = std::min(multiPV, rootMoves.size());
- int hIdx = (idx - 1) % 20; // helper index, cycle after 20 threads
-
// Iterative deepening loop until requested to stop or the target depth is reached
while ( (rootDepth += ONE_PLY) < DEPTH_MAX
&& !Signals.stop
&& (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth))
{
- // skip half of the plies in blocks depending on game ply and helper index.
- if (idx && ((rootDepth / ONE_PLY + rootPos.game_ply() + phase[hIdx]) / skipsize[hIdx]) % 2)
- continue;
+ // Distribute search depths across the threads
+ if (idx)
+ {
+ int i = (idx - 1) % 20;
+ if (((rootDepth / ONE_PLY + rootPos.game_ply() + skipPhase[i]) / skipSize[i]) % 2)
+ continue;
+ }
// Age out PV variability metric
if (mainThread)
Depth extension, newDepth;
Value bestValue, value, ttValue, eval;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
- bool captureOrPromotion, doFullDepthSearch, moveCountPruning;
+ bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets;
Piece moved_piece;
int moveCount, quietCount;
moves_loop: // When in check search starts from here
- const CounterMoveStats* cmh = (ss-1)->counterMoves;
- const CounterMoveStats* fmh = (ss-2)->counterMoves;
- const CounterMoveStats* fmh2 = (ss-4)->counterMoves;
+ const CounterMoveStats& cmh = *(ss-1)->counterMoves;
+ const CounterMoveStats& fmh = *(ss-2)->counterMoves;
+ const CounterMoveStats& fm2 = *(ss-4)->counterMoves;
const bool cm_ok = is_ok((ss-1)->currentMove);
const bool fm_ok = is_ok((ss-2)->currentMove);
- const bool fm2_ok = is_ok((ss-4)->currentMove);
+ const bool f2_ok = is_ok((ss-4)->currentMove);
MovePicker mp(pos, ttMove, depth, ss);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
&& !excludedMove // Recursive singular search is not allowed
&& (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY;
+ skipQuiets = false;
// Step 11. Loop through moves
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
- while ((move = mp.next_move()) != MOVE_NONE)
+ while ((move = mp.next_move(skipQuiets)) != MOVE_NONE)
{
assert(is_ok(move));
moveCountPruning = depth < 16 * ONE_PLY
&& moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY];
- // Step 12. Extensions
- // Extend checks
- if ( givesCheck
- && !moveCountPruning
- && pos.see_ge(move, VALUE_ZERO))
- extension = ONE_PLY;
+ // Step 12. Singular and Gives Check Extensions
// Singular extension search. If all moves but one fail low on a search of
// (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move
// ttValue minus a margin then we extend the ttMove.
if ( singularExtensionNode
&& move == ttMove
- && !extension
&& pos.legal(move))
{
Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE);
if (value < rBeta)
extension = ONE_PLY;
}
+ else if ( givesCheck
+ && !moveCountPruning
+ && pos.see_ge(move, VALUE_ZERO))
+ extension = ONE_PLY;
// Calculate new depth for this move
newDepth = depth - ONE_PLY + extension;
&& (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= 5000))
{
// Move count based pruning
- if (moveCountPruning)
+ if (moveCountPruning) {
+ skipQuiets = true;
continue;
+ }
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY;
// Countermoves based pruning
if ( lmrDepth < 3
- && (((*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok)
- && (((*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok)
- && (((*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm2_ok || (cm_ok && fm_ok)))
+ && ((cmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok)
+ && ((fmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok)
+ && ((fm2[moved_piece][to_sq(move)] < VALUE_ZERO) || !f2_ok || (cm_ok && fm_ok)))
continue;
// Futility pruning: parent node
&& !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO))
r -= 2 * ONE_PLY;
- ss->history = (*cmh )[moved_piece][to_sq(move)]
- + (*fmh )[moved_piece][to_sq(move)]
- + (*fmh2)[moved_piece][to_sq(move)]
+ ss->history = cmh[moved_piece][to_sq(move)]
+ + fmh[moved_piece][to_sq(move)]
+ + fm2[moved_piece][to_sq(move)]
+ thisThread->history.get(~pos.side_to_move(), move)
- 4000; // Correction factor
void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) {
for (int i : {1, 2, 4})
- if (is_ok((ss-i)->currentMove))
- (ss-i)->counterMoves->update(pc, s, bonus);
+ if (is_ok((ss-i)->currentMove))
+ (ss-i)->counterMoves->update(pc, s, bonus);
}