template <NodeType PvNode>
Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
- template <NodeType PvNode>
- void do_sp_search(SplitPoint* sp, int threadID);
-
template <NodeType PvNode>
Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous);
int64_t nodes;
Move move;
Depth depth, ext, newDepth;
- Value value, evalMargin, alpha, beta;
+ Value value, alpha, beta;
bool isCheck, moveIsCheck, captureOrPromotion, dangerous;
int researchCountFH, researchCountFL;
// Step 5. Evaluate the position statically
// At root we do this only to get reference value for child nodes
- ss->eval = isCheck ? VALUE_NONE : evaluate(pos, evalMargin);
+ ss->evalMargin = VALUE_NONE;
+ ss->eval = isCheck ? VALUE_NONE : evaluate(pos, ss->evalMargin);
// Step 6. Razoring (omitted at root)
// Step 7. Static null move pruning (omitted at root)
}
- // search<>() is the main search function for both PV and non-PV nodes
+ // search<>() is the main search function for both PV and non-PV nodes and for
+ // normal and SplitPoint nodes. When called just after a split point the search
+ // is simpler because we have already probed the hash table, done a null move
+ // search, and searched the first move before splitting, we don't have to repeat
+ // all this work again. 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.
template <NodeType PvNode, bool SplitPoint>
Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
Key posKey;
Move ttMove, move, excludedMove, threatMove;
Depth ext, newDepth;
- Value bestValue, value, evalMargin, oldAlpha;
+ Value bestValue, value, oldAlpha;
Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific
bool isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
bool mateThreat = false;
ttMove = excludedMove = MOVE_NONE;
threatMove = ss->sp->threatMove;
mateThreat = ss->sp->mateThreat;
- goto split_start;
+ goto split_point_start;
}
// Step 1. Initialize node and poll. Polling can abort search
// Step 5. Evaluate the position statically and
// update gain statistics of parent move.
if (isCheck)
- ss->eval = evalMargin = VALUE_NONE;
+ ss->eval = ss->evalMargin = VALUE_NONE;
else if (tte)
{
assert(tte->static_value() != VALUE_NONE);
ss->eval = tte->static_value();
- evalMargin = tte->static_value_margin();
+ ss->evalMargin = tte->static_value_margin();
refinedValue = refine_eval(tte, ss->eval, ply);
}
else
{
- refinedValue = ss->eval = evaluate(pos, evalMargin);
- TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin);
+ refinedValue = ss->eval = evaluate(pos, ss->evalMargin);
+ TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, ss->evalMargin);
}
// Save gain for the parent non-capture move
if (PvNode)
mateThreat = pos.has_mate_threat();
-split_start:
+split_point_start: // At split points actual search starts from here
// Initialize a MovePicker object for the current position
// FIXME currently MovePicker() c'tor is needless called also in SplitPoint
MovePicker& mp = SplitPoint ? *ss->sp->mp : mpBase;
CheckInfo ci(pos);
ss->bestMove = MOVE_NONE;
- singleEvasion = SplitPoint ? false : isCheck && mp.number_of_evasions() == 1;
- futilityBase = SplitPoint ? ss->eval : ss->eval + evalMargin;
+ singleEvasion = !SplitPoint && isCheck && mp.number_of_evasions() == 1;
+ futilityBase = ss->eval + ss->evalMargin;
singularExtensionNode = !SplitPoint
&& depth >= SingularExtensionDepth[PvNode]
&& tte
ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
move = (bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove);
- TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, evalMargin);
+ TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, ss->evalMargin);
// Update killers and history only for non capture moves that fails high
if ( bestValue >= beta
}
- // sp_search() is used to search from a split point. This function is called
- // by each thread working at the split point. It is similar to the normal
- // search() function, but simpler. Because we have already probed the hash
- // table, done a null move search, and searched the first move before
- // 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.
-
- template <NodeType PvNode>
- void do_sp_search(SplitPoint* sp, int threadID) {
-
- assert(threadID >= 0 && threadID < ThreadsMgr.active_threads());
- assert(ThreadsMgr.active_threads() > 1);
-
- Position pos(*sp->pos, threadID);
- SearchStack* ss = sp->sstack[threadID] + 1;
- ss->sp = sp;
-
- search<PvNode, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->ply);
- }
-
-
// connected_moves() tests whether two moves are 'connected' in the sense
// that the first move somehow made the second move possible (for instance
// if the moving piece is the same in both moves). The first move is assumed
threads[threadID].state = THREAD_SEARCHING;
- if (threads[threadID].splitPoint->pvNode)
- do_sp_search<PV>(threads[threadID].splitPoint, threadID);
+ // Here we call search() with SplitPoint template parameter set to true
+ SplitPoint* sp = threads[threadID].splitPoint;
+ Position pos(*sp->pos, threadID);
+ SearchStack* ss = sp->sstack[threadID] + 1;
+ ss->sp = sp;
+
+ if (sp->pvNode)
+ search<PV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->ply);
else
- do_sp_search<NonPV>(threads[threadID].splitPoint, threadID);
+ search<NonPV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->ply);
assert(threads[threadID].state == THREAD_SEARCHING);
// Initialize search stack
init_ss_array(ss, PLY_MAX_PLUS_2);
- ss[0].eval = VALUE_NONE;
+ ss[0].eval = ss[0].evalMargin = VALUE_NONE;
count = 0;
// Generate all legal moves