const int skipPhase[] = { 0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7 };
// Razoring and futility margin based on depth
- const int razor_margin[4] = { 483, 570, 603, 554 };
+ // razor_margin[0] is unused as long as depth >= ONE_PLY in search
+ const int razor_margin[] = { 0, 570, 603, 554 };
Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
// Futility and reductions lookup tables, initialized at startup
int FutilityMoveCounts[2][16]; // [improving][depth]
int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber]
+ // Threshold used for countermoves based pruning
+ const int CounterMovePruneThreshold = 0;
+
template <bool PvNode> Depth reduction(bool i, Depth d, int mn) {
return Reductions[PvNode][i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] * ONE_PLY;
}
// History and stats update bonus, based on depth
- Value stat_bonus(Depth depth) {
+ int stat_bonus(Depth depth) {
int d = depth / ONE_PLY ;
- return d > 17 ? VALUE_ZERO : Value(d * d + 2 * d - 2);
+ return d > 17 ? 0 : d * d + 2 * d - 2;
}
// Skill structure is used to implement strength limit
Value value_to_tt(Value v, int ply);
Value value_from_tt(Value v, int ply);
void update_pv(Move* pv, Move move, Move* childPv);
- void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus);
- void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, Value bonus);
+ void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus);
+ void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
void check_time();
} // namespace
for (int d = 0; d < 16; ++d)
{
- FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8));
- FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8));
+ FutilityMoveCounts[0][d] = int(2.4 + 0.74 * pow(d, 1.78));
+ FutilityMoveCounts[1][d] = int(5.0 + 1.00 * pow(d, 2.00));
}
}
th->history.clear();
th->counterMoveHistory.clear();
th->resetCalls = true;
+ CounterMoveStats& cm = th->counterMoveHistory[NO_PIECE][0];
+ int* t = &cm[NO_PIECE][0];
+ std::fill(t, t + sizeof(cm), CounterMovePruneThreshold - 1);
}
Threads.main()->previousScore = VALUE_INFINITE;
Thread* thisThread = pos.this_thread();
inCheck = pos.checkers();
moveCount = quietCount = ss->moveCount = 0;
- ss->history = VALUE_ZERO;
+ ss->history = 0;
bestValue = -VALUE_INFINITE;
ss->ply = (ss-1)->ply + 1;
if (thisThread->resetCalls.load(std::memory_order_relaxed))
{
thisThread->resetCalls = false;
+
// At low node count increase the checking rate to about 0.1% of nodes
// otherwise use a default value.
- thisThread->callsCnt = Limits.nodes ? std::min((int64_t)4096, Limits.nodes / 1024)
+ thisThread->callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024))
: 4096;
}
// Penalty for a quiet ttMove that fails low
else if (!pos.capture_or_promotion(ttMove))
{
- Value penalty = -stat_bonus(depth);
+ int penalty = -stat_bonus(depth);
thisThread->history.update(pos.side_to_move(), ttMove, penalty);
update_cm_stats(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty);
}
const CounterMoveStats& cmh = *(ss-1)->counterMoves;
const CounterMoveStats& fmh = *(ss-2)->counterMoves;
const CounterMoveStats& fm2 = *(ss-4)->counterMoves;
- const bool cm_ok = is_ok((ss-1)->currentMove);
- const bool fm_ok = is_ok((ss-2)->currentMove);
- const bool f2_ok = is_ok((ss-4)->currentMove);
MovePicker mp(pos, ttMove, depth, ss);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
if (value < rBeta)
extension = ONE_PLY;
}
- else if ( givesCheck
+ else if ( givesCheck
&& !moveCountPruning
&& pos.see_ge(move, VALUE_ZERO))
extension = ONE_PLY;
{
if ( !captureOrPromotion
&& !givesCheck
- && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= 5000))
+ && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= Value(5000)))
{
// Move count based pruning
- if (moveCountPruning) {
+ if (moveCountPruning)
+ {
skipQuiets = true;
continue;
}
// Countermoves based pruning
if ( lmrDepth < 3
- && ((cmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok)
- && ((fmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok)
- && ((fm2[moved_piece][to_sq(move)] < VALUE_ZERO) || !f2_ok || (cm_ok && fm_ok)))
+ && (cmh[moved_piece][to_sq(move)] < CounterMovePruneThreshold)
+ && (fmh[moved_piece][to_sq(move)] < CounterMovePruneThreshold))
continue;
// Futility pruning: parent node
- 4000; // Correction factor
// Decrease/increase reduction by comparing opponent's stat score
- if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO)
+ if (ss->history > 0 && (ss-1)->history < 0)
r -= ONE_PLY;
- else if (ss->history < VALUE_ZERO && (ss-1)->history > VALUE_ZERO)
+ else if (ss->history < 0 && (ss-1)->history > 0)
r += ONE_PLY;
// Decrease/increase reduction for moves with a good/bad history
// Bonus for prior countermove that caused the fail low
else if ( depth >= 3 * ONE_PLY
&& !pos.captured_piece()
- && cm_ok)
+ && is_ok((ss-1)->currentMove))
update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth));
- if(!excludedMove)
+ if (!excludedMove)
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());
+ bestValue >= beta ? BOUND_LOWER :
+ PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
+ depth, bestMove, ss->staticEval, TT.generation());
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
// update_cm_stats() updates countermove and follow-up move history
- void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) {
+ void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus) {
for (int i : {1, 2, 4})
if (is_ok((ss-i)->currentMove))
// update_stats() updates move sorting heuristics when a new quiet best move is found
void update_stats(const Position& pos, Stack* ss, Move move,
- Move* quiets, int quietsCnt, Value bonus) {
+ Move* quiets, int quietsCnt, int bonus) {
if (ss->killers[0] != move)
{