void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCnt, int bonus);
- bool pv_is_draw(Position& pos);
// perft() is our utility to verify move generation. All the leaf nodes up
// to the given depth are generated and counted, and the sum is returned.
Time.init(Limits, us, rootPos.game_ply());
TT.new_search();
- int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
-
- Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
- : -make_score(contempt, contempt / 2));
-
if (rootMoves.empty())
{
rootMoves.emplace_back(MOVE_NONE);
Depth lastBestMoveDepth = DEPTH_ZERO;
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
double timeReduction = 1.0;
+ Color us = rootPos.side_to_move();
std::memset(ss-4, 0, 7 * sizeof(Stack));
for (int i = 4; i > 0; i--)
multiPV = std::min(multiPV, rootMoves.size());
+ int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
+ Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
+ : -make_score(contempt, contempt / 2));
+
// Iterative deepening loop until requested to stop or the target depth is reached
while ( (rootDepth += ONE_PLY) < DEPTH_MAX
&& !Threads.stop
delta = Value(18);
alpha = std::max(rootMoves[PVIdx].previousScore - delta,-VALUE_INFINITE);
beta = std::min(rootMoves[PVIdx].previousScore + delta, VALUE_INFINITE);
+
+ // Adjust contempt based on current situation
+ contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
+ contempt += bestValue > 500 ? 50: // Dynamic contempt
+ bestValue < -500 ? -50:
+ bestValue / 10;
+
+ Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
+ : -make_score(contempt, contempt / 2));
}
// Start with a small aspiration window and, in the case of a fail
bestValue - mainThread->previousScore };
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
- Color us = rootPos.side_to_move();
- bool thinkHard = bestValue == VALUE_DRAW
- && Limits.time[us] - Time.elapsed() > Limits.time[~us]
- && ::pv_is_draw(rootPos);
-
- double unstablePvFactor = 1 + mainThread->bestMoveChanges + thinkHard;
+ double unstablePvFactor = 1 + mainThread->bestMoveChanges;
// if the bestMove is stable over several iterations, reduce time for this move,
// the longer the move has been stable, the more.
// Use part of the gained time from a previous stable move for the current move.
timeReduction = 1;
for (int i : {3, 4, 5})
- if (lastBestMoveDepth * i < completedDepth && !thinkHard)
+ if (lastBestMoveDepth * i < completedDepth )
timeReduction *= 1.3;
unstablePvFactor *= std::pow(mainThread->previousTimeReduction, 0.51) / timeReduction;
if ( rootMoves.size() == 1
- || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 628)
+ || Time.elapsed() > Time.optimum() * unstablePvFactor * improvingFactor / 605)
{
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
Key posKey;
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth;
- Value bestValue, value, ttValue, eval;
+ Value bestValue, value, ttValue, eval, maxValue;
bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
Piece movedPiece;
moveCount = captureCount = quietCount = ss->moveCount = 0;
ss->statScore = 0;
bestValue = -VALUE_INFINITE;
+ maxValue = VALUE_INFINITE;
// Check for the available remaining time
if (thisThread == Threads.main())
&& !pos.can_castle(ANY_CASTLING))
{
TB::ProbeState err;
- TB::WDLScore v = Tablebases::probe_wdl(pos, &err);
+ TB::WDLScore wdl = Tablebases::probe_wdl(pos, &err);
if (err != TB::ProbeState::FAIL)
{
int drawScore = TB::UseRule50 ? 1 : 0;
- value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1
- : v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1
- : VALUE_DRAW + 2 * v * drawScore;
+ value = wdl < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1
+ : wdl > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1
+ : VALUE_DRAW + 2 * wdl * drawScore;
+
+ Bound b = wdl < -drawScore ? BOUND_UPPER
+ : wdl > drawScore ? BOUND_LOWER : BOUND_EXACT;
- tte->save(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
- std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
- MOVE_NONE, VALUE_NONE, TT.generation());
+ if ( b == BOUND_EXACT
+ || (b == BOUND_LOWER ? value >= beta : value <= alpha))
+ {
+ tte->save(posKey, value_to_tt(value, ss->ply), b,
+ std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
+ MOVE_NONE, VALUE_NONE, TT.generation());
- return value;
+ return value;
+ }
+
+ if (PvNode)
+ {
+ if (b == BOUND_LOWER)
+ bestValue = value, alpha = std::max(alpha, bestValue);
+ else
+ maxValue = value;
+ }
}
}
}
&& is_ok((ss-1)->currentMove))
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth));
+ if (PvNode)
+ bestValue = std::min(bestValue, maxValue);
+
if (!excludedMove)
tte->save(posKey, value_to_tt(bestValue, ss->ply),
bestValue >= beta ? BOUND_LOWER :
}
}
-
- // Is the PV leading to a draw position? Assumes all pv moves are legal
- bool pv_is_draw(Position& pos) {
-
- StateInfo st[MAX_PLY];
- auto& pv = pos.this_thread()->rootMoves[0].pv;
-
- for (size_t i = 0; i < pv.size(); ++i)
- pos.do_move(pv[i], st[i]);
-
- bool isDraw = pos.is_draw(pv.size());
-
- for (size_t i = pv.size(); i > 0; --i)
- pos.undo_move(pv[i-1]);
-
- return isDraw;
- }
-
-
// When playing with strength handicap, choose best move among a set of RootMoves
// using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1
: TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1
: VALUE_DRAW;
+
+ // Since root_probe() and root_probe_wdl() dirty the root move scores,
+ // we reset them to -VALUE_INFINITE
+ for (RootMove& rm : rootMoves)
+ rm.score = -VALUE_INFINITE;
}