Move best = MOVE_NONE;
};
- Value DrawValue[COLOR_NB];
-
template <NodeType NT>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning);
TT.new_search();
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
- DrawValue[ us] = VALUE_DRAW - Value(contempt);
- DrawValue[~us] = VALUE_DRAW + Value(contempt);
+
+ Eval::Contempt = (us == WHITE ? make_score(contempt, contempt / 2)
+ : -make_score(contempt, contempt / 2));
if (rootMoves.empty())
{
int improvingFactor = std::max(229, std::min(715, 357 + 119 * F[0] - 6 * F[1]));
Color us = rootPos.side_to_move();
- bool thinkHard = DrawValue[us] == bestValue
+ bool thinkHard = bestValue == VALUE_DRAW
&& Limits.time[us] - Time.elapsed() > Limits.time[~us]
&& ::pv_is_draw(rootPos);
{
// Step 2. Check for aborted search and immediate draw
if (Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
- return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
- : DrawValue[pos.side_to_move()];
+ return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : VALUE_DRAW;
// Step 3. Mate distance pruning. Even if we mate at the next move our score
// would be at best mate_in(ss->ply+1), but if alpha is already bigger because
// search to overwrite a previous full search TT value, so we use a different
// position key in case of an excluded move.
excludedMove = ss->excludedMove;
- posKey = pos.key() ^ Key(excludedMove);
+ posKey = pos.key() ^ Key(excludedMove << 16); // isn't a very good hash
tte = TT.probe(posKey, ttHit);
ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
ttMove = rootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
ss->staticEval, TT.generation());
}
- if (skipEarlyPruning)
+ if (skipEarlyPruning || !pos.non_pawn_material(pos.side_to_move()))
goto moves_loop;
// Step 6. Razoring (skipped when in check)
if ( !rootNode
&& depth < 7 * ONE_PLY
&& eval - futility_margin(depth) >= beta
- && eval < VALUE_KNOWN_WIN // Do not return unproven wins
- && pos.non_pawn_material(pos.side_to_move()))
+ && eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
// Step 8. Null move search with verification search (is omitted in PV nodes)
if ( !PvNode
&& eval >= beta
&& ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
- && pos.non_pawn_material(pos.side_to_move()))
+ && (ss->ply >= thisThread->nmp_ply || ss->ply % 2 == thisThread->pair))
{
assert(eval - beta >= 0);
return nullValue;
// Do verification search at high depths
+ R += ONE_PLY;
+ // disable null move pruning for side to move for the first part of the remaining search tree
+ int nmp_ply = thisThread->nmp_ply;
+ int pair = thisThread->pair;
+ thisThread->nmp_ply = ss->ply + 3 * (depth-R) / 4;
+ thisThread->pair = (ss->ply % 2) == 0;
+
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta)
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
+ thisThread->pair = pair;
+ thisThread->nmp_ply = nmp_ply;
if (v >= beta)
return nullValue;
if (!moveCount)
bestValue = excludedMove ? alpha
- : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
+ : inCheck ? mated_in(ss->ply) : VALUE_DRAW;
else if (bestMove)
{
// Quiet best move: update move sorting heuristics
// Check for an instant draw or if the maximum ply has been reached
if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
- return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos)
- : DrawValue[pos.side_to_move()];
+ return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : VALUE_DRAW;
assert(0 <= ss->ply && ss->ply < MAX_PLY);