LCOV - code coverage report
Current view: top level - Source - eval.cpp (source / functions) Coverage Total Hit
Test: coverage Lines: 93.1 % 437 407
Test Date: 2026-03-02 16:42:41 Functions: 86.2 % 29 25

            Line data    Source code
       1              : #include "attack.hpp"
       2              : #include "bitboardTools.hpp"
       3              : #include "dynamicConfig.hpp"
       4              : #include "evalConfig.hpp"
       5              : #include "evalTools.hpp"
       6              : #include "hash.hpp"
       7              : #include "moveApply.hpp"
       8              : #include "positionTools.hpp"
       9              : #include "score.hpp"
      10              : #include "searcher.hpp"
      11              : #include "timers.hpp"
      12              : 
      13              : using namespace BB; // to much of it ...
      14              : 
      15              : #pragma GCC diagnostic push
      16              : #pragma GCC diagnostic ignored "-Wconversion"
      17              : 
      18              : template<Color C>
      19              : FORCE_FINLINE void evalPawnPasser(const Position &p, BitBoard pieceBBiterator, EvalScore &score) {
      20       662166 :    applyOn(pieceBBiterator, [&](const Square & k){
      21       182329 :       const EvalScore kingNearBonus = (isValidSquare(p.king[C])  ? EvalConfig::kingNearPassedPawnSupport[chebyshevDistance(p.king[C], k)][ColorRank<C>(k)]  : 0) +
      22       182329 :                                       (isValidSquare(p.king[~C]) ? EvalConfig::kingNearPassedPawnDefend[chebyshevDistance(p.king[~C], k)][ColorRank<~C>(k)] : 0);
      23       190768 :       const bool unstoppable = (p.mat[~C][M_t] == 0) && ((chebyshevDistance(p.king[~C], PromotionSquare<C>(k)) - static_cast<int>(p.c != C)) >
      24        10106 :                                                          std::min(static_cast<Square>(5), chebyshevDistance(PromotionSquare<C>(k), k)));
      25              :       if (unstoppable)
      26         1667 :          score += ColorSignHelper<C>() * (value(P_wr) - value(P_wp)); // yes rook not queen to force promotion asap
      27              :       else
      28       361324 :          score += (EvalConfig::passerBonus[ColorRank<C>(k)] + kingNearBonus) * ColorSignHelper<C>();
      29              :    });
      30              : }
      31              : 
      32              : template<Color C>
      33              : FORCE_FINLINE void evalPawn(BitBoard pieceBBiterator, EvalScore &score) {
      34      1722984 :    applyOn(pieceBBiterator, [&](const Square & k){
      35       787115 :       const Square kk = ColorSquarePstHelper<C>(k);
      36      2423047 :       score += EvalConfig::PST[0][kk] * ColorSignHelper<C>();
      37              :    });
      38              : }
      39              : 
      40              : template<Color C>
      41              : FORCE_FINLINE void evalPawnFreePasser(const Position &p, BitBoard pieceBBiterator, EvalScore &score) {
      42      3032982 :    applyOn(pieceBBiterator, [&](const Square & k){
      43      1439046 :       score += EvalConfig::freePasserBonus[ColorRank<C>(k)] * ScoreType((BBTools::frontSpan<C>(k) & p.allPieces[~C]) == emptyBitBoard) * ColorSignHelper<C>();
      44              :    });
      45              : }
      46              : 
      47              : template<Color C>
      48              : FORCE_FINLINE void evalPawnProtected(BitBoard pieceBBiterator, EvalScore &score) {
      49       160420 :    applyOn(pieceBBiterator, [&](const Square & k){
      50        30260 :       score += EvalConfig::protectedPasserBonus[ColorRank<C>(k)] * ColorSignHelper<C>(); 
      51              :    });
      52              : }
      53              : 
      54              : template<Color C>
      55              : FORCE_FINLINE void evalPawnCandidate(BitBoard pieceBBiterator, EvalScore &score) {
      56       148754 :    applyOn(pieceBBiterator, [&](const Square & k){
      57        57773 :       score += EvalConfig::candidate[ColorRank<C>(k)] * ColorSignHelper<C>(); 
      58              :    });
      59              : }
      60              : 
      61              : template<Color C> 
      62      3187872 : BitBoard getPinned(const Position &p, const Square s) {
      63      3187872 :    BitBoard pinned = emptyBitBoard;
      64      3187872 :    if (!isValidSquare(s)) return pinned; // this allows for pinned to queen detection more easily
      65      4638854 :    const BitBoard pinner = BBTools::attack<P_wb>(s, p.pieces_const<P_wb>(~C) | p.pieces_const<P_wq>(~C), p.allPieces[~C]) |
      66      2319427 :                            BBTools::attack<P_wr>(s, p.pieces_const<P_wr>(~C) | p.pieces_const<P_wq>(~C), p.allPieces[~C]);
      67      2971753 :    applyOn(pinner, [&](const Square & k){
      68       326163 :       pinned |= BBTools::between(k,p.king[C]) & p.allPieces[C]; 
      69              :    });
      70      2319427 :    return pinned;
      71              : }
      72              : 
      73      2918516 : bool isLazyHigh(ScoreType lazyThreshold, const EvalFeatures &features, EvalScore &score) {
      74              :    //if (DynamicConfig::FRC) return false;
      75      2918516 :    score = features.SumUp();
      76      2918516 :    return Abs(score[MG] + score[EG]) / 2 > lazyThreshold;
      77              : }
      78              : 
      79            0 : bool forbidNNUE([[maybe_unused]] const Position &p){
      80              :    /*
      81              :    // for opposite colored bishop alone (with pawns)
      82              :    if (p.mat[Co_White][M_t] == 1 && 
      83              :        p.mat[Co_Black][M_t] == 1 &&
      84              :        p.mat[Co_White][M_b] == 1 && 
      85              :        p.mat[Co_Black][M_b] == 1 && 
      86              :        countBit(p.allBishop() & whiteSquare) == 1 &&
      87              :        Abs(p.mat[Co_White][M_p] - p.mat[Co_Black][M_p]) < 4 ) return true;
      88              :    */
      89            0 :    return false;
      90              : }
      91              : 
      92            0 : ScoreType armageddonScore(ScoreType score, unsigned int ply, DepthType height, Color c) {
      93            0 :    return std::clamp(shiftArmageddon(score, ply, c), matedScore(height), matingScore(height-1));
      94              : }
      95              : 
      96            0 : ScoreType variantScore(ScoreType score, unsigned int ply, DepthType height, Color c) {
      97            0 :    if (DynamicConfig::armageddon) return armageddonScore(score, ply, height, c);
      98              :    return score;
      99              : }
     100              : 
     101              : // if antichess, we'll just try to minimize material for now
     102            0 : ScoreType evalAntiChess(const Position &p, EvalData &data, [[maybe_unused]] Searcher &context, [[maybe_unused]] bool allowEGEvaluation, [[maybe_unused]] bool display) {
     103            0 :     const bool white2Play = p.c == Co_White;
     104              : 
     105              :     //@todo some special case : opposite color bishop => draw
     106              : 
     107            0 :     ScoreType matScoreW = 0;
     108            0 :     ScoreType matScoreB = 0;
     109            0 :     data.gp = gamePhase(p.mat, matScoreW, matScoreB);
     110              :     EvalScore score = EvalScore(
     111            0 :         (- p.mat[Co_White][M_k] + p.mat[Co_Black][M_k]) * absValue(P_wk) +
     112              :         (- p.mat[Co_White][M_q] + p.mat[Co_Black][M_q]) * absValue(P_wq) +
     113            0 :         (- p.mat[Co_White][M_r] + p.mat[Co_Black][M_r]) * absValue(P_wr) +
     114              :         (- p.mat[Co_White][M_b] + p.mat[Co_Black][M_b]) * absValue(P_wb) +
     115            0 :         (- p.mat[Co_White][M_n] + p.mat[Co_Black][M_n]) * absValue(P_wn) +
     116              :         (- p.mat[Co_White][M_p] + p.mat[Co_Black][M_p]) * absValue(P_wp) ,
     117            0 :         (- p.mat[Co_White][M_k] + p.mat[Co_Black][M_k]) * absValueEG(P_wk) +
     118            0 :         (- p.mat[Co_White][M_q] + p.mat[Co_Black][M_q]) * absValueEG(P_wq) +
     119            0 :         (- p.mat[Co_White][M_r] + p.mat[Co_Black][M_r]) * absValueEG(P_wr) +
     120            0 :         (- p.mat[Co_White][M_b] + p.mat[Co_Black][M_b]) * absValueEG(P_wb) +
     121            0 :         (- p.mat[Co_White][M_n] + p.mat[Co_Black][M_n]) * absValueEG(P_wn) +
     122            0 :         (- p.mat[Co_White][M_p] + p.mat[Co_Black][M_p]) * absValueEG(P_wp) );
     123              : 
     124              :     const ScoreType ret = ScaleScore(score, data.gp, 1.f);
     125            0 :     return (white2Play ? +1 : -1) * ret;
     126              : }
     127              : 
     128              : #ifdef WITH_NNUE
     129      2127467 : ScoreType NNUEEVal(const Position & p, EvalData &data, Searcher &context, EvalFeatures &features, bool secondTime = false){
     130              :    START_TIMER
     131      2127467 :    if (DynamicConfig::armageddon) features.scalingFactor = 1.f; ///@todo better
     132              :    /*
     133              :    // king bucket
     134              :    constexpr int kingBucket[64] = {
     135              :       0,  0,  0,  1,  1,  1,  2,  2,
     136              :       0,  3,  3,  3,  4,  4,  5,  5,
     137              :       3,  3,  3,  3,  4,  4,  5,  5,
     138              :       3,  3,  3,  4,  4,  4,  5,  5,
     139              :       3,  3,  3,  4,  4,  6,  6,  5,
     140              :       6,  6,  6,  6,  6,  6,  6,  6, 
     141              :       6,  6,  6,  6,  6,  6,  6,  6, 
     142              :       6,  6,  6,  6,  6,  6,  6,  6, 
     143              :    };
     144              :    const int bucket = kingBucket[relative_square(p.c, p.king[p.c])];
     145              :    */
     146              :    // or phase
     147              :    //const int bucketDivisor = 32/p.evaluator().weights.nbuckets;
     148              :    //const int bucket = std::max(0, std::min(p.evaluator().weights.nbuckets-1, (std::min(32,static_cast<int>(BB::countBit(p.occupancy()))-1) / bucketDivisor)));
     149              :    int bucket = 0;
     150      2127467 :    if (data.gp < 0.45f)
     151              :       bucket = 0;
     152              :    else
     153              :       bucket = 1;
     154              :    
     155              :    // call the net
     156      2127467 :    ScoreType nnueScore = static_cast<ScoreType>(p.evaluator().propagate(p.c, bucket));
     157              : 
     158              :    // fuse MG and EG score applying the EG scaling factor ///@todo, doesn't the net already learned that ????
     159      2127467 :    nnueScore = ScaleScore({nnueScore, nnueScore}, data.gp, features.scalingFactor);
     160              :    // NNUE evaluation scaling
     161      2127467 :    nnueScore = static_cast<ScoreType>((nnueScore * DynamicConfig::NNUEScaling) / 64);
     162              :    // take contempt into account (no tempo with NNUE, 
     163              :    // the HalfKA net already take it into account but this is necessary for "dynamic" contempt from opponent)
     164      2127467 :    nnueScore += ScaleScore(context.contempt, data.gp);
     165              :    // clamp score
     166      2127467 :    nnueScore = clampScore(nnueScore);
     167      2127467 :    if (!DynamicConfig::armageddon){
     168              :       // apply scaling factor based on fifty move rule
     169      2127467 :       nnueScore = fiftyScale(nnueScore, p.fifty);
     170              :    }
     171      2127467 :    context.stats.incr(secondTime ? Stats::sid_evalNNUE2 : Stats::sid_evalNNUE);
     172              :    // apply variants scoring if requiered
     173              :    STOP_AND_SUM_TIMER(NNUE)
     174      2127467 :    return variantScore(nnueScore, p.halfmoves, context.height_, p.c);   
     175              : }
     176              : #endif
     177              : 
     178      2919045 : ScoreType eval(const Position &p, EvalData &data, Searcher &context, bool allowEGEvaluation, bool display) {
     179              :    START_TIMER
     180              : 
     181      2919045 :    if (DynamicConfig::antichess) return evalAntiChess(p, data, context, allowEGEvaluation, display);
     182              :    ///@todo other variants
     183              : 
     184              :    // in some variant (like antichess) king is not mandatory
     185              :    const bool kingIsMandatory = DynamicConfig::isKingMandatory();
     186              : 
     187              :    // if no more pieces except maybe kings, end of game as draw in most standard variants
     188      2919045 :    if ( (p.occupancy() & ~p.allKing()) == emptyBitBoard ){
     189              :       if (kingIsMandatory ){ 
     190              :          // drawScore take some variants into account like armageddon
     191            0 :          return context.drawScore(p, context.height_);
     192              :       }
     193              :       else {
     194              :          ///@todo implements things for some variants ?
     195              :       }
     196              :    }
     197              : 
     198              :    // is it player with the white pieces turn ?
     199      2919045 :    const bool white2Play = p.c == Co_White;
     200              : 
     201              : #ifdef DEBUG_KING_CAP
     202              :    if (kingIsMandatory) {
     203              :       if (p.king[Co_White] == INVALIDSQUARE) {
     204              :          STOP_AND_SUM_TIMER(Eval)
     205              :          context.stats.incr(Stats::sid_evalNoKing);
     206              :          return data.gp = 0, (white2Play ? -1 : +1) * matingScore(0);
     207              :       }
     208              :       if (p.king[Co_Black] == INVALIDSQUARE) {
     209              :          STOP_AND_SUM_TIMER(Eval)
     210              :          context.stats.incr(Stats::sid_evalNoKing);
     211              :          return data.gp = 0, (white2Play ? +1 : -1) * matingScore(0);
     212              :       }
     213              :    }
     214              : #endif
     215              : 
     216              :    ///@todo activate (or modulate) some features based on skill level
     217              : 
     218              :    // main features (feature won't survive Eval scope), but EvalData will !
     219              :    EvalFeatures features;
     220              : 
     221              :    // Material evaluation (most often from Material table)
     222      2919045 :    if (const Hash matHash = MaterialHash::getMaterialHash(p.mat); matHash != nullHash) {
     223              :       context.stats.incr(Stats::sid_materialTableHits);
     224              :       // Get material hash data
     225              :       const MaterialHash::MaterialHashEntry &MEntry = MaterialHash::materialHashTable[matHash];
     226              :       // update EvalData and EvalFeatures
     227      2918200 :       data.gp = MEntry.gamePhase();
     228      2918200 :       features.scores[F_material] += MEntry.score;
     229              : 
     230              :       // end game knowledge (helper or scaling), only for most standard chess variants with kings on the board
     231      2918200 :       if (allowEGEvaluation && kingIsMandatory && (p.mat[Co_White][M_t] + p.mat[Co_Black][M_t] < 5) ) {
     232              :          // let's verify that the is no naive capture before using end-game knowledge
     233      1489005 :          MoveList moves;
     234      1489005 :          MoveGen::generate<MoveGen::GP_cap>(p, moves);
     235              :          bool hasCapture = false;
     236      1554297 :          for (auto m : moves){
     237      1295726 :             Position p2 = p;
     238      1295726 :             if (const MoveInfo moveInfo(p2, m); applyMove(p2,moveInfo, true)){
     239              :                hasCapture = true;
     240      1230434 :                break;
     241              :             }
     242      1295726 :          }
     243              :          // probe endgame knowledge only if position is quiet from stm pov
     244              :          if (!hasCapture) {
     245       258571 :             const Color winningSideEG = features.scores[F_material][EG] > 0 ? Co_White : Co_Black;
     246              :             // helpers for various endgame
     247       258571 :             if (MEntry.t == MaterialHash::Ter_WhiteWinWithHelper || MEntry.t == MaterialHash::Ter_BlackWinWithHelper) {
     248              :                STOP_AND_SUM_TIMER(Eval)
     249              :                context.stats.incr(Stats::sid_materialTableHelper);
     250              :                const ScoreType materialTableScore =
     251           39 :                    (white2Play ? +1 : -1) * (MaterialHash::helperTable[matHash](p, winningSideEG, features.scores[F_material][EG], context.height_));
     252           30 :                return variantScore(materialTableScore, p.halfmoves, context.height_, p.c);
     253              :             }
     254              :             // real FIDE draws (shall not happens for now in fact ///@todo !!!)
     255              :             else if (MEntry.t == MaterialHash::Ter_Draw) {
     256            0 :                if (!isPosInCheck(p)) {
     257              :                   STOP_AND_SUM_TIMER(Eval)
     258              :                   context.stats.incr(Stats::sid_materialTableDraw);
     259            0 :                   return context.drawScore(p, context.height_); // drawScore take armageddon into account
     260              :                }
     261              :             }
     262              :             // non FIDE draws
     263              :             else if (MEntry.t == MaterialHash::Ter_MaterialDraw) {
     264           56 :                if (!isPosInCheck(p)) {
     265              :                   STOP_AND_SUM_TIMER(Eval)
     266              :                   context.stats.incr(Stats::sid_materialTableDraw2);
     267           56 :                   return context.drawScore(p, context.height_); // drawScore take armageddon into account
     268              :                }
     269              :             }
     270              :             // apply some scaling (more later...)
     271              :             else if (MEntry.t == MaterialHash::Ter_WhiteWin || MEntry.t == MaterialHash::Ter_BlackWin)
     272            0 :                features.scalingFactor = static_cast<float>(EvalConfig::scalingFactorWin) / 128.f;
     273              :             else if (MEntry.t == MaterialHash::Ter_HardToWin)
     274           38 :                features.scalingFactor = static_cast<float>(EvalConfig::scalingFactorHardWin) / 128.f;
     275              :             else if (MEntry.t == MaterialHash::Ter_LikelyDraw)
     276            5 :                features.scalingFactor = static_cast<float>(EvalConfig::scalingFactorLikelyDraw) / 128.f;
     277              :          }
     278              :          /*
     279              :          else {
     280              :             std::cout << "posible cap" << std::endl;
     281              :          }
     282              :          */
     283              :       }
     284              :    }
     285              :    else { // game phase and material scores out of table
     286              :       ///@todo we don't care about imbalance here ?
     287          845 :       ScoreType matScoreW = 0;
     288          845 :       ScoreType matScoreB = 0;
     289          845 :       data.gp = gamePhase(p.mat, matScoreW, matScoreB);
     290          845 :       features.scores[F_material] += EvalScore(
     291          845 :           (p.mat[Co_White][M_q] - p.mat[Co_Black][M_q]) * absValue(P_wq) +
     292              :           (p.mat[Co_White][M_r] - p.mat[Co_Black][M_r]) * absValue(P_wr) +
     293          845 :           (p.mat[Co_White][M_b] - p.mat[Co_Black][M_b]) * absValue(P_wb) +
     294          845 :           (p.mat[Co_White][M_n] - p.mat[Co_Black][M_n]) * absValue(P_wn) +
     295              :           (p.mat[Co_White][M_p] - p.mat[Co_Black][M_p]) * absValue(P_wp) ,
     296          845 :           (p.mat[Co_White][M_q] - p.mat[Co_Black][M_q]) * absValueEG(P_wq) +
     297          845 :           (p.mat[Co_White][M_r] - p.mat[Co_Black][M_r]) * absValueEG(P_wr) +
     298          845 :           (p.mat[Co_White][M_b] - p.mat[Co_Black][M_b]) * absValueEG(P_wb) +
     299          845 :           (p.mat[Co_White][M_n] - p.mat[Co_Black][M_n]) * absValueEG(P_wn) +
     300          845 :           (p.mat[Co_White][M_p] - p.mat[Co_Black][M_p]) * absValueEG(P_wp) );
     301              :       //std::cout << ToString(p,true) << std::endl;
     302              :       context.stats.incr(Stats::sid_materialTableMiss);
     303              :    }
     304              : 
     305              :    //std::cout << "allow material eval? " << allowEGEvaluation << std::endl;
     306              :    //std::cout << GetFEN(p) << std::endl;
     307              : 
     308              : #ifndef WITH_MATERIAL_TABLE
     309              :    // in case we are not using a material table, we still need KPK, KRK and KBNK helper
     310              :    // but only for most standard chess variants with kings on the board
     311              :    // end game knowledge (helper or scaling)
     312              :    if (allowEGEvaluation && kingIsMandatory && (p.mat[Co_White][M_t] + p.mat[Co_Black][M_t] < 5)) {
     313              :      static const auto matHashKPK = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KPK"));
     314              :      static const auto matHashKKP = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KKP"));
     315              :      static const auto matHashKQK = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KQK"));
     316              :      static const auto matHashKKQ = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KKQ"));
     317              :      static const auto matHashKRK = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KRK"));
     318              :      static const auto matHashKKR = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KKR"));
     319              :      static const auto matHashKLNK = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KLNK"));
     320              :      static const auto matHashKKLN = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KKLN"));
     321              :      static const auto matHashKDNK = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KDNK"));
     322              :      static const auto matHashKKDN = MaterialHash::getMaterialHash2(MaterialHash::materialFromString("KKDN"));
     323              :      STOP_AND_SUM_TIMER(Eval)
     324              :      const Color winningSideEG = features.scores[F_material][EG] > 0 ? Co_White : Co_Black;
     325              :      context.stats.incr(Stats::sid_materialTableHelper);
     326              :      ScoreType materialTableScore = 0;
     327              :      const Hash matHash2 = MaterialHash::getMaterialHash2(p.mat);
     328              :      bool matHelperHit = false;
     329              : #if !defined(WITH_SMALL_MEMORY)
     330              :      if (matHash2 == matHashKPK || matHash2 == matHashKKP){
     331              :         materialTableScore = (white2Play ? +1 : -1) * (MaterialHash::helperKPK(p, winningSideEG, features.scores[F_material][EG], context.height_));
     332              :         matHelperHit = true;
     333              :      }
     334              : #endif
     335              :      if (matHash2 == matHashKQK || matHash2 == matHashKKQ || matHash2 == matHashKRK || matHash2 == matHashKKR){
     336              :         materialTableScore = (white2Play ? +1 : -1) * (MaterialHash::helperKXK(p, winningSideEG, features.scores[F_material][EG], context.height_));
     337              :         matHelperHit = true;
     338              :      }
     339              :      if (matHash2 == matHashKLNK || matHash2 == matHashKKLN || matHash2 == matHashKDNK || matHash2 == matHashKKDN){
     340              :         materialTableScore = (white2Play ? +1 : -1) * (MaterialHash::helperKmmK(p, winningSideEG, features.scores[F_material][EG], context.height_));
     341              :         matHelperHit = true;
     342              :      }
     343              :      if (matHelperHit){
     344              :          return variantScore(materialTableScore, p.halfmoves, context.height_, p.c);
     345              :      }
     346              :    }
     347              : #endif
     348              : 
     349              : #ifdef WITH_EVAL_TUNING
     350              :    features.scores[F_material] += MaterialHash::Imbalance(p.mat, Co_White) - MaterialHash::Imbalance(p.mat, Co_Black);
     351              : #endif
     352              : 
     353              : #ifdef WITH_NNUE
     354              :    const bool forbiddenNNUE = forbidNNUE(p) && !DynamicConfig::forceNNUE;
     355      2918959 :    if (DynamicConfig::useNNUE && !forbiddenNNUE) {
     356              :       // we will stay to classic eval when the game is already decided (to gain some nps)
     357              :       ///@todo use data.gp inside NNUE condition ?
     358      5837474 :       if (EvalScore score; DynamicConfig::forceNNUE ||
     359      2918516 :           !isLazyHigh(static_cast<ScoreType>(DynamicConfig::NNUEThreshold), features, score)) {
     360              :          STOP_AND_SUM_TIMER(Eval)
     361      2121991 :          ScoreType nnueEval = NNUEEVal(p, data, context, features);
     362              : 
     363              :          // random factor in opening if requiered
     364      2121991 :          if (p.halfmoves < 10 && DynamicConfig::randomOpen != 0){
     365            0 :             nnueEval += static_cast<ScoreType>(randomInt<int /*NO SEED USE => random device*/>(-1*DynamicConfig::randomOpen, DynamicConfig::randomOpen));
     366              :          }
     367      2121991 :          return nnueEval;
     368              :       }
     369              :       // fall back to classic eval
     370              :       context.stats.incr(Stats::sid_evalStd);
     371              :    }
     372              : #endif
     373              : 
     374              :    STOP_AND_SUM_TIMER(Eval1)
     375              : 
     376              :    // prefetch pawn evaluation table as soon as possible
     377       796968 :    context.prefetchPawn(computeHash(p));
     378              : 
     379              :    // pre compute some usefull bitboards (///@todo maybe this is not efficient ...)
     380              :    const colored<BitBoard> pawns      = {p.whitePawn(), p.blackPawn()};
     381              :    const colored<BitBoard> knights    = {p.whiteKnight(), p.blackKnight()};
     382              :    const colored<BitBoard> bishops    = {p.whiteBishop(), p.blackBishop()};
     383              :    const colored<BitBoard> rooks      = {p.whiteRook(), p.blackRook()};
     384       796968 :    const colored<BitBoard> queens     = {p.whiteQueen(), p.blackQueen()};
     385              :    const colored<BitBoard> kings      = {p.whiteKing(), p.blackKing()};
     386       796968 :    const colored<BitBoard> nonPawnMat = {p.allPieces[Co_White] & ~pawns[Co_White], 
     387       796968 :                                          p.allPieces[Co_Black] & ~pawns[Co_Black]};
     388       796968 :    const colored<BitBoard> kingZone   = {isValidSquare(p.king[Co_White]) ? BBTools::mask[p.king[Co_White]].kingZone : emptyBitBoard, 
     389       796968 :                                          isValidSquare(p.king[Co_Black]) ? BBTools::mask[p.king[Co_Black]].kingZone : emptyBitBoard};
     390       796968 :    const BitBoard occupancy = p.occupancy();
     391              : 
     392              :    // helpers that will be filled by evalPiece calls
     393       796968 :    colored<ScoreType> kdanger = {0, 0};
     394       796968 :    colored<BitBoard>  att     = {emptyBitBoard, emptyBitBoard}; // bitboard of squares attacked by Color
     395       796968 :    colored<BitBoard>  att2    = {emptyBitBoard, emptyBitBoard}; // bitboard of squares attacked twice by Color
     396       796968 :    array2d<BitBoard,2,6>  attFromPiece = {{emptyBitBoard}};     // bitboard of squares attacked by specific piece of Color
     397       796968 :    array2d<BitBoard,2,6>  checkers     = {{emptyBitBoard}};     // bitboard of Color pieces squares attacking king
     398              : 
     399              :    // PST, attack, danger
     400       796968 :    const bool withForwadness = DynamicConfig::styleForwardness != 50;
     401       796968 :    const array1d<ScoreType,2> staticColorSignHelper = { +1, -1};
     402      2390904 :    for (Color c = Co_White ; c <= Co_Black ; ++c){
     403              :       // will do pawns later
     404      9563616 :       for (Piece pp = P_wn ; pp <= P_wk ; ++pp){
     405     15939360 :          applyOn(p.pieces_const(c,pp), [&](const Square & k){
     406      4906538 :             const Square kk = relative_square(~c,k);
     407      9813076 :             features.scores[F_positional] += EvalConfig::PST[pp - 1][kk] * staticColorSignHelper[c];
     408      4906538 :             if (withForwadness)
     409            0 :                features.scores[F_positional] += EvalScore {ScoreType(((DynamicConfig::styleForwardness - 50) * SQRANK(kk)) / 8), 0} * staticColorSignHelper[c];
     410              :             // aligned threats removing own piece (not pawn) in occupancy
     411      4906538 :             const BitBoard shadowTarget = BBTools::pfCoverage[pp - 1](k, occupancy ^ nonPawnMat[c], c);
     412      4906538 :             if (shadowTarget) {
     413      4906538 :                kdanger[~c] += countBit(shadowTarget & kingZone[~c]) * EvalConfig::kingAttWeight[EvalConfig::katt_attack][pp - 1];
     414      4906538 :                const BitBoard target = BBTools::pfCoverage[pp - 1](k, occupancy, c); // real targets
     415      4906538 :                if (target) {
     416      4906538 :                   attFromPiece[c][pp - 1] |= target;
     417      4906538 :                   att2[c] |= att[c] & target;
     418      4906538 :                   att[c] |= target;
     419      4906538 :                   if (target & p.pieces_const<P_wk>(~c)) checkers[c][pp - 1] |= SquareToBitboard(k);
     420      4906538 :                   kdanger[c] -= countBit(target & kingZone[c]) * EvalConfig::kingAttWeight[EvalConfig::katt_defence][pp - 1];
     421              :                }
     422              :             }
     423      4906538 :          });
     424              :       }
     425              :    }
     426              : 
     427              :    // random factor in opening if requiered
     428       796968 :    if (p.halfmoves < 10 && DynamicConfig::randomOpen != 0){
     429            0 :       features.scores[F_positional] += static_cast<ScoreType>(randomInt<int /*NO SEED USE => random device*/>(-1*DynamicConfig::randomOpen, DynamicConfig::randomOpen));
     430              :    }
     431              : 
     432              :    STOP_AND_SUM_TIMER(Eval2)
     433              : 
     434       796968 :    Searcher::PawnEntry *pePtr = nullptr;
     435              : #ifdef WITH_EVAL_TUNING
     436              :    Searcher::PawnEntry dummy; // used for evaluations tuning
     437              :    pePtr = &dummy;
     438              :    {
     439              : #else
     440       796968 :    if (!context.getPawnEntry(computePHash(p), pePtr)) {
     441              : #endif
     442       148754 :       assert(pePtr);
     443              :       Searcher::PawnEntry &pe = *pePtr;
     444              :       pe.reset();
     445       148754 :       pe.pawnTargets[Co_White]   = BBTools::pawnAttacks<Co_White>(pawns[Co_White]);
     446       148754 :       pe.pawnTargets[Co_Black]   = BBTools::pawnAttacks<Co_Black>(pawns[Co_Black]);
     447              :       // semiOpen white means with white pawn, and without black pawn
     448       148754 :       pe.semiOpenFiles[Co_White] = BBTools::fillFile(pawns[Co_White]) & ~BBTools::fillFile(pawns[Co_Black]);
     449       148754 :       pe.semiOpenFiles[Co_Black] = BBTools::fillFile(pawns[Co_Black]) & ~BBTools::fillFile(pawns[Co_White]);
     450       148754 :       pe.passed[Co_White]        = BBTools::pawnPassed<Co_White>(pawns[Co_White], pawns[Co_Black]);
     451       148754 :       pe.passed[Co_Black]        = BBTools::pawnPassed<Co_Black>(pawns[Co_Black], pawns[Co_White]);
     452       148754 :       pe.holes[Co_White]         = BBTools::pawnHoles<Co_White>(pawns[Co_White]) & holesZone[Co_White];
     453       148754 :       pe.holes[Co_Black]         = BBTools::pawnHoles<Co_Black>(pawns[Co_Black]) & holesZone[Co_Black];
     454       148754 :       pe.openFiles               = BBTools::openFiles(pawns[Co_White], pawns[Co_Black]);
     455              : 
     456              :       // PST
     457       148754 :       evalPawn<Co_White>(pawns[Co_White], pe.score);
     458              :       evalPawn<Co_Black>(pawns[Co_Black], pe.score);
     459              : 
     460              :       // danger in king zone (from pawns attacking or defending)
     461       148754 :       pe.danger[Co_White] -= countBit(pe.pawnTargets[Co_White] & kingZone[Co_White]) * EvalConfig::kingAttWeight[EvalConfig::katt_defence][0];
     462       148754 :       pe.danger[Co_White] += countBit(pe.pawnTargets[Co_Black] & kingZone[Co_White]) * EvalConfig::kingAttWeight[EvalConfig::katt_attack][0];
     463       148754 :       pe.danger[Co_Black] -= countBit(pe.pawnTargets[Co_Black] & kingZone[Co_Black]) * EvalConfig::kingAttWeight[EvalConfig::katt_defence][0];
     464       148754 :       pe.danger[Co_Black] += countBit(pe.pawnTargets[Co_White] & kingZone[Co_Black]) * EvalConfig::kingAttWeight[EvalConfig::katt_attack][0];
     465              : 
     466              :       // pawn passer
     467       148754 :       evalPawnPasser<Co_White>(p, pe.passed[Co_White], pe.score);
     468       148754 :       evalPawnPasser<Co_Black>(p, pe.passed[Co_Black], pe.score);
     469              : 
     470              :       // pawn protected
     471       148754 :       evalPawnProtected<Co_White>(pe.passed[Co_White] & pe.pawnTargets[Co_White], pe.score);
     472       148754 :       evalPawnProtected<Co_Black>(pe.passed[Co_Black] & pe.pawnTargets[Co_Black], pe.score);
     473              : 
     474              :       // pawn candidate
     475       148754 :       evalPawnCandidate<Co_White>(BBTools::pawnCandidates<Co_White>(pawns[Co_White], pawns[Co_Black]), pe.score);
     476       148754 :       evalPawnCandidate<Co_Black>(BBTools::pawnCandidates<Co_Black>(pawns[Co_Black], pawns[Co_White]), pe.score);
     477              : 
     478              :       ///@todo hidden passed
     479              : 
     480              :       // bad pawns
     481              :       const colored<BitBoard> semiOpenPawn = {BBTools::pawnSemiOpen<Co_White>(pawns[Co_White], pawns[Co_Black]),
     482              :                                               BBTools::pawnSemiOpen<Co_Black>(pawns[Co_Black], pawns[Co_White])};
     483       148754 :       const colored<BitBoard> backward     = {BBTools::pawnBackward<Co_White>(pawns[Co_White], pawns[Co_Black]),
     484       148754 :                                               BBTools::pawnBackward<Co_Black>(pawns[Co_Black], pawns[Co_White])};
     485       148754 :       const BitBoard backwardOpenW     = backward[Co_White] & semiOpenPawn[Co_White];
     486       148754 :       const BitBoard backwardCloseW    = backward[Co_White] & ~semiOpenPawn[Co_White];
     487       148754 :       const BitBoard backwardOpenB     = backward[Co_Black] & semiOpenPawn[Co_Black];
     488       148754 :       const BitBoard backwardCloseB    = backward[Co_Black] & ~semiOpenPawn[Co_Black];
     489              :       const colored<BitBoard> doubled  = {BBTools::pawnDoubled<Co_White>(pawns[Co_White]),
     490              :                                          BBTools::pawnDoubled<Co_Black>(pawns[Co_Black])};
     491       148754 :       const BitBoard doubledOpenW      = doubled[Co_White] & semiOpenPawn[Co_White];
     492       148754 :       const BitBoard doubledCloseW     = doubled[Co_White] & ~semiOpenPawn[Co_White];
     493       148754 :       const BitBoard doubledOpenB      = doubled[Co_Black] & semiOpenPawn[Co_Black];
     494       148754 :       const BitBoard doubledCloseB     = doubled[Co_Black] & ~semiOpenPawn[Co_Black];
     495       148754 :       const colored<BitBoard> isolated = {BBTools::pawnIsolated(pawns[Co_White]),
     496       148754 :                                           BBTools::pawnIsolated(pawns[Co_Black])};
     497       148754 :       const BitBoard isolatedOpenW     = isolated[Co_White] & semiOpenPawn[Co_White];
     498       148754 :       const BitBoard isolatedCloseW    = isolated[Co_White] & ~semiOpenPawn[Co_White];
     499       148754 :       const BitBoard isolatedOpenB     = isolated[Co_Black] & semiOpenPawn[Co_Black];
     500       148754 :       const BitBoard isolatedCloseB    = isolated[Co_Black] & ~semiOpenPawn[Co_Black];
     501              :       const colored<BitBoard> detached = {BBTools::pawnDetached<Co_White>(pawns[Co_White], pawns[Co_Black]),
     502              :                                           BBTools::pawnDetached<Co_Black>(pawns[Co_Black], pawns[Co_White])};
     503       148754 :       const BitBoard detachedOpenW     = detached[Co_White] & semiOpenPawn[Co_White] & ~backward[Co_White];
     504       148754 :       const BitBoard detachedCloseW    = detached[Co_White] & ~semiOpenPawn[Co_White] & ~backward[Co_White];
     505       148754 :       const BitBoard detachedOpenB     = detached[Co_Black] & semiOpenPawn[Co_Black] & ~backward[Co_Black];
     506       148754 :       const BitBoard detachedCloseB    = detached[Co_Black] & ~semiOpenPawn[Co_Black] & ~backward[Co_Black];
     507              : 
     508      1041278 :       for (Rank r = Rank_2; r <= Rank_7; ++r) { // simply r2..r7 for classic chess works
     509              :          // pawn backward
     510      1785048 :          pe.score -= EvalConfig::backwardPawn[r][EvalConfig::Close] * countBit(backwardCloseW & ranks[r]);
     511      1785048 :          pe.score -= EvalConfig::backwardPawn[r][EvalConfig::SemiOpen] * countBit(backwardOpenW & ranks[r]);
     512              :          // double pawn malus
     513      1785048 :          pe.score -= EvalConfig::doublePawn[r][EvalConfig::Close] * countBit(doubledCloseW & ranks[r]);
     514      1785048 :          pe.score -= EvalConfig::doublePawn[r][EvalConfig::SemiOpen] * countBit(doubledOpenW & ranks[r]);
     515              :          // isolated pawn malus
     516      1785048 :          pe.score -= EvalConfig::isolatedPawn[r][EvalConfig::Close] * countBit(isolatedCloseW & ranks[r]);
     517      1785048 :          pe.score -= EvalConfig::isolatedPawn[r][EvalConfig::SemiOpen] * countBit(isolatedOpenW & ranks[r]);
     518              :          // detached pawn (not backward)
     519      1785048 :          pe.score -= EvalConfig::detachedPawn[r][EvalConfig::Close] * countBit(detachedCloseW & ranks[r]);
     520      1785048 :          pe.score -= EvalConfig::detachedPawn[r][EvalConfig::SemiOpen] * countBit(detachedOpenW & ranks[r]);
     521              : 
     522              :          // pawn backward
     523      1785048 :          pe.score += EvalConfig::backwardPawn[7 - r][EvalConfig::Close] * countBit(backwardCloseB & ranks[r]);
     524      1785048 :          pe.score += EvalConfig::backwardPawn[7 - r][EvalConfig::SemiOpen] * countBit(backwardOpenB & ranks[r]);
     525              :          // double pawn malus
     526      1785048 :          pe.score += EvalConfig::doublePawn[7 - r][EvalConfig::Close] * countBit(doubledCloseB & ranks[r]);
     527      1785048 :          pe.score += EvalConfig::doublePawn[7 - r][EvalConfig::SemiOpen] * countBit(doubledOpenB & ranks[r]);
     528              :          // isolated pawn malus
     529      1785048 :          pe.score += EvalConfig::isolatedPawn[7 - r][EvalConfig::Close] * countBit(isolatedCloseB & ranks[r]);
     530      1785048 :          pe.score += EvalConfig::isolatedPawn[7 - r][EvalConfig::SemiOpen] * countBit(isolatedOpenB & ranks[r]);
     531              :          // detached pawn (not backward)
     532      1785048 :          pe.score += EvalConfig::detachedPawn[7 - r][EvalConfig::Close] * countBit(detachedCloseB & ranks[r]);
     533      1785048 :          pe.score += EvalConfig::detachedPawn[7 - r][EvalConfig::SemiOpen] * countBit(detachedOpenB & ranks[r]);
     534              :       }
     535              : 
     536              :       // pawn impact on king safety (PST and king troppism alone is not enough)
     537              :       if (kingIsMandatory){
     538              :         // pawn shield
     539       148754 :         const colored<BitBoard> kingShield = {kingZone[Co_White] & ~BBTools::shiftS<Co_White>(ranks[SQRANK(p.king[Co_White])]),
     540       148754 :                                               kingZone[Co_Black] & ~BBTools::shiftS<Co_Black>(ranks[SQRANK(p.king[Co_Black])])};
     541       148754 :         const int pawnShieldW = countBit(kingShield[Co_White] & pawns[Co_White]);
     542       148754 :         const int pawnShieldB = countBit(kingShield[Co_Black] & pawns[Co_Black]);
     543       297508 :         pe.score += EvalConfig::pawnShieldBonus * std::min(pawnShieldW * pawnShieldW, 9);
     544       297508 :         pe.score -= EvalConfig::pawnShieldBonus * std::min(pawnShieldB * pawnShieldB, 9);
     545              :         
     546              :         // malus for king on a pawnless flank
     547       148754 :         const File wkf = SQFILE(p.king[Co_White]);
     548       148754 :         const File bkf = SQFILE(p.king[Co_Black]);
     549       148754 :         if (!(pawns[Co_White] & kingFlank[wkf])) pe.score += EvalConfig::pawnlessFlank;
     550       148754 :         if (!(pawns[Co_Black] & kingFlank[bkf])) pe.score -= EvalConfig::pawnlessFlank;
     551              :         
     552              :         // pawn storm
     553       297508 :         pe.score -= EvalConfig::pawnStormMalus * countBit(kingFlank[wkf] & (rank3 | rank4) & pawns[Co_Black]);
     554       297508 :         pe.score += EvalConfig::pawnStormMalus * countBit(kingFlank[bkf] & (rank5 | rank6) & pawns[Co_White]);
     555              :         
     556              :         // open file near king
     557       148754 :         pe.danger[Co_White] += EvalConfig::kingAttOpenfile * countBit(kingFlank[wkf] & pe.openFiles) / 8;
     558       148754 :         pe.danger[Co_White] += EvalConfig::kingAttSemiOpenfileOpp * countBit(kingFlank[wkf] & pe.semiOpenFiles[Co_White]) / 8;
     559       148754 :         pe.danger[Co_White] += EvalConfig::kingAttSemiOpenfileOur * countBit(kingFlank[wkf] & pe.semiOpenFiles[Co_Black]) / 8;
     560       148754 :         pe.danger[Co_Black] += EvalConfig::kingAttOpenfile * countBit(kingFlank[bkf] & pe.openFiles) / 8;
     561       148754 :         pe.danger[Co_Black] += EvalConfig::kingAttSemiOpenfileOpp * countBit(kingFlank[bkf] & pe.semiOpenFiles[Co_Black]) / 8;
     562       148754 :         pe.danger[Co_Black] += EvalConfig::kingAttSemiOpenfileOur * countBit(kingFlank[bkf] & pe.semiOpenFiles[Co_White]) / 8;
     563              :         
     564              :         // fawn (mostly for fun ...)
     565       148754 :         pe.score -= EvalConfig::pawnFawnMalusKS *
     566       297508 :                     (countBit((pawns[Co_White] & (BBSq_h2 | BBSq_g3)) | (pawns[Co_Black] & BBSq_h3) | (kings[Co_White] & kingSide)) / 4);
     567       148754 :         pe.score += EvalConfig::pawnFawnMalusKS *
     568       297508 :                     (countBit((pawns[Co_Black] & (BBSq_h7 | BBSq_g6)) | (pawns[Co_White] & BBSq_h6) | (kings[Co_Black] & kingSide)) / 4);
     569       148754 :         pe.score -= EvalConfig::pawnFawnMalusQS *
     570       297508 :                     (countBit((pawns[Co_White] & (BBSq_a2 | BBSq_b3)) | (pawns[Co_Black] & BBSq_a3) | (kings[Co_White] & queenSide)) / 4);
     571       148754 :         pe.score += EvalConfig::pawnFawnMalusQS *
     572       297508 :                     (countBit((pawns[Co_Black] & (BBSq_a7 | BBSq_b6)) | (pawns[Co_White] & BBSq_a6) | (kings[Co_Black] & queenSide)) / 4);
     573              :       }
     574              : 
     575              :       context.stats.incr(Stats::sid_ttPawnInsert);
     576       148754 :       pe.h = Hash64to32(computePHash(p)); // this associate the pawn entry to the current K&P positions
     577              :    }
     578       796968 :    assert(pePtr);
     579              :    const Searcher::PawnEntry &pe = *pePtr; // let's use a ref instead of a pointer
     580              :    // add computed or hash score for pawn structure
     581       796968 :    features.scores[F_pawnStruct] += pe.score;
     582              : 
     583              :    // update global things with freshy gotten pawn entry stuff
     584       796968 :    kdanger[Co_White] += pe.danger[Co_White];
     585       796968 :    kdanger[Co_Black] += pe.danger[Co_Black];
     586       796968 :    checkers[Co_White][0] = BBTools::pawnAttacks<Co_Black>(kings[Co_Black]) & pawns[Co_White];
     587       796968 :    checkers[Co_Black][0] = BBTools::pawnAttacks<Co_White>(kings[Co_White]) & pawns[Co_Black];
     588       796968 :    att2[Co_White] |= att[Co_White] & pe.pawnTargets[Co_White];
     589       796968 :    att2[Co_Black] |= att[Co_Black] & pe.pawnTargets[Co_Black];
     590       796968 :    att[Co_White] |= pe.pawnTargets[Co_White];
     591       796968 :    att[Co_Black] |= pe.pawnTargets[Co_Black];
     592              : 
     593              :    STOP_AND_SUM_TIMER(Eval3)
     594              : 
     595              :    //const BitBoard attackedOrNotDefended[2]    = {att[Co_White]  | ~att[Co_Black]  , att[Co_Black]  | ~att[Co_White] };
     596       796968 :    const colored<BitBoard> attackedAndNotDefended   = {att[Co_White] & ~att[Co_Black], att[Co_Black] & ~att[Co_White]};
     597       796968 :    const colored<BitBoard> attacked2AndNotDefended2 = {att2[Co_White] & ~att2[Co_Black], att2[Co_Black] & ~att2[Co_White]};
     598              : 
     599       796968 :    const colored<BitBoard> weakSquare = { att[Co_Black] & ~att2[Co_White] & (~att[Co_White] | attFromPiece[Co_White][P_wk - 1] | attFromPiece[Co_White][P_wq - 1]),
     600       796968 :                                           att[Co_White] & ~att2[Co_Black] & (~att[Co_Black] | attFromPiece[Co_Black][P_wk - 1] | attFromPiece[Co_Black][P_wq - 1])};
     601       796968 :    const colored<BitBoard> safeSquare = { ~att[Co_Black] | (weakSquare[Co_Black] & att2[Co_White]),
     602       796968 :                                           ~att[Co_White] | (weakSquare[Co_White] & att2[Co_Black])};
     603       796968 :    const colored<BitBoard> protectedSquare = {pe.pawnTargets[Co_White] | attackedAndNotDefended[Co_White] | attacked2AndNotDefended2[Co_White],
     604       796968 :                                               pe.pawnTargets[Co_Black] | attackedAndNotDefended[Co_Black] | attacked2AndNotDefended2[Co_Black]};
     605              : 
     606       796968 :    data.haveThreats[Co_White] = (att[Co_White] & p.allPieces[Co_Black]) != emptyBitBoard;
     607       796968 :    data.haveThreats[Co_Black] = (att[Co_Black] & p.allPieces[Co_White]) != emptyBitBoard;
     608              : 
     609       796968 :    data.goodThreats[Co_White] = ((attFromPiece[Co_White][P_wp-1] & p.allPieces[Co_Black] & ~p.blackPawn())
     610       796968 :                                 | (attFromPiece[Co_White][P_wn-1] & (p.blackQueen() | p.blackRook()))
     611       796968 :                                 | (attFromPiece[Co_White][P_wb-1] & (p.blackQueen() | p.blackRook()))
     612       796968 :                                 | (attFromPiece[Co_White][P_wr-1] & p.blackQueen())) != emptyBitBoard;
     613       796968 :    data.goodThreats[Co_Black] = ((attFromPiece[Co_Black][P_wp-1] & p.allPieces[Co_White] & ~p.whitePawn())
     614       796968 :                                 | (attFromPiece[Co_Black][P_wn-1] & (p.whiteQueen() | p.whiteRook()))
     615       796968 :                                 | (attFromPiece[Co_Black][P_wb-1] & (p.whiteQueen() | p.whiteRook()))
     616       796968 :                                 | (attFromPiece[Co_Black][P_wr-1] & p.whiteQueen())) != emptyBitBoard;
     617              : 
     618              :    // reward safe checks
     619       796968 :    kdanger[Co_White] += EvalConfig::kingAttSafeCheck[0] * countBit(checkers[Co_Black][0] & att[Co_Black]);
     620       796968 :    kdanger[Co_Black] += EvalConfig::kingAttSafeCheck[0] * countBit(checkers[Co_White][0] & att[Co_White]);
     621      3984840 :    for (Piece pp = P_wn; pp < P_wk; ++pp) {
     622      3187872 :       kdanger[Co_White] += EvalConfig::kingAttSafeCheck[pp - 1] * countBit(checkers[Co_Black][pp - 1] & safeSquare[Co_Black]);
     623      3187872 :       kdanger[Co_Black] += EvalConfig::kingAttSafeCheck[pp - 1] * countBit(checkers[Co_White][pp - 1] & safeSquare[Co_White]);
     624              :    }
     625              : 
     626              :    // less danger if no enemy queen
     627       796968 :    const Square whiteQueenSquare = queens[Co_White] ? BBTools::SquareFromBitBoard(queens[Co_White]) : INVALIDSQUARE;
     628       796968 :    const Square blackQueenSquare = queens[Co_Black] ? BBTools::SquareFromBitBoard(queens[Co_Black]) : INVALIDSQUARE;
     629       796968 :    kdanger[Co_White] -= blackQueenSquare == INVALIDSQUARE ? EvalConfig::kingAttNoQueen : 0;
     630       796968 :    kdanger[Co_Black] -= whiteQueenSquare == INVALIDSQUARE ? EvalConfig::kingAttNoQueen : 0;
     631              : 
     632              :    // danger : use king danger score. **DO NOT** apply this in end-game
     633       796968 :    const ScoreType dw = EvalConfig::kingAttTable[std::min(std::max(ScoreType(kdanger[Co_White] / 32), ScoreType(0)), ScoreType(63))];
     634      1593936 :    const ScoreType db = EvalConfig::kingAttTable[std::min(std::max(ScoreType(kdanger[Co_Black] / 32), ScoreType(0)), ScoreType(63))];
     635       796968 :    features.scores[F_attack] -= EvalScore(dw, 0);
     636       796968 :    features.scores[F_attack] += EvalScore(db, 0);
     637       796968 :    data.danger[Co_White] = kdanger[Co_White];
     638       796968 :    data.danger[Co_Black] = kdanger[Co_Black];
     639              : 
     640              :    // own piece in front of pawn
     641      1593936 :    features.scores[F_development] += EvalConfig::pieceFrontPawn * countBit(BBTools::shiftN<Co_White>(pawns[Co_White]) & nonPawnMat[Co_White]);
     642      1593936 :    features.scores[F_development] -= EvalConfig::pieceFrontPawn * countBit(BBTools::shiftN<Co_Black>(pawns[Co_Black]) & nonPawnMat[Co_Black]);
     643              : 
     644              :    // pawn in front of own minor
     645       796968 :    const colored<BitBoard> minor = {knights[Co_White] | bishops[Co_White], knights[Co_Black] | bishops[Co_Black]};
     646       796968 :    applyOn(BBTools::shiftS<Co_White>(pawns[Co_White]) & minor[Co_White], [&](const Square & k){ 
     647         8191 :       features.scores[F_development] += EvalConfig::pawnFrontMinor[ColorRank<Co_White>(k)]; 
     648              :    });
     649       796968 :    applyOn(BBTools::shiftS<Co_Black>(pawns[Co_Black]) & minor[Co_Black], [&](const Square & k){
     650         9560 :       features.scores[F_development] -= EvalConfig::pawnFrontMinor[ColorRank<Co_Black>(k)]; 
     651              :    });
     652              : 
     653              :    // center control
     654      1593936 :    features.scores[F_development] += EvalConfig::centerControl * countBit(protectedSquare[Co_White] & extendedCenter);
     655      1593936 :    features.scores[F_development] -= EvalConfig::centerControl * countBit(protectedSquare[Co_Black] & extendedCenter);
     656              : 
     657              :    // pawn hole, unprotected
     658      1593936 :    features.scores[F_positional] += EvalConfig::holesMalus * countBit(pe.holes[Co_White] & ~protectedSquare[Co_White]) / 4;
     659      1593936 :    features.scores[F_positional] -= EvalConfig::holesMalus * countBit(pe.holes[Co_Black] & ~protectedSquare[Co_Black]) / 4;
     660              : 
     661              :    // free passer bonus
     662       796968 :    evalPawnFreePasser<Co_White>(p, pe.passed[Co_White], features.scores[F_pawnStruct]);
     663       796968 :    evalPawnFreePasser<Co_Black>(p, pe.passed[Co_Black], features.scores[F_pawnStruct]);
     664              : 
     665              :    // rook behind passed
     666       796968 :    features.scores[F_pawnStruct] += EvalConfig::rookBehindPassed * (countBit(rooks[Co_White] & BBTools::rearSpan<Co_White>(pe.passed[Co_White])) -
     667      1593936 :                                                                     countBit(rooks[Co_Black] & BBTools::rearSpan<Co_White>(pe.passed[Co_White])));
     668       796968 :    features.scores[F_pawnStruct] -= EvalConfig::rookBehindPassed * (countBit(rooks[Co_Black] & BBTools::rearSpan<Co_Black>(pe.passed[Co_Black])) -
     669      1593936 :                                                                     countBit(rooks[Co_White] & BBTools::rearSpan<Co_Black>(pe.passed[Co_Black])));
     670              : 
     671              :    // protected minor blocking openfile
     672      1593936 :    features.scores[F_positional] += EvalConfig::minorOnOpenFile * countBit(pe.openFiles & (minor[Co_White]) & pe.pawnTargets[Co_White]);
     673      1593936 :    features.scores[F_positional] -= EvalConfig::minorOnOpenFile * countBit(pe.openFiles & (minor[Co_Black]) & pe.pawnTargets[Co_Black]);
     674              : 
     675              :    // knight on opponent hole, protected by pawn
     676      1593936 :    features.scores[F_positional] += EvalConfig::outpostN * countBit(pe.holes[Co_Black] & knights[Co_White] & pe.pawnTargets[Co_White]);
     677      1593936 :    features.scores[F_positional] -= EvalConfig::outpostN * countBit(pe.holes[Co_White] & knights[Co_Black] & pe.pawnTargets[Co_Black]);
     678              : 
     679              :    // bishop on opponent hole, protected by pawn
     680      1593936 :    features.scores[F_positional] += EvalConfig::outpostB * countBit(pe.holes[Co_Black] & bishops[Co_White] & pe.pawnTargets[Co_White]);
     681      1593936 :    features.scores[F_positional] -= EvalConfig::outpostB * countBit(pe.holes[Co_White] & bishops[Co_Black] & pe.pawnTargets[Co_Black]);
     682              : 
     683              :    // knight far from both kings gets a penalty
     684              :    if (kingIsMandatory){
     685       796968 :     applyOn(knights[Co_White], [&](const Square & knighSq){
     686        12731 :         features.scores[F_positional] +=
     687        13995 :             EvalConfig::knightTooFar[std::min(chebyshevDistance(p.king[Co_White], knighSq), chebyshevDistance(p.king[Co_Black], knighSq))];
     688        12731 :     });
     689       805366 :     applyOn(knights[Co_Black], [&](const Square & knighSq){
     690         8398 :         features.scores[F_positional] -=
     691        15982 :             EvalConfig::knightTooFar[std::min(chebyshevDistance(p.king[Co_White], knighSq), chebyshevDistance(p.king[Co_Black], knighSq))];
     692         8398 :     });
     693              :    }
     694              : 
     695              :    // number of hanging pieces
     696       796968 :    const colored<BitBoard> hanging = {nonPawnMat[Co_White] & weakSquare[Co_White], nonPawnMat[Co_Black] & weakSquare[Co_Black]};
     697      1593936 :    features.scores[F_attack] += EvalConfig::hangingPieceMalus * (countBit(hanging[Co_White]) - countBit(hanging[Co_Black]));
     698              : 
     699              :    // threats by minor
     700       796968 :    BitBoard targetThreat = (nonPawnMat[Co_White] | (pawns[Co_White] & weakSquare[Co_White])) & (attFromPiece[Co_Black][P_wn - 1] | attFromPiece[Co_Black][P_wb - 1]);
     701       798860 :    applyOn(targetThreat, [&](const Square & k){
     702         3784 :       features.scores[F_attack] += EvalConfig::threatByMinor[PieceTools::getPieceType(p, k) - 1];
     703         1892 :    });
     704       796968 :    targetThreat = (nonPawnMat[Co_Black] | (pawns[Co_Black] & weakSquare[Co_Black])) & (attFromPiece[Co_White][P_wn - 1] | attFromPiece[Co_White][P_wb - 1]);
     705       799332 :    applyOn(targetThreat, [&](const Square & k){
     706         4728 :       features.scores[F_attack] -= EvalConfig::threatByMinor[PieceTools::getPieceType(p, k) - 1];
     707         2364 :    });
     708              : 
     709              :    // threats by rook
     710       796968 :    targetThreat = p.allPieces[Co_White] & weakSquare[Co_White] & attFromPiece[Co_Black][P_wr - 1];
     711      1203371 :    applyOn(targetThreat, [&](const Square & k){
     712       812806 :       features.scores[F_attack] += EvalConfig::threatByRook[PieceTools::getPieceType(p, k) - 1];
     713       406403 :    });
     714       796968 :    targetThreat = p.allPieces[Co_Black] & weakSquare[Co_Black] & attFromPiece[Co_White][P_wr - 1];
     715      1218999 :    applyOn(targetThreat, [&](const Square & k){
     716       844062 :       features.scores[F_attack] -= EvalConfig::threatByRook[PieceTools::getPieceType(p, k) - 1];
     717       422031 :    });
     718              : 
     719              :    // threats by queen
     720       796968 :    targetThreat = p.allPieces[Co_White] & weakSquare[Co_White] & attFromPiece[Co_Black][P_wq - 1];
     721      1105139 :    applyOn(targetThreat, [&](const Square & k){
     722       616342 :       features.scores[F_attack] += EvalConfig::threatByQueen[PieceTools::getPieceType(p, k) - 1];
     723       308171 :    });
     724       796968 :    targetThreat = p.allPieces[Co_Black] & weakSquare[Co_Black] & attFromPiece[Co_White][P_wq - 1];
     725      1131919 :    applyOn(targetThreat, [&](const Square & k){
     726       669902 :       features.scores[F_attack] -= EvalConfig::threatByQueen[PieceTools::getPieceType(p, k) - 1];
     727       334951 :    });
     728              : 
     729              :    // threats by king
     730       796968 :    targetThreat = p.allPieces[Co_White] & weakSquare[Co_White] & attFromPiece[Co_Black][P_wk - 1];
     731       831643 :    applyOn(targetThreat, [&](const Square & k){
     732        69350 :       features.scores[F_attack] += EvalConfig::threatByKing[PieceTools::getPieceType(p, k) - 1];
     733        34675 :    });
     734       796968 :    targetThreat = p.allPieces[Co_Black] & weakSquare[Co_Black] & attFromPiece[Co_White][P_wk - 1];
     735       820917 :    applyOn(targetThreat, [&](const Square & k){
     736        47898 :       features.scores[F_attack] -= EvalConfig::threatByKing[PieceTools::getPieceType(p, k) - 1];
     737        23949 :    });
     738              : 
     739              :    // threat by safe pawn
     740       796968 :    const colored<BitBoard> safePawnAtt = {nonPawnMat[Co_Black] & BBTools::pawnAttacks<Co_White>(pawns[Co_White] & safeSquare[Co_White]),
     741       796968 :                                           nonPawnMat[Co_White] & BBTools::pawnAttacks<Co_Black>(pawns[Co_Black] & safeSquare[Co_Black])};
     742      1593936 :    features.scores[F_attack] += EvalConfig::pawnSafeAtt * (countBit(safePawnAtt[Co_White]) - countBit(safePawnAtt[Co_Black]));
     743              : 
     744              :    // safe pawn push (protected once or not attacked)
     745       796968 :    const colored<BitBoard> safePawnPush = {BBTools::shiftN<Co_White>(pawns[Co_White]) & ~occupancy & safeSquare[Co_White],
     746       796968 :                                            BBTools::shiftN<Co_Black>(pawns[Co_Black]) & ~occupancy & safeSquare[Co_Black]};
     747      1593936 :    features.scores[F_mobility] += EvalConfig::pawnMobility * (countBit(safePawnPush[Co_White]) - countBit(safePawnPush[Co_Black]));
     748              : 
     749              :    // threat by safe pawn push
     750              :    features.scores[F_attack] +=
     751      1593936 :        EvalConfig::pawnSafePushAtt * (countBit(nonPawnMat[Co_Black] & BBTools::pawnAttacks<Co_White>(safePawnPush[Co_White])) -
     752      1593936 :                                       countBit(nonPawnMat[Co_White] & BBTools::pawnAttacks<Co_Black>(safePawnPush[Co_Black])));
     753              : 
     754              :    STOP_AND_SUM_TIMER(Eval4)
     755              : 
     756              :    // pieces mobility (second attack loop needed, knowing safeSquare ...)
     757       796968 :    evalMob<P_wn, Co_White>(p, knights[Co_White], features.scores[F_mobility], safeSquare[Co_White], occupancy, data.mobility[Co_White]);
     758       796968 :    evalMob<P_wb, Co_White>(p, bishops[Co_White], features.scores[F_mobility], safeSquare[Co_White], occupancy, data.mobility[Co_White]);
     759       796968 :    evalMob<P_wr, Co_White>(p, rooks  [Co_White], features.scores[F_mobility], safeSquare[Co_White], occupancy, data.mobility[Co_White]);
     760       796968 :    evalMobQ<     Co_White>(p, queens [Co_White], features.scores[F_mobility], safeSquare[Co_White], occupancy, data.mobility[Co_White]);
     761      1593936 :    evalMobK<     Co_White>(p, kings  [Co_White], features.scores[F_mobility], ~att[Co_Black]      , occupancy, data.mobility[Co_White]);
     762       796968 :    evalMob<P_wn, Co_Black>(p, knights[Co_Black], features.scores[F_mobility], safeSquare[Co_Black], occupancy, data.mobility[Co_Black]);
     763       796968 :    evalMob<P_wb, Co_Black>(p, bishops[Co_Black], features.scores[F_mobility], safeSquare[Co_Black], occupancy, data.mobility[Co_Black]);
     764       796968 :    evalMob<P_wr, Co_Black>(p, rooks  [Co_Black], features.scores[F_mobility], safeSquare[Co_Black], occupancy, data.mobility[Co_Black]);
     765       796968 :    evalMobQ<     Co_Black>(p, queens [Co_Black], features.scores[F_mobility], safeSquare[Co_Black], occupancy, data.mobility[Co_Black]);
     766       796968 :    evalMobK<     Co_Black>(p, kings  [Co_Black], features.scores[F_mobility], ~att[Co_White]      , occupancy, data.mobility[Co_Black]);
     767              : 
     768              :    STOP_AND_SUM_TIMER(Eval5)
     769              : 
     770              :    // rook on open file
     771      1593936 :    features.scores[F_positional] += EvalConfig::rookOnOpenFile * countBit(rooks[Co_White] & pe.openFiles);
     772      1593936 :    features.scores[F_positional] += EvalConfig::rookOnOpenSemiFileOur * countBit(rooks[Co_White] & pe.semiOpenFiles[Co_White]);
     773      1593936 :    features.scores[F_positional] += EvalConfig::rookOnOpenSemiFileOpp * countBit(rooks[Co_White] & pe.semiOpenFiles[Co_Black]);
     774      1593936 :    features.scores[F_positional] -= EvalConfig::rookOnOpenFile * countBit(rooks[Co_Black] & pe.openFiles);
     775      1593936 :    features.scores[F_positional] -= EvalConfig::rookOnOpenSemiFileOur * countBit(rooks[Co_Black] & pe.semiOpenFiles[Co_Black]);
     776      1593936 :    features.scores[F_positional] -= EvalConfig::rookOnOpenSemiFileOpp * countBit(rooks[Co_Black] & pe.semiOpenFiles[Co_White]);
     777              : 
     778              :    // enemy rook facing king
     779      1593936 :    features.scores[F_positional] += EvalConfig::rookFrontKingMalus * countBit(BBTools::frontSpan<Co_White>(kings[Co_White]) & rooks[Co_Black]);
     780      1593936 :    features.scores[F_positional] -= EvalConfig::rookFrontKingMalus * countBit(BBTools::frontSpan<Co_Black>(kings[Co_Black]) & rooks[Co_White]);
     781              : 
     782              :    // enemy rook facing queen
     783      1593936 :    features.scores[F_positional] += EvalConfig::rookFrontQueenMalus * countBit(BBTools::frontSpan<Co_White>(queens[Co_White]) & rooks[Co_Black]);
     784      1593936 :    features.scores[F_positional] -= EvalConfig::rookFrontQueenMalus * countBit(BBTools::frontSpan<Co_Black>(queens[Co_Black]) & rooks[Co_White]);
     785              : 
     786              :    // queen aligned with own rook
     787      1593936 :    features.scores[F_positional] += EvalConfig::rookQueenSameFile * countBit(BBTools::fillFile(queens[Co_White]) & rooks[Co_White]);
     788      1593936 :    features.scores[F_positional] -= EvalConfig::rookQueenSameFile * countBit(BBTools::fillFile(queens[Co_Black]) & rooks[Co_Black]);
     789              : 
     790              :    // pins on king and queen
     791       796968 :    const colored<BitBoard> pinnedK = {getPinned<Co_White>(p, p.king[Co_White]), getPinned<Co_Black>(p, p.king[Co_Black])};
     792       796968 :    const colored<BitBoard> pinnedQ = {getPinned<Co_White>(p, whiteQueenSquare), getPinned<Co_Black>(p, blackQueenSquare)};
     793      4781808 :    for (Piece pp = P_wp; pp < P_wk; ++pp) {
     794      3984840 :       if (const BitBoard bw = p.pieces_const(Co_White, pp); bw) {
     795      1919470 :          if (pinnedK[Co_White] & bw) features.scores[F_attack] -= EvalConfig::pinnedKing[pp - 1] * countBit(pinnedK[Co_White] & bw);
     796      1855410 :          if (pinnedQ[Co_White] & bw) features.scores[F_attack] -= EvalConfig::pinnedQueen[pp - 1] * countBit(pinnedQ[Co_White] & bw);
     797              :       }
     798      3984840 :       if (const BitBoard bb = p.pieces_const(Co_Black, pp); bb) {
     799      2104240 :          if (pinnedK[Co_Black] & bb) features.scores[F_attack] += EvalConfig::pinnedKing[pp - 1] * countBit(pinnedK[Co_Black] & bb);
     800      2033429 :          if (pinnedQ[Co_Black] & bb) features.scores[F_attack] += EvalConfig::pinnedQueen[pp - 1] * countBit(pinnedQ[Co_Black] & bb);
     801              :       }
     802              :    }
     803              : 
     804              :    // attack : queen distance to opponent king (wrong if multiple queens ...)
     805       796968 :    if (kingIsMandatory && blackQueenSquare != INVALIDSQUARE)
     806       896620 :       features.scores[F_positional] -= EvalConfig::queenNearKing * (7 - chebyshevDistance(p.king[Co_White], blackQueenSquare));
     807       796968 :    if (kingIsMandatory && whiteQueenSquare != INVALIDSQUARE)
     808       554362 :       features.scores[F_positional] += EvalConfig::queenNearKing * (7 - chebyshevDistance(p.king[Co_Black], whiteQueenSquare));
     809              : 
     810              :    // number of pawn and piece type value  ///@todo closedness instead ?
     811      1593936 :    features.scores[F_material] += EvalConfig::adjRook[p.mat[Co_White][M_p]] * ScoreType(p.mat[Co_White][M_r]);
     812      1593936 :    features.scores[F_material] -= EvalConfig::adjRook[p.mat[Co_Black][M_p]] * ScoreType(p.mat[Co_Black][M_r]);
     813      1593936 :    features.scores[F_material] += EvalConfig::adjKnight[p.mat[Co_White][M_p]] * ScoreType(p.mat[Co_White][M_n]);
     814      1593936 :    features.scores[F_material] -= EvalConfig::adjKnight[p.mat[Co_Black][M_p]] * ScoreType(p.mat[Co_Black][M_n]);
     815              : 
     816              :    // bad bishop
     817       796968 :    if (p.whiteLightBishop()) features.scores[F_material] -= EvalConfig::badBishop[countBit(pawns[Co_White] & whiteSquare)];
     818       796968 :    if (p.whiteDarkBishop()) features.scores[F_material] -= EvalConfig::badBishop[countBit(pawns[Co_White] & blackSquare)];
     819       796968 :    if (p.blackLightBishop()) features.scores[F_material] += EvalConfig::badBishop[countBit(pawns[Co_Black] & whiteSquare)];
     820       796968 :    if (p.blackDarkBishop()) features.scores[F_material] += EvalConfig::badBishop[countBit(pawns[Co_Black] & blackSquare)];
     821              : 
     822              :    // adjust piece pair score
     823       796968 :    features.scores[F_material] += ((p.mat[Co_White][M_b] > 1 ? EvalConfig::bishopPairBonus[p.mat[Co_White][M_p]] : 0) -
     824      1593936 :                                    (p.mat[Co_Black][M_b] > 1 ? EvalConfig::bishopPairBonus[p.mat[Co_Black][M_p]] : 0));
     825       796968 :    features.scores[F_material] += ((p.mat[Co_White][M_n] > 1 ? EvalConfig::knightPairMalus : 0) -
     826      1593936 :                                    (p.mat[Co_Black][M_n] > 1 ? EvalConfig::knightPairMalus : 0));
     827       796968 :    features.scores[F_material] += ((p.mat[Co_White][M_r] > 1 ? EvalConfig::rookPairMalus : 0) -
     828      1593936 :                                    (p.mat[Co_Black][M_r] > 1 ? EvalConfig::rookPairMalus : 0));
     829              : 
     830              :    // complexity
     831              :    // an "anti human" trick : winning side wants to keep the position more complex
     832      1593936 :    features.scores[F_complexity] += EvalScore {1, 0} * (white2Play ? +1 : -1) * 
     833      1593936 :                                     (p.mat[Co_White][M_t] + p.mat[Co_Black][M_t] + (p.mat[Co_White][M_p] + p.mat[Co_Black][M_p]) / 2);
     834              : 
     835       796968 :    if (display) displayEval(data, features);
     836              : 
     837              :    // taking Style into account, giving each score a [0..2] factor
     838       796968 :    features.scores[F_material]    = features.scores[F_material]   .scale(1 + (DynamicConfig::styleMaterial    - 50) / 50.f, 1.f);
     839       796968 :    features.scores[F_positional]  = features.scores[F_positional] .scale(1 + (DynamicConfig::stylePositional  - 50) / 50.f, 1.f);
     840       796968 :    features.scores[F_development] = features.scores[F_development].scale(1 + (DynamicConfig::styleDevelopment - 50) / 50.f, 1.f);
     841       796968 :    features.scores[F_mobility]    = features.scores[F_mobility]   .scale(1 + (DynamicConfig::styleMobility    - 50) / 50.f, 1.f);
     842       796968 :    features.scores[F_pawnStruct]  = features.scores[F_pawnStruct] .scale(1 + (DynamicConfig::stylePawnStruct  - 50) / 50.f, 1.f);
     843       796968 :    features.scores[F_attack]      = features.scores[F_attack]     .scale(1 + (DynamicConfig::styleAttack      - 50) / 50.f, 1.f);
     844       796968 :    features.scores[F_complexity]  = features.scores[F_complexity] .scale((DynamicConfig::styleComplexity      - 50) / 50.f, 0.f);
     845              : 
     846              :    // sum every score contribution
     847       796968 :    EvalScore score = features.SumUp();
     848              : 
     849              : #ifdef VERBOSE_EVAL
     850              :    if (display) {
     851              :       Logging::LogIt(Logging::logInfo) << "Post correction ... ";
     852              :       displayEval(data, features);
     853              :       Logging::LogIt(Logging::logInfo) << "> All (before 2nd order) " << score;
     854              :    }
     855              : #endif
     856              : 
     857              :    // initiative (kind of second order pawn structure stuff for end-games)
     858              :    const BitBoard &allPawns = p.allPawn();
     859       796968 :    EvalScore initiativeBonus = EvalConfig::initiative[0] * countBit(allPawns) +
     860       796968 :                                EvalConfig::initiative[1] * ((allPawns & queenSide) && (allPawns & kingSide)) +
     861       796968 :                                EvalConfig::initiative[2] * (countBit(occupancy & ~allPawns) == 2) - EvalConfig::initiative[3];
     862      1593958 :    initiativeBonus = EvalScore(sgn(score[MG]) * std::max(initiativeBonus[MG], static_cast<ScoreType>(-Abs(score[MG]))),
     863       796968 :                                sgn(score[EG]) * std::max(initiativeBonus[EG], static_cast<ScoreType>(-Abs(score[EG]))));
     864       796968 :    score += initiativeBonus;
     865              : 
     866              : #ifdef VERBOSE_EVAL
     867              :    if (display) {
     868              :       Logging::LogIt(Logging::logInfo) << "Initiative    " << initiativeBonus;
     869              :       Logging::LogIt(Logging::logInfo) << "> All (with initiative) " << score;
     870              :    }
     871              : #endif
     872              : 
     873              :    // add contempt
     874       796968 :    score += context.contempt;
     875              : 
     876              : #ifdef VERBOSE_EVAL
     877              :    if (display) { Logging::LogIt(Logging::logInfo) << "> All (with contempt) " << score; }
     878              : #endif
     879              : 
     880              :    // compute a scale factor in some other end-game cases that are not using the material table:
     881       796968 :    if (features.scalingFactor == 1.f && !DynamicConfig::armageddon) {
     882       796968 :       const Color strongSide = score[EG] > 0 ? Co_White : Co_Black;
     883              :       
     884              :       // opposite colored bishops (scale based on passed pawn of strong side)
     885       796968 :       if (p.mat[Co_White][M_b] == 1 && p.mat[Co_Black][M_b] == 1 && countBit(p.allBishop() & whiteSquare) == 1) {
     886            5 :          if (p.mat[Co_White][M_t] == 1 && p.mat[Co_Black][M_t] == 1) // only bishops and pawn
     887            0 :             features.scalingFactor =
     888            0 :                 (EvalConfig::scalingFactorOppBishopAlone + EvalConfig::scalingFactorOppBishopAloneSlope * countBit(pe.passed[strongSide])) / 128.f;
     889              :          else // more pieces present
     890            5 :             features.scalingFactor =
     891            5 :                 (EvalConfig::scalingFactorOppBishop + EvalConfig::scalingFactorOppBishopSlope * countBit(p.allPieces[strongSide])) / 128.f;
     892              :       }
     893              :       
     894              :       // queen versus no queen (scale on number of minor of no queen side)
     895       796963 :       else if (countBit(p.allQueen()) == 1) {
     896       546658 :          features.scalingFactor =
     897       905971 :              (EvalConfig::scalingFactorQueenNoQueen + EvalConfig::scalingFactorQueenNoQueenSlope * p.mat[p.whiteQueen() ? Co_Black : Co_White][M_m]) / 128.f;
     898              :       }
     899              :       
     900              :       // scale based on the number of pawn of strong side
     901              :       else
     902       250305 :          features.scalingFactor =
     903       252312 :              std::min(1.f, (EvalConfig::scalingFactorPawns + EvalConfig::scalingFactorPawnsSlope * p.mat[strongSide][M_p]) / 128.f);
     904              : 
     905              :       // moreover scaledown if pawn on only one side
     906       796968 :       if (allPawns && !((allPawns & queenSide) && (allPawns & kingSide))) { features.scalingFactor -= EvalConfig::scalingFactorPawnsOneSide / 128.f; }
     907              :    }
     908       796968 :    if (DynamicConfig::armageddon) features.scalingFactor = 1.f; ///@todo better
     909              : 
     910              : #ifdef VERBOSE_EVAL
     911              :    if (display) { Logging::LogIt(Logging::logInfo) << "Scaling factor (corrected) " << features.scalingFactor; }
     912              : #endif
     913              : 
     914              :    // fuse MG and EG score
     915              :    // scale both game phase and end-game scaling factor
     916       796968 :    ScoreType ret = ScaleScore(score, data.gp, features.scalingFactor);
     917              : 
     918              : #ifdef VERBOSE_EVAL
     919              :    if (display) { Logging::LogIt(Logging::logInfo) << "> All (with game phase scaling) " << ret; }
     920              : #endif
     921              : 
     922       796968 :    if (!DynamicConfig::armageddon){
     923              :       // apply scaling factor based on fifty move rule
     924       796968 :       ret = fiftyScale(ret, p.fifty);
     925              :    }
     926              : 
     927              : #ifdef VERBOSE_EVAL
     928              :    if (display) { Logging::LogIt(Logging::logInfo) << "> All (with last scaling) " << ret; }
     929              : #endif
     930              : 
     931              :    // apply tempo
     932      1163671 :    ret += EvalConfig::tempo * (white2Play ? +1 : -1);
     933              : 
     934              : #ifdef VERBOSE_EVAL
     935              :    if (display) { Logging::LogIt(Logging::logInfo) << "> All (with tempo) " << ret; }
     936              : #endif
     937              : 
     938              :    // clamp score
     939       796968 :    ret = clampScore(ret);
     940              : 
     941              : #ifdef VERBOSE_EVAL
     942              :    if (display) { Logging::LogIt(Logging::logInfo) << "> All (clamped) " << ret; }
     943              : #endif
     944              : 
     945              :    // take side to move into account
     946       796968 :    ret = (white2Play ? +1 : -1) * ret;
     947              : 
     948       796969 :    if (display) { Logging::LogIt(Logging::logInfo) << "==> All (fully scaled) " << ret; }
     949              : 
     950       796968 :    data.evalDone = true;
     951              :    // apply variante scoring if requiered
     952       796968 :    const ScoreType hceScore = variantScore(ret, p.halfmoves, context.height_, p.c);
     953              : 
     954              : #ifdef WITH_NNUE
     955       796968 :    if ( DynamicConfig::useNNUE && !forbiddenNNUE && Abs(hceScore) <= DynamicConfig::NNUEThreshold2 ){
     956              :       // if HCE is small (there is something more than just material value going on ...), fall back to NNUE;
     957         5476 :       const ScoreType nnueScore = NNUEEVal(p, data, context, features, true);
     958              :       STOP_AND_SUM_TIMER(Eval)
     959         5476 :       return nnueScore;
     960              :    }
     961              : #endif
     962              : 
     963              :    STOP_AND_SUM_TIMER(Eval)
     964              :    return hceScore;
     965              : }
     966              : 
     967              : #pragma GCC diagnostic pop
        

Generated by: LCOV version 2.0-1