/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
void id_loop(Position& pos);
Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply);
void id_loop(Position& pos);
Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply);
void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt);
string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta);
void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt);
string uci_pv(const Position& pos, Depth depth, Value alpha, Value beta);
- pos.do_move(*it, st, ci, pos.gives_check(*it, ci));
+ pos.do_move(ms.move, st, ci, pos.gives_check(ms.move, ci));
- int cf = Options["Contempt"] * PawnValueEg / 100; // From centipawns
- DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(cf);
- DrawValue[~RootPos.side_to_move()] = VALUE_DRAW + Value(cf);
+ int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
+ DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(contempt);
+ DrawValue[~RootPos.side_to_move()] = VALUE_DRAW + Value(contempt);
- sync_cout << "bestmove " << UCI::format_move(RootMoves[0].pv[0], RootPos.is_chess960())
- << " ponder " << UCI::format_move(RootMoves[0].pv[1], RootPos.is_chess960())
- << sync_endl;
+ sync_cout << "bestmove " << UCI::move(RootMoves[0].pv[0], RootPos.is_chess960());
+
+ if (RootMoves[0].pv.size() > 1)
+ std::cout << " ponder " << UCI::move(RootMoves[0].pv[1], RootPos.is_chess960());
+
+ std::cout << sync_endl;
// Save the last iteration's scores before first PV line is searched and
// all the move scores except the (new) PV are set to -VALUE_INFINITE.
// Save the last iteration's scores before first PV line is searched and
// all the move scores except the (new) PV are set to -VALUE_INFINITE.
// MultiPV loop. We perform a full root search for each PV line
for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx)
// MultiPV loop. We perform a full root search for each PV line
for (PVIdx = 0; PVIdx < std::min(multiPV, RootMoves.size()) && !Signals.stop; ++PVIdx)
- alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
- beta = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
+ alpha = std::max(RootMoves[PVIdx].previousScore - delta,-VALUE_INFINITE);
+ beta = std::min(RootMoves[PVIdx].previousScore + delta, VALUE_INFINITE);
SplitPoint* splitPoint;
Key posKey;
Move ttMove, move, excludedMove, bestMove;
SplitPoint* splitPoint;
Key posKey;
Move ttMove, move, excludedMove, bestMove;
Value bestValue, value, ttValue, eval, nullValue, futilityValue;
Value bestValue, value, ttValue, eval, nullValue, futilityValue;
- bool inCheck, givesCheck, singularExtensionNode, improving;
+ bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
bool captureOrPromotion, dangerous, doFullDepthSearch;
int moveCount, quietCount;
bool captureOrPromotion, dangerous, doFullDepthSearch;
int moveCount, quietCount;
splitPoint = ss->splitPoint;
bestMove = splitPoint->bestMove;
bestValue = splitPoint->bestValue;
splitPoint = ss->splitPoint;
bestMove = splitPoint->bestMove;
bestValue = splitPoint->bestValue;
assert(0 <= ss->ply && ss->ply < MAX_PLY);
ss->currentMove = ss->ttMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
assert(0 <= ss->ply && ss->ply < MAX_PLY);
ss->currentMove = ss->ttMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
// TT value, so we use a different position key in case of an excluded move.
excludedMove = ss->excludedMove;
posKey = excludedMove ? pos.exclusion_key() : pos.key();
// TT value, so we use a different position key in case of an excluded move.
excludedMove = ss->excludedMove;
posKey = excludedMove ? pos.exclusion_key() : pos.key();
- tte = TT.probe(posKey);
- ss->ttMove = ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE;
- ttValue = tte ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
+ tte = TT.probe(posKey, ttHit);
+ ss->ttMove = ttMove = RootNode ? RootMoves[PVIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE;
+ ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
&& tte->depth() >= depth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
// If ttMove is quiet, update killers, history, counter move and followup move on TT hit
if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck)
// If ttMove is quiet, update killers, history, counter move and followup move on TT hit
if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck)
- update_stats(pos, ss, ttMove, depth, NULL, 0);
+ update_stats(pos, ss, ttMove, depth, nullptr, 0);
- TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval);
+ tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
if ( !pos.captured_piece_type()
&& ss->staticEval != VALUE_NONE
&& (ss-1)->staticEval != VALUE_NONE
if ( !pos.captured_piece_type()
&& ss->staticEval != VALUE_NONE
&& (ss-1)->staticEval != VALUE_NONE
nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO)
: - search<NonPV, false>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode);
nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO)
: - search<NonPV, false>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode);
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta, DEPTH_ZERO)
: search<NonPV, false>(pos, ss, beta-1, beta, depth-R, false);
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta, DEPTH_ZERO)
: search<NonPV, false>(pos, ss, beta-1, beta, depth-R, false);
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
Value rbeta = std::min(beta + 200, VALUE_INFINITE);
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
Value rbeta = std::min(beta + 200, VALUE_INFINITE);
&& (PvNode || ss->staticEval + 256 >= beta))
{
Depth d = 2 * (depth - 2 * ONE_PLY) - (PvNode ? DEPTH_ZERO : depth / 2);
&& (PvNode || ss->staticEval + 256 >= beta))
{
Depth d = 2 * (depth - 2 * ONE_PLY) - (PvNode ? DEPTH_ZERO : depth / 2);
search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d / 2, true);
search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d / 2, true);
- tte = TT.probe(posKey);
- ttMove = tte ? tte->move() : MOVE_NONE;
+ tte = TT.probe(posKey, ttHit);
+ ttMove = ttHit ? tte->move() : MOVE_NONE;
Signals.firstRootMove = (moveCount == 1);
if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
Signals.firstRootMove = (moveCount == 1);
if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
- sync_cout << "info depth " << depth
- << " currmove " << UCI::format_move(move, pos.is_chess960())
+ sync_cout << "info depth " << depth / ONE_PLY
+ << " currmove " << UCI::move(move, pos.is_chess960())
captureOrPromotion = pos.capture_or_promotion(move);
givesCheck = type_of(move) == NORMAL && !ci.dcCandidates
captureOrPromotion = pos.capture_or_promotion(move);
givesCheck = type_of(move) == NORMAL && !ci.dcCandidates
// 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
// 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
value = search<NonPV, false>(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode);
value = search<NonPV, false>(pos, ss, rBeta - 1, rBeta, depth / 2, cutNode);
ss->reduction = reduction<PvNode>(improving, depth, moveCount);
if ( (!PvNode && cutNode)
ss->reduction = reduction<PvNode>(improving, depth, moveCount);
if ( (!PvNode && cutNode)
ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
ss->reduction = std::max(DEPTH_ZERO, ss->reduction - ONE_PLY);
Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
// parent node fail low with value <= alpha and to try another move.
if (PvNode && (moveCount == 1 || (value > alpha && (RootNode || value < beta))))
{
// parent node fail low with value <= alpha and to try another move.
if (PvNode && (moveCount == 1 || (value > alpha && (RootNode || value < beta))))
{
value = newDepth < ONE_PLY ?
givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
: -qsearch<PV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
value = newDepth < ONE_PLY ?
givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
: -qsearch<PV, false>(pos, ss+1, -beta, -alpha, DEPTH_ZERO)
// We record how often the best move has been changed in each
// iteration. This information is used for time management: When
// We record how often the best move has been changed in each
// iteration. This information is used for time management: When
- if (PvNode && !RootNode)
- {
- update_pv(ss->pv, move, (ss+1)->pv);
- if (SpNode)
- update_pv(splitPoint->ss->pv, move, (ss+1)->pv);
- }
+ if (PvNode && !RootNode) // Update pv even in fail-high case
+ update_pv(SpNode ? splitPoint->ss->pv : ss->pv, move, (ss+1)->pv);
if (PvNode && value < beta) // Update alpha! Always alpha < beta
alpha = SpNode ? splitPoint->alpha = value : value;
if (PvNode && value < beta) // Update alpha! Always alpha < beta
alpha = SpNode ? splitPoint->alpha = value : value;
else if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck)
update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1);
else if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck)
update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1);
- TT.store(posKey, value_to_tt(bestValue, ss->ply),
- bestValue >= beta ? BOUND_LOWER :
- PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
- depth, bestMove, ss->staticEval);
+ tte->save(posKey, value_to_tt(bestValue, ss->ply),
+ bestValue >= beta ? BOUND_LOWER :
+ PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
+ depth, bestMove, ss->staticEval, TT.generation());
Key posKey;
Move ttMove, move, bestMove;
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
Key posKey;
Move ttMove, move, bestMove;
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
- tte = TT.probe(posKey);
- ttMove = tte ? tte->move() : MOVE_NONE;
- ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE;
+ tte = TT.probe(posKey, ttHit);
+ ttMove = ttHit ? tte->move() : MOVE_NONE;
+ ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE;
&& tte->depth() >= ttDepth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
&& tte->depth() >= ttDepth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
- if (!tte)
- TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
- DEPTH_NONE, MOVE_NONE, ss->staticEval);
+ if (!ttHit)
+ tte->save(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
+ DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
update_pv(ss->pv, move, (ss+1)->pv);
if (PvNode && value < beta) // Update alpha here! Always alpha < beta
update_pv(ss->pv, move, (ss+1)->pv);
if (PvNode && value < beta) // Update alpha here! Always alpha < beta
- TT.store(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
- ttDepth, move, ss->staticEval);
+ tte->save(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
+ ttDepth, move, ss->staticEval, TT.generation());
if (InCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
if (InCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
- TT.store(posKey, value_to_tt(bestValue, ss->ply),
- PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
- ttDepth, bestMove, ss->staticEval);
+ tte->save(posKey, value_to_tt(bestValue, ss->ply),
+ PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
+ ttDepth, bestMove, ss->staticEval, TT.generation());
History.update(pos.moved_piece(move), to_sq(move), bonus);
for (int i = 0; i < quietsCnt; ++i)
{
History.update(pos.moved_piece(move), to_sq(move), bonus);
for (int i = 0; i < quietsCnt; ++i)
{
- static RKISS rk;
-
- // PRNG sequence should be not deterministic
- for (int i = Time::now() % 50; i > 0; --i)
- rk.rand<unsigned>();
+ // PRNG sequence should be non-deterministic, so we seed it with the time at init
+ static PRNG rng(Time::now());
// RootMoves are already sorted by score in descending order
int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg);
int weakness = 120 - 2 * level;
// RootMoves are already sorted by score in descending order
int variance = std::min(RootMoves[0].score - RootMoves[candidates - 1].score, PawnValueMg);
int weakness = 120 - 2 * level;
- s += ( weakness * int(RootMoves[0].score - s)
- + variance * (rk.rand<unsigned>() % weakness)) / 128;
+ score += ( weakness * int(RootMoves[0].score - score)
+ + variance * (rng.rand<unsigned>() % weakness)) / 128;
- for (size_t i = 0; i < Threads.size(); ++i)
- if (Threads[i]->maxPly > selDepth)
- selDepth = Threads[i]->maxPly;
+ for (Thread* th : Threads)
+ if (th->maxPly > selDepth)
+ selDepth = th->maxPly;
- << " score " << (i == PVIdx ? UCI::format_value(v, alpha, beta) : UCI::format_value(v))
- << " nodes " << pos.nodes_searched()
+ << " score " << UCI::value(v);
+
+ if (i == PVIdx)
+ ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
+
+ ss << " nodes " << pos.nodes_searched()
<< " nps " << pos.nodes_searched() * 1000 / elapsed
<< " time " << elapsed
<< " pv";
for (size_t j = 0; j < RootMoves[i].pv.size(); ++j)
<< " nps " << pos.nodes_searched() * 1000 / elapsed
<< " time " << elapsed
<< " pv";
for (size_t j = 0; j < RootMoves[i].pv.size(); ++j)
void RootMove::insert_pv_in_tt(Position& pos) {
StateInfo state[MAX_PLY], *st = state;
void RootMove::insert_pv_in_tt(Position& pos) {
StateInfo state[MAX_PLY], *st = state;
- if (!tte || tte->move() != pv[idx]) // Don't overwrite correct entries
- TT.store(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[idx], VALUE_NONE);
+ if (!ttHit || tte->move() != pv[idx]) // Don't overwrite correct entries
+ tte->save(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[idx], VALUE_NONE, TT.generation());
// Pointer 'this_sp' is not null only if we are called from split(), and not
// at the thread creation. This means we are the split point's master.
// Pointer 'this_sp' is not null only if we are called from split(), and not
// at the thread creation. This means we are the split point's master.
sp->slavesMask.reset(idx);
sp->allSlavesSearching = false;
sp->nodes += pos.nodes_searched();
sp->slavesMask.reset(idx);
sp->allSlavesSearching = false;
sp->nodes += pos.nodes_searched();
for (size_t i = 0; i < Threads.size(); ++i)
{
const int size = Threads[i]->splitPointsSize; // Local copy
for (size_t i = 0; i < Threads.size(); ++i)
{
const int size = Threads[i]->splitPointsSize; // Local copy
// If we are master and all slaves have finished then exit idle_loop
if (this_sp && this_sp->slavesMask.none())
{
assert(!searching);
// If we are master and all slaves have finished then exit idle_loop
if (this_sp && this_sp->slavesMask.none())
{
assert(!searching);
break;
}
// If we are not searching, wait for a condition to be signaled instead of
// wasting CPU time polling for work.
if (!searching && !exit)
break;
}
// If we are not searching, wait for a condition to be signaled instead of
// wasting CPU time polling for work.
if (!searching && !exit)
// Loop across all split points and sum accumulated SplitPoint nodes plus
// all the currently active positions nodes.
// Loop across all split points and sum accumulated SplitPoint nodes plus
// all the currently active positions nodes.