void put_threads_to_sleep();
void idle_loop(int threadID, SplitPoint* waitSp);
bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
- Depth depth, int* moves, MovePicker* mp, int master, bool pvNode);
+ Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode);
private:
friend void poll(SearchStack ss[], int ply);
int MultiPV;
// Time managment variables
- int RootMoveNumber, SearchStartTime, MaxNodes, MaxDepth;
- int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
+ int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime;
+ int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
- bool AbortSearch, Quit, AspirationFailLow;
+ bool FirstRootMove, AbortSearch, Quit, AspirationFailLow;
// Show current line?
bool ShowCurrentLine;
/// Local functions
Value id_loop(const Position& pos, Move searchMoves[]);
- Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta);
+ Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr);
Value search_pv(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE);
Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID);
beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE);
}
- // Search to the current depth, rml is updated and sorted
- value = root_search(p, ss, rml, alpha, beta);
+ // Search to the current depth, rml is updated and sorted, alpha and beta could change
+ value = root_search(p, ss, rml, &alpha, &beta);
// Write PV to transposition table, in case the relevant entries have
// been overwritten during the search.
// scheme, prints some information to the standard output and handles
// the fail low/high loops.
- Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value& oldAlpha, Value& beta) {
+ Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr) {
EvalInfo ei;
StateInfo st;
int64_t nodes;
Move move;
Depth depth, ext, newDepth;
- Value value, alpha;
+ Value value, alpha, beta;
bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
int researchCount = 0;
+ alpha = *alphaPtr;
+ beta = *betaPtr;
CheckInfo ci(pos);
- alpha = oldAlpha;
isCheck = pos.is_check();
// Step 1. Initialize node and poll (omitted at root, but I can see no good reason for this, FIXME)
// Step 10. Loop through all moves in the root move list
for (int i = 0; i < rml.move_count() && !AbortSearch; i++)
{
- // This is used by time management and starts from 1
- RootMoveNumber = i + 1;
+ // This is used by time management
+ FirstRootMove = (i == 0);
// Save the current node count before the move is searched
nodes = TM.nodes_searched();
if (current_search_time() >= 1000)
cout << "info currmove " << move
- << " currmovenumber " << RootMoveNumber << endl;
+ << " currmovenumber " << i + 1 << endl;
moveIsCheck = pos.move_is_check(move);
captureOrPromotion = pos.move_is_capture_or_promotion(move);
// Prepare for a research after a fail high, each time with a wider window
researchCount++;
- beta = Min(beta + AspirationDelta * (1 << researchCount), VALUE_INFINITE);
+ *betaPtr = beta = Min(beta + AspirationDelta * (1 << researchCount), VALUE_INFINITE);
} // End of fail high loop
rml.set_move_nodes(i, TM.nodes_searched() - nodes);
assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
+ assert(value < beta);
// Step 17. Check for new best move
if (value <= alpha && i >= MultiPV)
// Print information to the standard output
print_pv_info(pos, ss, alpha, beta, value);
- // Raise alpha to setup proper non-pv search upper bound, note
- // that we can end up with alpha >= beta and so get a fail high.
+ // Raise alpha to setup proper non-pv search upper bound
if (value > alpha)
alpha = value;
}
}
} // PV move or new best move
- assert(alpha >= oldAlpha);
+ assert(alpha >= *alphaPtr);
- AspirationFailLow = (alpha == oldAlpha);
+ AspirationFailLow = (alpha == *alphaPtr);
if (AspirationFailLow && StopOnPonderhit)
StopOnPonderhit = false;
}
// Can we exit fail low loop ?
- if (AbortSearch || alpha > oldAlpha)
+ if (AbortSearch || !AspirationFailLow)
break;
// Prepare for a research after a fail low, each time with a wider window
researchCount++;
- alpha = Max(alpha - AspirationDelta * (1 << researchCount), -VALUE_INFINITE);
- oldAlpha = alpha;
+ *alphaPtr = alpha = Max(alpha - AspirationDelta * (1 << researchCount), -VALUE_INFINITE);
} // Fail low loop
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, &alpha, beta, &bestValue,
- depth, &moveCount, &mp, threadID, true))
+ depth, mateThreat, &moveCount, &mp, threadID, true))
break;
}
Value rbeta = beta - razor_margin(depth);
Value v = qsearch(pos, ss, rbeta-1, rbeta, Depth(0), ply, threadID);
if (v < rbeta)
- return v; //FIXME: Logically should be: return (v + razor_margin(depth));
+ // Logically we should return (v + razor_margin(depth)), but
+ // surprisingly this did slightly weaker in tests.
+ return v;
}
// Step 7. Static null move pruning
&& !AbortSearch
&& !TM.thread_should_stop(threadID)
&& TM.split(pos, ss, ply, NULL, beta, &bestValue,
- depth, &moveCount, &mp, threadID, false))
+ depth, mateThreat, &moveCount, &mp, threadID, false))
break;
}
// splitting, we don't have to repeat all this work in sp_search(). We
// also don't need to store anything to the hash table here: This is taken
// care of after we return from the split point.
- // FIXME: We are currently ignoring mateThreat flag here
void sp_search(SplitPoint* sp, int threadID) {
captureOrPromotion = pos.move_is_capture_or_promotion(move);
// Step 11. Decide the new search depth
- ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, false, &dangerous);
+ ext = extension(pos, move, false, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous);
newDepth = sp->depth - OnePly + ext;
// Update current move
// don't have to repeat all this work in sp_search_pv(). We also don't
// need to store anything to the hash table here: This is taken care of
// after we return from the split point.
- // FIXME: We are ignoring mateThreat flag!
void sp_search_pv(SplitPoint* sp, int threadID) {
captureOrPromotion = pos.move_is_capture_or_promotion(move);
// Step 11. Decide the new search depth
- ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, false, &dangerous);
+ ext = extension(pos, move, true, captureOrPromotion, moveIsCheck, false, sp->mateThreat, &dangerous);
newDepth = sp->depth - OnePly + ext;
// Update current move
if (PonderSearch)
return;
- bool stillAtFirstMove = RootMoveNumber == 1
+ bool stillAtFirstMove = FirstRootMove
&& !AspirationFailLow
&& t > MaxSearchTime + ExtraSearchTime;
int t = current_search_time();
PonderSearch = false;
- bool stillAtFirstMove = RootMoveNumber == 1
+ bool stillAtFirstMove = FirstRootMove
&& !AspirationFailLow
&& t > MaxSearchTime + ExtraSearchTime;
bool ThreadsManager::split(const Position& p, SearchStack* sstck, int ply,
Value* alpha, const Value beta, Value* bestValue,
- Depth depth, int* moves, MovePicker* mp, int master, bool pvNode) {
+ Depth depth, bool mateThreat, int* moves, MovePicker* mp, int master, bool pvNode) {
assert(p.is_ok());
assert(sstck != NULL);
splitPoint->stopRequest = false;
splitPoint->ply = ply;
splitPoint->depth = depth;
+ splitPoint->mateThreat = mateThreat;
splitPoint->alpha = pvNode ? *alpha : beta - 1;
splitPoint->beta = beta;
splitPoint->pvNode = pvNode;