// Futility lookup tables (initialized at startup) and their access functions
Value FutilityMargins[16][64]; // [depth][moveNumber]
- int FutilityMoveCounts[32]; // [depth]
+ int FutilityMoveCounts[2][32]; // [improving][depth]
inline Value futility_margin(Depth d, int mn) {
// Init futility move count array
for (d = 0; d < 32; d++)
- FutilityMoveCounts[d] = int(3.001 + 0.3 * pow(double(d), 1.8));
+ {
+ FutilityMoveCounts[1][d] = int(3.001 + 0.3 * pow(double(d), 1.8));
+ FutilityMoveCounts[0][d] = d < 5 ? FutilityMoveCounts[1][d]
+ : 3 * FutilityMoveCounts[1][d] / 4;
+ }
}
void id_loop(Position& pos) {
- Stack stack[MAX_PLY_PLUS_2], *ss = stack+1; // To allow referencing (ss-1)
+ Stack stack[MAX_PLY_PLUS_3], *ss = stack+2; // To allow referencing (ss-2)
int depth, prevBestMoveChanges;
Value bestValue, alpha, beta, delta;
- memset(ss-1, 0, 4 * sizeof(Stack));
+ std::memset(ss-2, 0, 5 * sizeof(Stack));
(ss-1)->currentMove = MOVE_NULL; // Hack to skip update gains
depth = BestMoveChanges = 0;
if (Signals.stop)
return;
- // Give some update (without cluttering the UI) before to research
- if (Time::now() - SearchTime > 3000)
+ // When failing high/low give some update (without cluttering
+ // the UI) before to research.
+ if ( (bestValue <= alpha || bestValue >= beta)
+ && Time::now() - SearchTime > 3000)
sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
// In case of failing low/high increase aspiration window and
Depth ext, newDepth;
Value bestValue, value, ttValue;
Value eval, nullValue, futilityValue;
- bool inCheck, givesCheck, pvMove, singularExtensionNode;
+ bool inCheck, givesCheck, pvMove, singularExtensionNode, improving;
bool captureOrPromotion, dangerous, doFullDepthSearch;
int moveCount, quietCount;
// Step 1. Initialize node
Thread* thisThread = pos.this_thread();
- moveCount = quietCount = 0;
inCheck = pos.checkers();
if (SpNode)
goto moves_loop;
}
+ moveCount = quietCount = 0;
bestValue = -VALUE_INFINITE;
ss->currentMove = threatMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
ss->ply = (ss-1)->ply + 1;
Gains.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval);
}
- // Step 6. Razoring (is omitted in PV nodes)
+ // Step 6. Razoring (skipped when in check)
if ( !PvNode
&& depth < 4 * ONE_PLY
&& eval + razor_margin(depth) < beta
return v;
}
- // Step 7. Static null move pruning (is omitted in PV nodes)
+ // Step 7. Static null move pruning (skipped when in check)
// We're betting that the opponent doesn't have a move that will reduce
// the score by more than futility_margin(depth) if we do a null move.
if ( !PvNode
}
}
- // Step 9. ProbCut (is omitted in PV nodes)
+ // Step 9. ProbCut (skipped when in check)
// If we have a very good capture (i.e. SEE > seeValues[captured_piece_type])
// and a reduced search returns a value much above beta, we can (almost) safely
// prune the previous move.
}
}
- // Step 10. Internal iterative deepening
+ // Step 10. Internal iterative deepening (skipped when in check)
if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY)
&& ttMove == MOVE_NONE
&& (PvNode || ss->staticEval + Value(256) >= beta))
Move countermoves[] = { Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].first,
Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].second };
- MovePicker mp(pos, ttMove, depth, History, countermoves, ss, PvNode ? -VALUE_INFINITE : beta);
+ MovePicker mp(pos, ttMove, depth, History, countermoves, ss);
CheckInfo ci(pos);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
+ improving = ss->staticEval >= (ss-2)->staticEval;
singularExtensionNode = !RootNode
&& !SpNode
&& depth >= (PvNode ? 6 * ONE_PLY : 8 * ONE_PLY)
{
Signals.firstRootMove = (moveCount == 1);
- if (thisThread == Threads.main_thread() && Time::now() - SearchTime > 3000)
+ if (thisThread == Threads.main() && Time::now() - SearchTime > 3000)
sync_cout << "info depth " << depth / ONE_PLY
<< " currmove " << move_to_uci(move, pos.is_chess960())
<< " currmovenumber " << moveCount + PVIdx << sync_endl;
{
// Move count based pruning
if ( depth < 16 * ONE_PLY
- && moveCount >= FutilityMoveCounts[depth]
+ && moveCount >= FutilityMoveCounts[improving][depth]
&& (!threatMove || !refutes(pos, move, threatMove)))
{
if (SpNode)
Key posKey;
Move ttMove, move, bestMove;
Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha;
- bool givesCheck, enoughMaterial, evasionPrunable;
+ bool givesCheck, evasionPrunable;
Depth ttDepth;
// To flag BOUND_EXACT a node with eval above alpha and no available moves
{
ss->staticEval = ss->evalMargin = VALUE_NONE;
bestValue = futilityBase = -VALUE_INFINITE;
- enoughMaterial = false;
}
else
{
alpha = bestValue;
futilityBase = ss->staticEval + ss->evalMargin + Value(128);
- enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMg;
}
// Initialize a MovePicker object for the current position, and prepare
&& !InCheck
&& !givesCheck
&& move != ttMove
- && enoughMaterial
&& type_of(move) != PROMOTION
&& !pos.is_passed_pawn_push(move))
{
}
// Detect non-capture evasions that are candidate to be pruned
- evasionPrunable = !PvNode
- && InCheck
+ evasionPrunable = InCheck
&& bestValue > VALUE_MATED_IN_MAX_PLY
&& !pos.is_capture(move)
&& !pos.can_castle(pos.side_to_move());
| (attacks_bb<BISHOP>(m2to, occ) & pos.pieces(color_of(pc), QUEEN, BISHOP));
// Verify attackers are triggered by our move and not already existing
- if (xray && (xray ^ (xray & pos.attacks_from<QUEEN>(m2to))))
+ if (unlikely(xray) && (xray & ~pos.attacks_from<QUEEN>(m2to)))
return true;
}
void RootMove::extract_pv_from_tt(Position& pos) {
- StateInfo state[MAX_PLY_PLUS_2], *st = state;
+ StateInfo state[MAX_PLY_PLUS_3], *st = state;
const TTEntry* tte;
int ply = 0;
Move m = pv[0];
void RootMove::insert_pv_in_tt(Position& pos) {
- StateInfo state[MAX_PLY_PLUS_2], *st = state;
+ StateInfo state[MAX_PLY_PLUS_3], *st = state;
const TTEntry* tte;
int ply = 0;
Threads.mutex.lock();
assert(searching);
+ assert(activeSplitPoint);
SplitPoint* sp = activeSplitPoint;
Threads.mutex.unlock();
- Stack stack[MAX_PLY_PLUS_2], *ss = stack+1; // To allow referencing (ss-1)
+ Stack stack[MAX_PLY_PLUS_3], *ss = stack+2; // To allow referencing (ss-2)
Position pos(*sp->pos, this);
- memcpy(ss-1, sp->ss-1, 4 * sizeof(Stack));
+ std::memcpy(ss-2, sp->ss-2, 5 * sizeof(Stack));
ss->splitPoint = sp;
sp->mutex.lock();