diff --git a/src/movepick.cpp b/src/movepick.cpp index 064951893..2a1fb8373 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -216,7 +216,7 @@ Move MovePicker::select(Pred filter) { // This is the most important method of the MovePicker class. We emit one // new pseudo-legal move on every call until there are no more moves left, // picking the move with the highest score from a list of generated moves. -Move MovePicker::next_move(bool skipQuiets) { +Move MovePicker::next_move() { auto quiet_threshold = [](Depth d) { return -3560 * d; }; @@ -322,4 +322,6 @@ top: return Move::none(); // Silence warning } +void MovePicker::skip_quiet_moves() { skipQuiets = true; } + } // namespace Stockfish diff --git a/src/movepick.h b/src/movepick.h index 6ad13397a..f8f84d024 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -146,9 +146,6 @@ using CapturePieceToHistory = Stats; -// PieceToCorrectionHistory is addressed by a move's [piece][to] -using PieceToCorrectionHistory = Stats; - // ContinuationHistory is the combined history of a given pair of moves, usually // the current one given a previous one. The nested history table is based on // PieceToHistory instead of ButterflyBoards. @@ -162,26 +159,32 @@ using PawnHistory = Stats // positions and their search score. It is used to improve the static evaluation // used by some search heuristics. // see https://www.chessprogramming.org/Static_Evaluation_Correction_History +enum CorrHistType { + Pawn, // By color and pawn structure + Major, // By color and positions of major pieces (Queen, Rook) and King + Minor, // By color and positions of minor pieces (Knight, Bishop) and King + NonPawn, // By color and non-pawn material positions + PieceTo, // By [piece][to] move + Continuation, // Combined history of move pairs +}; -// PawnCorrectionHistory is addressed by color and pawn structure -using PawnCorrectionHistory = - Stats; +template +struct CorrHistTypedef { + using type = Stats; +}; -// MajorPieceCorrectionHistory is addressed by color and king/major piece (Queen, Rook) positions -using MajorPieceCorrectionHistory = - Stats; +template<> +struct CorrHistTypedef { + using type = Stats; +}; -// MinorPieceCorrectionHistory is addressed by color and king/minor piece (Knight, Bishop) positions -using MinorPieceCorrectionHistory = - Stats; +template<> +struct CorrHistTypedef { + using type = Stats::type, NOT_USED, PIECE_NB, SQUARE_NB>; +}; -// NonPawnCorrectionHistory is addressed by color and non-pawn material positions -using NonPawnCorrectionHistory = - Stats; - -// ContinuationCorrectionHistory is the combined correction history of a given pair of moves -using ContinuationCorrectionHistory = - Stats; +template +using CorrectionHistory = typename CorrHistTypedef::type; // The MovePicker class is used to pick one pseudo-legal move at a time from the // current position. The most important method is next_move(), which emits one @@ -209,7 +212,8 @@ class MovePicker { const PawnHistory*, int); MovePicker(const Position&, Move, int, const CapturePieceToHistory*); - Move next_move(bool skipQuiets = false); + Move next_move(); + void skip_quiet_moves(); private: template @@ -231,6 +235,7 @@ class MovePicker { int threshold; Depth depth; int ply; + bool skipQuiets = false; ExtMove moves[MAX_MOVES]; }; diff --git a/src/search.cpp b/src/search.cpp index ebaffd02b..74881e20a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -491,9 +491,9 @@ void Search::Worker::iterative_deepening() { { int nodesEffort = rootMoves[0].effort * 100 / std::max(size_t(1), size_t(nodes)); - double fallingEval = (1067 + 223 * (mainThread->bestPreviousAverageScore - bestValue) - + 97 * (mainThread->iterValue[iterIdx] - bestValue)) - / 10000.0; + double fallingEval = (11 + 2 * (mainThread->bestPreviousAverageScore - bestValue) + + (mainThread->iterValue[iterIdx] - bestValue)) + / 100.0; fallingEval = std::clamp(fallingEval, 0.580, 1.667); // If the bestMove is stable over several iterations, reduce time accordingly @@ -993,12 +993,11 @@ moves_loop: // When in check, search starts here value = bestValue; - int moveCount = 0; - bool moveCountPruning = false; + int moveCount = 0; // Step 13. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. - while ((move = mp.next_move(moveCountPruning)) != Move::none()) + while ((move = mp.next_move()) != Move::none()) { assert(move.is_ok()); @@ -1044,7 +1043,8 @@ moves_loop: // When in check, search starts here if (!rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~8 Elo) - moveCountPruning = moveCount >= futility_move_count(improving, depth); + if (moveCount >= futility_move_count(improving, depth)) + mp.skip_quiet_moves(); // Reduced depth of the next LMR search int lmrDepth = newDepth - r; @@ -1845,35 +1845,35 @@ void update_all_stats(const Position& pos, Piece moved_piece = pos.moved_piece(bestMove); PieceType captured; - int quietMoveBonus = stat_bonus(depth); - int quietMoveMalus = stat_malus(depth); + int bonus = stat_bonus(depth); + int malus = stat_malus(depth); if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, quietMoveBonus); + update_quiet_histories(pos, ss, workerThread, bestMove, bonus); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -quietMoveMalus); + update_quiet_histories(pos, ss, workerThread, move, -malus); } else { // Increase stats for the best move in case it was a capture move captured = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[moved_piece][bestMove.to_sq()][captured] << quietMoveBonus; + captureHistory[moved_piece][bestMove.to_sq()][captured] << bonus; } // Extra penalty for a quiet early move that was not a TT move in // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -quietMoveMalus); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { moved_piece = pos.moved_piece(move); captured = type_of(pos.piece_on(move.to_sq())); - captureHistory[moved_piece][move.to_sq()][captured] << -quietMoveMalus; + captureHistory[moved_piece][move.to_sq()][captured] << -malus; } } diff --git a/src/search.h b/src/search.h index 4d50a15c6..d415098bc 100644 --- a/src/search.h +++ b/src/search.h @@ -63,19 +63,19 @@ namespace Search { // shallower and deeper in the tree during the search. Each search thread has // its own array of Stack objects, indexed by the current ply. struct Stack { - Move* pv; - PieceToHistory* continuationHistory; - PieceToCorrectionHistory* continuationCorrectionHistory; - int ply; - Move currentMove; - Move excludedMove; - Value staticEval; - int statScore; - int moveCount; - bool inCheck; - bool ttPv; - bool ttHit; - int cutoffCnt; + Move* pv; + PieceToHistory* continuationHistory; + CorrectionHistory* continuationCorrectionHistory; + int ply; + Move currentMove; + Move excludedMove; + Value staticEval; + int statScore; + int moveCount; + bool inCheck; + bool ttPv; + bool ttHit; + int cutoffCnt; }; @@ -298,11 +298,11 @@ class Worker { ContinuationHistory continuationHistory[2][2]; PawnHistory pawnHistory; - PawnCorrectionHistory pawnCorrectionHistory; - MajorPieceCorrectionHistory majorPieceCorrectionHistory; - MinorPieceCorrectionHistory minorPieceCorrectionHistory; - NonPawnCorrectionHistory nonPawnCorrectionHistory[COLOR_NB]; - ContinuationCorrectionHistory continuationCorrectionHistory; + CorrectionHistory pawnCorrectionHistory; + CorrectionHistory majorPieceCorrectionHistory; + CorrectionHistory minorPieceCorrectionHistory; + CorrectionHistory nonPawnCorrectionHistory[COLOR_NB]; + CorrectionHistory continuationCorrectionHistory; #ifdef USE_MPI struct { diff --git a/src/tt.cpp b/src/tt.cpp index 507507539..75689562d 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -194,19 +194,12 @@ void TranspositionTable::clear(ThreadPool& threads) { // occupation during a search. The hash is x permill full, as per UCI protocol. // Only counts entries which match the current generation. int TranspositionTable::hashfull(int maxAge) const { - int cnt = 0; + int maxAgeInternal = maxAge << GENERATION_BITS; + int cnt = 0; for (int i = 0; i < 1000; ++i) for (int j = 0; j < ClusterSize; ++j) - { - if (table[i].entry[j].is_occupied()) - { - int age = (generation8 >> GENERATION_BITS) - - ((table[i].entry[j].genBound8 & GENERATION_MASK) >> GENERATION_BITS); - if (age < 0) - age += 1 << (8 - GENERATION_BITS); - cnt += age <= maxAge; - } - } + cnt += table[i].entry[j].is_occupied() + && table[i].entry[j].relative_age(generation8) <= maxAgeInternal; return cnt / ClusterSize; }