LCOV - code coverage report
Current view: top level - Source - moveSort.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 95.1 % 61 58
Test Date: 2026-03-02 16:42:41 Functions: 83.3 % 6 5

            Line data    Source code
       1              : #include "moveSort.hpp"
       2              : 
       3              : #include "logging.hpp"
       4              : #include "searcher.hpp"
       5              : #include "searchConfig.hpp"
       6              : 
       7              : /* Moves are sorted this way
       8              :  * 1°) previous best (from current thread previousBest)
       9              :  * 2°) TT move
      10              :  * --3°) king evasion if in check and king moves--
      11              :  * 4°) prom cap
      12              :  * 5°) good capture (not prom) based on SEE if not in check, based on MVV LVA if in check
      13              :  * 6°) prom
      14              :  * 7°) killer 0, then killer 1, then killer 0 from previous move, then counter
      15              :  * 8°) other quiet based on various history score (from/to, piece/to, CMH)
      16              :  * 9°) bad cap
      17              :  */
      18              : 
      19              : #pragma GCC diagnostic push
      20              : #pragma GCC diagnostic ignored "-Wconversion"
      21              : 
      22              : template<Color C>
      23     27803368 : void MoveSorter::computeScore(Move& m) const {
      24            0 :    assert(isValidMove(m));
      25              :    //std::cout << ToString(m) << std::endl;
      26     27803368 :    if (Move2Score(m) != 0) return; // prob cut may have already computed captures score
      27              :    const MType t = Move2Type(m);
      28              :    assert(isValidMoveType(t));
      29     27798897 :    const Square from = Move2From(m);
      30     27798897 :    assert(isValidSquare(from));
      31     27798897 :    const Square to = Move2To(m);
      32     27798897 :    assert(isValidSquare(to));
      33              : 
      34              :    // apply default score based on type
      35     27798897 :    ScoreType s = MoveScoring[t];
      36              : 
      37              :    // previous root best at root
      38     27798897 :    if (height == 0 && sameMove(context.previousBest, m)){
      39         1223 :       s += 15000;
      40              :    }
      41              :    // TT move
      42     27797674 :    else if (e && sameMove(e->m, m)){
      43       266518 :       s += 14000;
      44              :    }
      45              :    else {
      46              :       // king evasion ///@todo try again ??
      47              :       //if (isInCheck && from == p.king[C]) s += 10000;
      48              : 
      49              :       // capture that are not promotion
      50     27531156 :       if (isCapture(t) && !isPromotion(t)) {
      51      4094861 :          const Piece pp    = PieceTools::getPieceType(p, from);
      52      4094861 :          const Piece ppOpp = (t != T_ep) ? PieceTools::getPieceType(p, to) : P_wp;
      53      4094861 :          assert(pp > 0);
      54      4094861 :          assert(ppOpp > 0);
      55              : 
      56      4094861 :          const std::span<const EvalScore> pst    = EvalConfig::PST[pp - 1];
      57      4094861 :          const std::span<const EvalScore> pstOpp = EvalConfig::PST[ppOpp - 1];
      58              :          // always use PST as a hint
      59      4094861 :          const ScoreType pstScore = (ScaleScore(pst[ColorSquarePstHelper<C>(to)] - pst[ColorSquarePstHelper<C>(from)] + pstOpp[ColorSquarePstHelper<~C>(to)], gp));
      60      4094861 :          s += pstScore/SearchConfig::capPSTScoreDivisor;
      61              : 
      62      4094861 :          if (useSEE && !isInCheck) {
      63      1864855 :             const ScoreType see = Searcher::SEE(p, m);
      64      1864855 :             s += see;
      65              :             // recapture bonus
      66      3618315 :             if (isValidMove(p.lastMove) && isCapture(p.lastMove) && to == Move2To(p.lastMove)) s += 512;
      67              :             // too bad capture are ordered last (-7000)
      68      1864855 :             if (/*see + pstScore < 0 &&*/ see < DynamicConfig::badCapLimit) s -= 2 * MoveScoring[T_capture];
      69              :          }
      70              :          else { // without SEE
      71              :             // recapture (> max MVVLVA value)
      72      4203993 :             if (isValidMove(p.lastMove) && isCapture(p.lastMove) && to == Move2To(p.lastMove)) s += 512;
      73              :             // MVVLVA [0 400] 
      74      2230006 :             s += SearchConfig::capMMLVAMultiplicator * SearchConfig::MvvLvaScores[ppOpp - 1][pp - 1];
      75              :             // cap history (HISTORY_MAX = 1024)
      76      2230006 :             s += context.historyT.historyCap[PieceIdx(p.board_const(from))][to][ppOpp-1] / SearchConfig::capHistoryDivisor;
      77              :          }
      78              :       }
      79              : 
      80              :       // standard moves and castling
      81     23436295 :       else if (t == T_std || isCastling(m)) {
      82     23412994 :          if (sameMove(m, context.killerT.killers[height][0])) s += 1900; // quiet killer
      83     23260688 :          else if (sameMove(m, context.killerT.killers[height][1]))
      84        47712 :             s += 1300; // quiet killer
      85     23212976 :          else if (height > 1 && sameMove(m, context.killerT.killers[height - 2][0]))
      86       134729 :             s += 1700; // quiet killer
      87              :          //else if (height > 1 && sameMove(m, context.killerT.killers[height - 2][1]))
      88              :          //   s += 1400; // quiet killer
      89     66744295 :          else if (isValidMove(p.lastMove) && sameMove(context.counterT.counter[Move2From(p.lastMove)][correctedMove2ToKingDest(p.lastMove)], m)) // in sync with CounterT::update()
      90       222076 :             s += 1500; // quiet counter
      91              :          else {
      92              :             ///@todo give another try to tune those ratio!
      93              :             // History
      94              :             const Square correctedTo = correctedMove2ToKingDest(m);
      95     22856171 :             const Piece pp = p.board_const(from);
      96     22856171 :             s += context.historyT.history[p.c][from][correctedTo] / SearchConfig::quietHistoryDivisor1;     // +/- HISTORY_MAX = 1024
      97     22856171 :             s += context.historyT.historyP[PieceIdx(pp)][correctedTo] / SearchConfig::quietHistoryDivisor2; // +/- HISTORY_MAX = 1024
      98     22856171 :             s += context.getCMHScore(p, from, correctedTo, cmhPtr) / SearchConfig::quietHistoryDivisor3;    // +/- HISTORY_MAX = 1024
      99     22856171 :             if (!isCastling(m)) {
     100              :                // move (safely) leaving threat square from null move search
     101     23820898 :                if (!isInCheck && refutation != INVALIDMINIMOVE && from == correctedMove2ToKingDest(refutation) && Searcher::SEE_GE(p, m, -80)) s += 512;
     102              :                // always use PST to compensate low value history
     103     22855370 :                const std::span<const EvalScore> pst = EvalConfig::PST[Abs(pp) - 1];
     104     22855370 :                s += (ScaleScore(pst[ColorSquarePstHelper<C>(correctedTo)] - pst[ColorSquarePstHelper<C>(from)], gp))/2;
     105              :             }
     106              :          }
     107              :       }
     108              :    }
     109     27798897 :    m = ToMove(from, to, t, (ScoreType)s);
     110              : }
     111              : 
     112              : #pragma GCC diagnostic pop
     113              : 
     114      2336262 : void MoveSorter::score(const Searcher&    context,
     115              :                        MoveList&          moves,
     116              :                        const Position&    p,
     117              :                        const float        gp,
     118              :                        const DepthType    height,
     119              :                        const CMHPtrArray& cmhPtr,
     120              :                        const bool         useSEE,
     121              :                        const bool         isInCheck,
     122              :                        const TT::Entry*   e,
     123              :                        const MiniMove     refutation) {
     124              :    START_TIMER
     125      2336262 :    if (moves.size() < 2) return;
     126              :    const MoveSorter ms(context, p, gp, height, cmhPtr, useSEE, isInCheck, e, refutation);
     127      1938211 :    if (p.c == Co_White) {
     128     16548564 :       for (auto & it : moves) { ms.computeScore<Co_White>(it); }
     129              :    }
     130              :    else {
     131     13193015 :       for (auto & it : moves) { ms.computeScore<Co_Black>(it); }
     132              :    }
     133              :    STOP_AND_SUM_TIMER(MoveScoring)
     134              : }
     135              : 
     136            2 : void MoveSorter::scoreAndSort(const Searcher&    context,
     137              :                               MoveList&          moves,
     138              :                               const Position&    p,
     139              :                               const float        gp,
     140              :                               const DepthType    height,
     141              :                               const CMHPtrArray& cmhPtr,
     142              :                               const bool         useSEE,
     143              :                               const bool         isInCheck,
     144              :                               const TT::Entry*   e,
     145              :                               const MiniMove     refutation) {
     146            2 :    score(context, moves, p, gp, height, cmhPtr, useSEE, isInCheck, e, refutation);
     147              :    sort(moves);
     148            2 : }
     149              : 
     150            0 : void MoveSorter::sort(MoveList& moves) {
     151              :    START_TIMER
     152              :    std::ranges::sort(moves, MoveSortOperator());
     153              :    STOP_AND_SUM_TIMER(MoveSorting)
     154            0 : }
     155              : 
     156     16283053 : const Move* MoveSorter::pickNext(MoveList& moves, size_t& begin, bool skipSort) {
     157     16283053 :    if (moves.begin() + begin == moves.end()) return nullptr;
     158              :    START_TIMER
     159     14949825 :    if(!skipSort){
     160      9938672 :       const auto it = std::min_element(moves.begin() + begin, moves.end(), MoveSortOperator());
     161              :       std::iter_swap(moves.begin() + begin, it);
     162              :    }
     163              :    STOP_AND_SUM_TIMER(MoveSorting)
     164     14949825 :    return &*(moves.begin() + (begin++)); // increment begin !
     165              : }
        

Generated by: LCOV version 2.0-1