#include <algorithm>
#include <cassert>
#include <cmath>
-#include <cstring>
+#include <cstring> // For std::memset
#include <iostream>
#include <sstream>
pos.undo_move(*it);
}
if (Root)
- sync_cout << UCI::format_move(*it, pos.is_chess960()) << ": " << cnt << sync_endl;
+ sync_cout << UCI::move(*it, pos.is_chess960()) << ": " << cnt << sync_endl;
}
return nodes;
}
void Search::think() {
- TimeMgr.init(Limits, RootPos.game_ply(), RootPos.side_to_move());
+ TimeMgr.init(Limits, RootPos.side_to_move(), RootPos.game_ply());
int contempt = Options["Contempt"] * PawnValueEg / 100; // From centipawns
DrawValue[ RootPos.side_to_move()] = VALUE_DRAW - Value(contempt);
{
RootMoves.push_back(MOVE_NONE);
sync_cout << "info depth 0 score "
- << UCI::format_value(RootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
+ << UCI::value(RootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
<< sync_endl;
}
else
RootPos.this_thread()->wait_for(Signals.stop);
}
- sync_cout << "bestmove " << UCI::format_move(RootMoves[0].pv[0], RootPos.is_chess960());
+ sync_cout << "bestmove " << UCI::move(RootMoves[0].pv[0], RootPos.is_chess960());
if (RootMoves[0].pv.size() > 1)
- std::cout << " ponder " << UCI::format_move(RootMoves[0].pv[1], RootPos.is_chess960());
+ std::cout << " ponder " << UCI::move(RootMoves[0].pv[1], RootPos.is_chess960());
std::cout << sync_endl;
}
Move pv[MAX_PLY+1], quietsSearched[64];
StateInfo st;
- const TTEntry *tte;
+ TTEntry* tte;
SplitPoint* splitPoint;
Key posKey;
Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth, predictedDepth;
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;
bestMove = splitPoint->bestMove;
bestValue = splitPoint->bestValue;
tte = NULL;
+ ttHit = false;
ttMove = excludedMove = MOVE_NONE;
ttValue = VALUE_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();
- 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;
// At non-PV nodes we check for a fail high/low. We don't probe at PV nodes
if ( !PvNode
- && tte
+ && ttHit
&& tte->depth() >= depth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
: v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply
: VALUE_DRAW + 2 * v * drawScore;
- TT.store(posKey, value_to_tt(value, ss->ply), BOUND_EXACT,
- std::min(DEPTH_MAX - ONE_PLY, depth + 6 * ONE_PLY),
- MOVE_NONE, VALUE_NONE);
+ 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());
return value;
}
goto moves_loop;
}
- else if (tte)
+ else if (ttHit)
{
// Never assume anything on values stored in TT
if ((ss->staticEval = eval = tte->eval_value()) == VALUE_NONE)
eval = ss->staticEval =
(ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval + 2 * Eval::Tempo;
- 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 (ss->skipEarlyPruning)
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth and value
- Depth R = (3 + depth / 4 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY;
+ Depth R = ((823 + 67 * depth) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY;
pos.do_null_move(st);
(ss+1)->skipEarlyPruning = true;
search<PvNode ? PV : NonPV, false>(pos, ss, alpha, beta, d / 2, true);
ss->skipEarlyPruning = false;
- tte = TT.probe(posKey);
- ttMove = tte ? tte->move() : MOVE_NONE;
+ tte = TT.probe(posKey, ttHit);
+ ttMove = ttHit ? tte->move() : MOVE_NONE;
}
moves_loop: // When in check and at SpNode search starts from here
if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
sync_cout << "info depth " << depth / ONE_PLY
- << " currmove " << UCI::format_move(move, pos.is_chess960())
+ << " currmove " << UCI::move(move, pos.is_chess960())
<< " currmovenumber " << moveCount + PVIdx << sync_endl;
}
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());
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
Move pv[MAX_PLY+1];
StateInfo st;
- const TTEntry* tte;
+ TTEntry* tte;
Key posKey;
Move ttMove, move, bestMove;
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
- bool givesCheck, evasionPrunable;
+ bool ttHit, givesCheck, evasionPrunable;
Depth ttDepth;
if (PvNode)
// Transposition table lookup
posKey = pos.key();
- 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;
if ( !PvNode
- && tte
+ && ttHit
&& tte->depth() >= ttDepth
&& ttValue != VALUE_NONE // Only in case of TT access race
&& (ttValue >= beta ? (tte->bound() & BOUND_LOWER)
}
else
{
- if (tte)
+ if (ttHit)
{
// Never assume anything on values stored in TT
if ((ss->staticEval = bestValue = tte->eval_value()) == VALUE_NONE)
// Stand pat. Return immediately if static value is at least beta
if (bestValue >= beta)
{
- 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());
return bestValue;
}
}
else // Fail high
{
- 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());
return value;
}
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());
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
ss << "info depth " << d / ONE_PLY
<< " seldepth " << selDepth
<< " multipv " << i + 1
- << " score " << ((!tb && i == PVIdx) ? UCI::format_value(v, alpha, beta) : UCI::format_value(v))
- << " nodes " << pos.nodes_searched()
+ << " score " << UCI::value(v);
+
+ if (!tb && i == PVIdx)
+ ss << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
+
+ ss << " nodes " << pos.nodes_searched()
<< " nps " << pos.nodes_searched() * 1000 / elapsed
<< " tbhits " << TB::Hits
<< " time " << elapsed
<< " pv";
for (size_t j = 0; j < RootMoves[i].pv.size(); ++j)
- ss << " " << UCI::format_move(RootMoves[i].pv[j], pos.is_chess960());
+ ss << " " << UCI::move(RootMoves[i].pv[j], pos.is_chess960());
}
return ss.str();
void RootMove::insert_pv_in_tt(Position& pos) {
StateInfo state[MAX_PLY], *st = state;
- const TTEntry* tte;
size_t idx = 0;
for ( ; idx < pv.size(); ++idx)
{
- tte = TT.probe(pos.key());
+ bool ttHit;
+ TTEntry* tte = TT.probe(pos.key(), ttHit);
- 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());
assert(MoveList<LEGAL>(pos).contains(pv[idx]));