LCOV - code coverage report
Current view: top level - Source - score.hpp (source / functions) Coverage Total Hit
Test: coverage Lines: 80.0 % 45 36
Test Date: 2026-03-02 16:42:41 Functions: 100.0 % 7 7

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "definition.hpp"
       4              : #include "logging.hpp"
       5              : 
       6              : struct Position;
       7              : 
       8              : #ifdef DEBUG_EVALSYM
       9              : [[nodiscard]] FORCE_FINLINE float fiftyMoveRuleScaling(const uint8_t ){
      10              :    return 1;
      11              : }
      12              : [[nodiscard]] FORCE_FINLINE float fiftyMoveRuleUnScaling(const uint8_t ){
      13              :    return 1;
      14              : }
      15              : #else
      16              : [[nodiscard]] constexpr float fiftyMoveRuleScaling(const uint8_t fifty){
      17      5848870 :    return 1.f - std::max(0, fifty*fifty) / 10000.f;
      18              : }
      19              : #endif
      20              : 
      21              : [[nodiscard]] FORCE_FINLINE ScoreType fiftyScale(const ScoreType s, uint8_t fifty){
      22      4452073 :    return static_cast<ScoreType>(s * fiftyMoveRuleScaling(fifty));
      23              : }
      24              : 
      25              : ///@todo use that to store TT entry independant of fifty scaling
      26              : [[nodiscard]] FORCE_FINLINE ScoreType fiftyUnScale(const ScoreType s, uint8_t fifty){
      27              :    return static_cast<ScoreType>(s / fiftyMoveRuleScaling(fifty));
      28              : }
      29              : 
      30              : // Stockfish trick (two short in one int) is not compatible with evaluation tuning !
      31              : #ifndef WITH_EVALSCORE_AS_INT
      32              : struct EvalScore {
      33              :    array1d<ScoreType, GP_MAX> sc = {0};
      34    112351465 :    EvalScore(const ScoreType mg, const ScoreType eg): sc {mg, eg} {}
      35    212358242 :    EvalScore(const ScoreType s): sc {s, s} {}
      36     23352273 :    EvalScore(): sc {0, 0} {}
      37  11748185726 :    EvalScore(const EvalScore& e): sc {e.sc[MG], e.sc[EG]} {}
      38              :    ~EvalScore() = default;
      39              : 
      40  18978289886 :    FORCE_FINLINE ScoreType&       operator[](const GamePhase g) { return sc[g]; }
      41   9594295432 :    FORCE_FINLINE const ScoreType& operator[](const GamePhase g) const { return sc[g]; }
      42              : 
      43              :    EvalScore& operator*=(const EvalScore& s) {
      44              :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] *= s[g];
      45              :       return *this;
      46              :    }
      47              :    EvalScore& operator/=(const EvalScore& s) {
      48              :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] /= s[g];
      49              :       return *this;
      50              :    }
      51     46457655 :    EvalScore& operator+=(const EvalScore& s) {
      52   7081851315 :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] += s[g];
      53     46457655 :       return *this;
      54              :    }
      55     21828903 :    EvalScore& operator-=(const EvalScore& s) {
      56     65486709 :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] -= s[g];
      57     21828903 :       return *this;
      58              :    }
      59              :    EvalScore operator*(const EvalScore& s) const {
      60              :       EvalScore e(*this);
      61              :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] *= s[g];
      62              :       return e;
      63              :    }
      64              :    EvalScore operator/(const EvalScore& s) const {
      65              :       EvalScore e(*this);
      66              :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] /= s[g];
      67              :       return e;
      68              :    }
      69   2314245873 :    EvalScore operator+(const EvalScore& s) const {
      70              :       EvalScore e(*this);
      71   6947811432 :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] += s[g];
      72   2314245873 :       return e;
      73              :    }
      74     26950231 :    EvalScore operator-(const EvalScore& s) const {
      75              :       EvalScore e(*this);
      76     90414309 :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] -= s[g];
      77     26950231 :       return e;
      78              :    }
      79              :    EvalScore & operator=(const EvalScore& s) {
      80    344008275 :       for (GamePhase g = MG; g < GP_MAX; ++g) { sc[g] = s[g]; }
      81              :       return *this;
      82              :    }
      83              : 
      84              :    EvalScore& operator*=(const ScoreType& s) {
      85              :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] *= s;
      86              :       return *this;
      87              :    }
      88              :    EvalScore& operator/=(const ScoreType& s) {
      89              :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] /= s;
      90              :       return *this;
      91              :    }
      92              :    EvalScore& operator+=(const ScoreType& s) {
      93         6825 :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] += s;
      94              :       return *this;
      95              :    }
      96              :    EvalScore& operator-=(const ScoreType& s) {
      97              :       for (GamePhase g = MG; g < GP_MAX; ++g) sc[g] -= s;
      98              :       return *this;
      99              :    }
     100   9188880226 :    EvalScore operator*(const ScoreType& s) const {
     101              :       EvalScore e(*this);
     102  27736319068 :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] *= s;
     103   9188880226 :       return e;
     104              :    }
     105    210450636 :    EvalScore operator/(const ScoreType& s) const {
     106              :       EvalScore e(*this);
     107    636133716 :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] /= s;
     108    210450636 :       return e;
     109              :    }
     110              :    EvalScore operator+(const ScoreType& s) const {
     111              :       EvalScore e(*this);
     112              :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] += s;
     113              :       return e;
     114              :    }
     115              :    EvalScore operator-(const ScoreType& s) const {
     116              :       EvalScore e(*this);
     117              :       for (GamePhase g = MG; g < GP_MAX; ++g) e[g] -= s;
     118              :       return e;
     119              :    }
     120              :    EvalScore & operator=(const ScoreType& s) {
     121              :       for (GamePhase g = MG; g < GP_MAX; ++g) { sc[g] = s; }
     122              :       return *this;
     123              :    }
     124              : 
     125              :    [[nodiscard]] EvalScore scale(float s_mg, float s_eg) const {
     126              :       EvalScore e(*this);
     127      5578776 :       e[MG] = ScoreType(s_mg * e[MG]);
     128      5578776 :       e[EG] = ScoreType(s_eg * e[EG]);
     129              :       return e;
     130              :    }
     131              : };
     132              : 
     133              : #else
     134              : 
     135              : constexpr auto MakeScore(mg, eg) { return (int)((unsigned int)(eg) << 16) + (mg);}
     136              : constexpr auto MGScore(s)        { return (int16_t)((uint16_t)((unsigned)((s))));}
     137              : constexpr auto EGScore(s)        { return (int16_t)((uint16_t)((unsigned)((s) + 0x8000) >> 16));}
     138              : 
     139              : struct EvalScore {
     140              :    int sc = 0;
     141              :    EvalScore(const ScoreType mg, const ScoreType eg): sc {MakeScore(mg, eg)} {}
     142              :    EvalScore(const ScoreType s): sc {MakeScore(s, s)} {}
     143              :    EvalScore(): sc {0} {}
     144              :    EvalScore(const EvalScore& s): sc {s.sc} {}
     145              :    ~EvalScore() = default;
     146              : 
     147              :    FORCE_FINLINE ScoreType operator[](GamePhase g) const { return g == MG ? MGScore(sc) : EGScore(sc); }
     148              : 
     149              :    EvalScore& operator*=(const EvalScore& s) {
     150              :       sc = MakeScore(MGScore(sc) * MGScore(s.sc), EGScore(sc) * EGScore(s.sc));
     151              :       return *this;
     152              :    }
     153              :    EvalScore& operator/=(const EvalScore& s) {
     154              :       sc = MakeScore(MGScore(sc) / MGScore(s.sc), EGScore(sc) / EGScore(s.sc));
     155              :       return *this;
     156              :    }
     157              :    EvalScore& operator+=(const EvalScore& s) {
     158              :       sc = MakeScore(MGScore(sc) + MGScore(s.sc), EGScore(sc) + EGScore(s.sc));
     159              :       return *this;
     160              :    }
     161              :    EvalScore& operator-=(const EvalScore& s) {
     162              :       sc = MakeScore(MGScore(sc) - MGScore(s.sc), EGScore(sc) - EGScore(s.sc));
     163              :       return *this;
     164              :    }
     165              :    EvalScore operator*(const EvalScore& s) const { return MakeScore(MGScore(sc) * MGScore(s.sc), EGScore(sc) * EGScore(s.sc)); }
     166              :    EvalScore operator/(const EvalScore& s) const { return MakeScore(MGScore(sc) / MGScore(s.sc), EGScore(sc) / EGScore(s.sc)); }
     167              :    EvalScore operator+(const EvalScore& s) const { return MakeScore(MGScore(sc) + MGScore(s.sc), EGScore(sc) + EGScore(s.sc)); }
     168              :    EvalScore operator-(const EvalScore& s) const { return MakeScore(MGScore(sc) - MGScore(s.sc), EGScore(sc) - EGScore(s.sc)); }
     169              :    EvalScore& operator=(const EvalScore& s) { sc = s.sc; return *this; }
     170              : 
     171              :    EvalScore& operator*=(const ScoreType& s) {
     172              :       sc = MakeScore(MGScore(sc) * s, EGScore(sc) * s);
     173              :       return *this;
     174              :    }
     175              :    EvalScore& operator/=(const ScoreType& s) {
     176              :       sc = MakeScore(MGScore(sc) / s, EGScore(sc) / s);
     177              :       return *this;
     178              :    }
     179              :    EvalScore& operator+=(const ScoreType& s) {
     180              :       sc = MakeScore(MGScore(sc) + s, EGScore(sc) + s);
     181              :       return *this;
     182              :    }
     183              :    EvalScore& operator-=(const ScoreType& s) {
     184              :       sc = MakeScore(MGScore(sc) - s, EGScore(sc) - s);
     185              :       return *this;
     186              :    }
     187              :    EvalScore operator*(const ScoreType& s) const { return MakeScore(MGScore(sc) * s, EGScore(sc) * s); }
     188              :    EvalScore operator/(const ScoreType& s) const { return MakeScore(MGScore(sc) / s, EGScore(sc) / s); }
     189              :    EvalScore operator+(const ScoreType& s) const { return MakeScore(MGScore(sc) + s, EGScore(sc) + s); }
     190              :    EvalScore operator-(const ScoreType& s) const { return MakeScore(MGScore(sc) - s, EGScore(sc) - s); }
     191              :    EvalScore& operator=(const ScoreType& s) { sc = MakeScore(s, s); return *this; }
     192              : 
     193              :    [[nodiscard]] EvalScore scale(float s_mg, float s_eg) const { return EvalScore(ScoreType(MGScore(sc) * s_mg), ScoreType(EGScore(sc) * s_eg)); }
     194              : };
     195              : #endif
     196              : 
     197         1100 : inline std::ostream& operator<<(std::ostream& of, const EvalScore& s) {
     198         2200 :    of << s[MG] << " " << s[EG];
     199         1100 :    return of;
     200              : }
     201              : 
     202              : enum Feature : uint8_t { F_material = 0, F_positional, F_development, F_mobility, F_attack, F_pawnStruct, F_complexity, F_max };
     203              : FORCE_FINLINE Feature operator++(Feature& f) {
     204              :    f = Feature(f + 1);
     205              :    return f;
     206              : }
     207      2919045 : struct EvalFeatures {
     208              :    array1d<EvalScore, F_max> scores; // EvalScore is 0 initialized
     209              :    float       scalingFactor = 1.f; // only used in end-game !
     210              :    EvalScore   SumUp() const;
     211              :    static void callBack();
     212              : };
     213              : 
     214              : /*
     215              : inline std::ostream & operator<<(std::ostream & of, const EvalFeatures & features){
     216              :     for (size_t k = 0 ; k < F_max; ++k) of << features.scores[k] << " ";
     217              :     of << features.scalingFactor << " ";
     218              :     return of;
     219              : }
     220              : */
     221              : 
     222              : [[nodiscard]] FORCE_FINLINE ScoreType ScaleScore(const EvalScore s, const float gp, const float scalingFactorEG = 1.f) {
     223     29874666 :    return static_cast<ScoreType>(gp * s[MG] + (1.f - gp) * scalingFactorEG * s[EG]);
     224              : }
     225              : 
     226              : /* Evaluation is returning the score of course, but also fill this little structure to provide
     227              :  * additionnal usefull information, such as game phase and current danger. Things that are
     228              :  * possibly used in search later.
     229              :  */
     230              : struct EvalData {
     231              :    float gp = 0;
     232              :    colored<ScoreType> danger   = {0, 0};
     233              :    colored<uint16_t>  mobility = {0, 0};
     234              :    colored<bool>      haveThreats = {false, false};
     235              :    colored<bool>      goodThreats = {false, false};
     236              :    bool evalDone = false; // will tell if phase, danger and mobility are filleds or not
     237              : };
     238              : 
     239              : // used for easy move detection
     240              : struct RootScores {
     241              :    Move      m;
     242              :    ScoreType s;
     243              : };
     244              : 
     245              : // used for multiPV stuff
     246          789 : struct MultiPVScores {
     247              :    Move      m;
     248              :    ScoreType s;
     249              :    PVList    pv;
     250              :    DepthType seldepth;
     251              : };
     252              : 
     253              : void displayEval(const EvalData& data, const EvalFeatures& features);
     254              : 
     255              : // idea from Stockfish
     256              : namespace WDL {
     257              : // Coefficients of a 3rd order polynomial fit based on Minic test data (from CCRL, CEGT, FGRL)
     258              : constexpr array1d<double, 4> as {-13.65744616, 94.04894005, -95.05180396, 84.853482690};
     259              : constexpr array1d<double, 4> bs {-10.78187987, 77.22626799, -132.72201029, 122.54185402};
     260              : } // namespace WDL
     261              : 
     262              : [[nodiscard]] FORCE_FINLINE ScoreType shiftArmageddon(const ScoreType v, const unsigned int ply, const Color c) {
     263              :    // limit input ply and rescale
     264            0 :    const double m = std::min(256u, ply) / 64.0; // care! here ply not move
     265            0 :    const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
     266            0 :    if (c == Co_White) return static_cast<ScoreType>(v - 2 * a);
     267              :    else
     268            0 :       return static_cast<ScoreType>(v + 2 * a);
     269              : }
     270              : 
     271              : [[nodiscard]] FORCE_FINLINE double toWDLModel(const ScoreType v, const unsigned int ply) {
     272              :    // limit input ply and rescale
     273            0 :    const double m = std::min(256u, ply) / 64.0; // care! here ply not move
     274            0 :    const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
     275            0 :    const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
     276              :    // clamp score
     277            0 :    const double x = std::clamp(double((a - v) / b), -600.0, 600.0);
     278              :    // win probability from 0 to 1000
     279            0 :    return 1000. / (1. + std::exp(x));
     280              : }
     281              : 
     282              : /*
     283              : FORCE_FINLINE ScoreType fromWDLModel(const double w, const unsigned int ply) {
     284              :     // limit input ply and rescale
     285              :     const double m = std::min(256u, ply) / 32.0;
     286              :     const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
     287              :     const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
     288              :     const double s = a - b * std::log(1000./(std::max(w,std::numeric_limits<double>::epsilon())) - 1. + std::numeric_limits<double>::epsilon());
     289              :     return static_cast<ScoreType>(std::clamp(s, static_cast<double>matedScore(ply) , static_cast<double>(matingScore(ply - 1)) );
     290              : }
     291              : */
        

Generated by: LCOV version 2.0-1