Thread* bestThread = this;
if ( !this->easyMovePlayed
&& Options["MultiPV"] == 1
+ && !Limits.depth
&& !Skill(Options["Skill Level"]).enabled()
&& rootMoves[0].pv[0] != MOVE_NONE)
{
void Thread::search() {
- Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
+ Stack stack[MAX_PLY+7], *ss = stack+5; // To allow referencing (ss-5) and (ss+2)
Value bestValue, alpha, beta, delta;
Move easyMove = MOVE_NONE;
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
- std::memset(ss-2, 0, 5 * sizeof(Stack));
+ std::memset(ss-5, 0, 8 * sizeof(Stack));
bestValue = delta = alpha = -VALUE_INFINITE;
beta = VALUE_INFINITE;
multiPV = std::min(multiPV, rootMoves.size());
// Iterative deepening loop until requested to stop or the target depth is reached.
- while (++rootDepth < DEPTH_MAX && !Signals.stop && (!Limits.depth || rootDepth <= Limits.depth))
+ while (++rootDepth < DEPTH_MAX && !Signals.stop && (!Limits.depth || Threads.main()->rootDepth <= Limits.depth))
{
// Set up the new depths for the helper threads skipping on average every
// 2nd ply (using a half-density matrix).
std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1);
if (!mainThread)
- break;
+ continue;
if (Signals.stop)
sync_cout << "info nodes " << Threads.nodes_searched()
// Stop the search if only one legal move is available, or if all
// of the available time has been used, or if we matched an easyMove
// from the previous search and just did a fast verification.
- const bool F[] = { !mainThread->failedLow,
- bestValue >= mainThread->previousScore };
+ const int F[] = { mainThread->failedLow,
+ bestValue - mainThread->previousScore };
- int improvingFactor = 640 - 160*F[0] - 126*F[1] - 124*F[0]*F[1];
+ int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
double unstablePvFactor = 1 + mainThread->bestMoveChanges;
bool doEasyMove = rootMoves[0].pv[0] == easyMove
&& mainThread->bestMoveChanges < 0.03
- && Time.elapsed() > Time.optimum() * 25 / 204;
+ && Time.elapsed() > Time.optimum() * 5 / 42;
if ( rootMoves.size() == 1
- || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 634
+ || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628
|| (mainThread->easyMovePlayed = doEasyMove))
{
// If we are allowed to ponder do not stop the search now but
Value bestValue, value, ttValue, eval, nullValue, futilityValue;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
bool captureOrPromotion, doFullDepthSearch;
+ Piece moved_piece;
int moveCount, quietCount;
// Step 1. Initialize node
assert(0 <= ss->ply && ss->ply < MAX_PLY);
ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
+ ss->counterMoves = nullptr;
(ss+1)->skipEarlyPruning = false;
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
&& pos.non_pawn_material(pos.side_to_move()))
{
ss->currentMove = MOVE_NULL;
+ ss->counterMoves = nullptr;
assert(eval - beta >= 0);
assert((ss-1)->currentMove != MOVE_NONE);
assert((ss-1)->currentMove != MOVE_NULL);
- MovePicker mp(pos, ttMove, thisThread->history, PieceValue[MG][pos.captured_piece_type()]);
+ MovePicker mp(pos, ttMove, PieceValue[MG][pos.captured_piece_type()]);
CheckInfo ci(pos);
while ((move = mp.next_move()) != MOVE_NONE)
if (pos.legal(move, ci.pinned))
{
ss->currentMove = move;
+ ss->counterMoves = &CounterMoveHistory[pos.moved_piece(move)][to_sq(move)];
pos.do_move(move, st, pos.gives_check(move, ci));
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth, !cutNode);
pos.undo_move(move);
moves_loop: // When in check search starts from here
Square prevSq = to_sq((ss-1)->currentMove);
- Square ownPrevSq = to_sq((ss-2)->currentMove);
- Move cm = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq];
- const CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
- const CounterMoveStats& fmh = CounterMoveHistory[pos.piece_on(ownPrevSq)][ownPrevSq];
+ const CounterMoveStats* cmh = (ss-1)->counterMoves;
+ const CounterMoveStats* fmh = (ss-2)->counterMoves;
+ const CounterMoveStats* fmh2 = (ss-4)->counterMoves;
- MovePicker mp(pos, ttMove, depth, thisThread->history, cmh, fmh, cm, ss);
+ MovePicker mp(pos, ttMove, depth, ss);
CheckInfo ci(pos);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
improving = ss->staticEval >= (ss-2)->staticEval
extension = DEPTH_ZERO;
captureOrPromotion = pos.capture_or_promotion(move);
+ moved_piece = pos.moved_piece(move);
givesCheck = type_of(move) == NORMAL && !ci.dcCandidates
? ci.checkSquares[type_of(pos.piece_on(from_sq(move)))] & to_sq(move)
&& moveCount >= FutilityMoveCounts[improving][depth])
continue;
- // History based pruning
+ // Countermoves based pruning
if ( depth <= 4 * ONE_PLY
&& move != ss->killers[0]
- && thisThread->history[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO
- && cmh[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO)
+ && (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
+ && (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO)
+ && (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh)))
continue;
predictedDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO);
}
ss->currentMove = move;
+ ss->counterMoves = &CounterMoveHistory[moved_piece][to_sq(move)];
// Step 14. Make the move
pos.do_move(move, st, givesCheck);
&& !captureOrPromotion)
{
Depth r = reduction<PvNode>(improving, depth, moveCount);
- Value hValue = thisThread->history[pos.piece_on(to_sq(move))][to_sq(move)];
- Value cmhValue = cmh[pos.piece_on(to_sq(move))][to_sq(move)];
+ Value val = thisThread->history[moved_piece][to_sq(move)]
+ + (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ + (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO)
+ + (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO);
- // Increase reduction for cut nodes and moves with a bad history
- if ( (!PvNode && cutNode)
- || (hValue < VALUE_ZERO && cmhValue <= VALUE_ZERO))
+ // Increase reduction for cut nodes
+ if (!PvNode && cutNode)
r += ONE_PLY;
// Decrease/increase reduction for moves with a good/bad history
- int rHist = (hValue + cmhValue) / 14980;
+ int rHist = (val - 10000) / 20000;
r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY);
// Decrease reduction for moves that escape a capture. Filter out
&& !bestMove
&& !inCheck
&& !pos.captured_piece_type()
- && is_ok((ss - 1)->currentMove)
- && is_ok((ss - 2)->currentMove))
+ && is_ok((ss-1)->currentMove))
{
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
- Square prevPrevSq = to_sq((ss - 2)->currentMove);
- CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
- prevCmh.update(pos.piece_on(prevSq), prevSq, bonus);
+ if ((ss-2)->counterMoves)
+ (ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
+
+ if ((ss-3)->counterMoves)
+ (ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
+
+ if ((ss-5)->counterMoves)
+ (ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, bonus);
}
tte->save(posKey, value_to_tt(bestValue, ss->ply),
// to search the moves. Because the depth is <= 0 here, only captures,
// queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
// be generated.
- MovePicker mp(pos, ttMove, depth, pos.this_thread()->history, to_sq((ss-1)->currentMove));
+ MovePicker mp(pos, ttMove, depth, to_sq((ss-1)->currentMove));
CheckInfo ci(pos);
// Loop through the moves until no moves remain or a beta cutoff occurs
Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
Square prevSq = to_sq((ss-1)->currentMove);
- Square ownPrevSq = to_sq((ss-2)->currentMove);
- CounterMoveStats& cmh = CounterMoveHistory[pos.piece_on(prevSq)][prevSq];
- CounterMoveStats& fmh = CounterMoveHistory[pos.piece_on(ownPrevSq)][ownPrevSq];
+ CounterMoveStats* cmh = (ss-1)->counterMoves;
+ CounterMoveStats* fmh = (ss-2)->counterMoves;
+ CounterMoveStats* fmh2 = (ss-4)->counterMoves;
Thread* thisThread = pos.this_thread();
thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus);
- if (is_ok((ss-1)->currentMove))
+ if (cmh)
{
thisThread->counterMoves.update(pos.piece_on(prevSq), prevSq, move);
- cmh.update(pos.moved_piece(move), to_sq(move), bonus);
+ cmh->update(pos.moved_piece(move), to_sq(move), bonus);
}
- if (is_ok((ss-2)->currentMove))
- fmh.update(pos.moved_piece(move), to_sq(move), bonus);
+ if (fmh)
+ fmh->update(pos.moved_piece(move), to_sq(move), bonus);
+
+ if (fmh2)
+ fmh2->update(pos.moved_piece(move), to_sq(move), bonus);
// Decrease all the other played quiet moves
for (int i = 0; i < quietsCnt; ++i)
{
thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
- if (is_ok((ss-1)->currentMove))
- cmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
+ if (cmh)
+ cmh->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
- if (is_ok((ss-2)->currentMove))
- fmh.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
+ if (fmh)
+ fmh->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
+
+ if (fmh2)
+ fmh2->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus);
}
// Extra penalty for a quiet TT move in previous ply when it gets refuted
- if ( (ss-1)->moveCount == 1
- && !pos.captured_piece_type()
- && is_ok((ss-2)->currentMove))
+ if ((ss-1)->moveCount == 1 && !pos.captured_piece_type())
{
- Square prevPrevSq = to_sq((ss-2)->currentMove);
- CounterMoveStats& prevCmh = CounterMoveHistory[pos.piece_on(prevPrevSq)][prevPrevSq];
- prevCmh.update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
+ if ((ss-2)->counterMoves)
+ (ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
+
+ if ((ss-3)->counterMoves)
+ (ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
+
+ if ((ss-5)->counterMoves)
+ (ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY);
}
}