LCOV - code coverage report
Current view: top level - Source - position.hpp (source / functions) Coverage Total Hit
Test: coverage Lines: 91.1 % 146 133
Test Date: 2026-03-02 16:42:41 Functions: 94.4 % 36 34

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "bitboard.hpp"
       4              : #include "definition.hpp"
       5              : #include "moveApply.hpp"
       6              : #include "timers.hpp"
       7              : 
       8              : #ifdef WITH_NNUE
       9              : #include "nnue.hpp"
      10              : 
      11              : [[nodiscard]] static constexpr size_t getBlock(const Square ksq) {
      12    860236914 :    return ksq;
      13              :    //return (ksq / 16) * 4 + ((ksq % 8) / 2);
      14              : }
      15              : 
      16              : [[nodiscard]] static constexpr size_t NNUEIndiceUs(const Square ksq, const Square s, const Piece p) {
      17    504112337 :    return nnue::FeatureIdx::major * getBlock(HFlip(ksq)) + HFlip(s) + nnue::FeatureIdx::usOffset(p);
      18              : }
      19              : 
      20              : [[nodiscard]] static constexpr size_t NNUEIndiceThem(const Square ksq, const Square s, const Piece p) {
      21    528374021 :    return nnue::FeatureIdx::major * getBlock(HFlip(ksq)) + HFlip(s) + nnue::FeatureIdx::themOffset(p);
      22              : }
      23              : #endif // WITH_NNUE
      24              : 
      25              : struct Position; // forward decl
      26              : struct RootPosition; // forward decl
      27              : 
      28              : /*!
      29              :  * Main Position initialisation function
      30              :  * - silent will forbid logging (for info, not for error !)
      31              :  * - withMoveCount shall be set in order to read last part of the FEN string
      32              :  */
      33              : bool readFEN(const std::string& fen, RootPosition& p, bool silent = false, bool withMoveCount = false); // forward decl
      34              : 
      35              : /*!
      36              :  * Informations associated with an initially given Position (from readFEN)
      37              :  * There will not change inside the search tree
      38              :  */
      39           89 : struct RootInformation {
      40              :    array1d<CastlingRights, NbSquare> castlePermHashTable = {CastlingRights::C_none}; // C_none is 0 so ok
      41              :    array2d<Square, 2, 2> rooksInit = {{{INVALIDSQUARE, INVALIDSQUARE}, {INVALIDSQUARE, INVALIDSQUARE}}};
      42              :    colored<Square> kingInit  = {INVALIDSQUARE, INVALIDSQUARE};
      43              :    void initCaslingPermHashTable();
      44              : };
      45              : 
      46              : /*!
      47              :  * The main position structure
      48              :  * Storing
      49              :  *  - board
      50              :  *  - all bitboards
      51              :  *  - material
      52              :  *  - hash (full position and just K+P)
      53              :  *  - some game status info
      54              :  *
      55              :  *  Contains also some usefull accessor
      56              :  *
      57              :  * Minic is a copy/make engine, so that this structure is copied a lot !
      58              :  */
      59              : struct alignas(32) Position {
      60              :    Position();
      61              :    virtual ~Position();
      62              : 
      63              :    array1d<Piece, NbSquare> _b {{P_none}}; // works because P_none is in fact 0
      64              :    array1d<BitBoard, 6>     _allB {{emptyBitBoard}}; // works because emptyBitBoard is in fact 0
      65              :    array1d<BitBoard, 2>     allPieces {{emptyBitBoard}}; // works because emptyBitBoard is in fact 0
      66              : 
      67              :    // t p n b r q k bl bd M n x x x x x (total is first so that pawn to king is same index as Piece type)
      68              :    using Material = colored<array1d<uint8_t, 16>>;
      69              :    Material mat = {{{{0}}}}; // such a nice syntax ...
      70              : 
      71              :    // shared by all "child" of a same "root" position
      72              :    // Assumed rule of 3 disrespect
      73              :    // the default copy CTOR and copy operator will copy that
      74              :    // but only a RootPosition will delete it
      75              :    // (this is way faster than a shared_ptr)
      76              :    mutable RootInformation* root = nullptr;
      77              : 
      78              : #ifdef WITH_NNUE
      79              :    mutable NNUEEvaluator* associatedEvaluator = nullptr;
      80              : #endif
      81              :    
      82              :    mutable Hash    h         = nullHash;
      83              :    mutable Hash    ph        = nullHash;
      84              :    MiniMove        lastMove  = INVALIDMINIMOVE;
      85              :    uint16_t        moves     = 0;
      86              :    uint16_t        halfmoves = 0;
      87              :    colored<Square> king      = {INVALIDSQUARE, INVALIDSQUARE};
      88              :    Square          ep        = INVALIDSQUARE;
      89              :    uint8_t         fifty     = 0;
      90              :    CastlingRights  castling  = C_none;
      91              :    Color           c         = Co_White;
      92              : 
      93              :    inline void clear(){
      94          308 :       _b        = {{P_none}};
      95          308 :       _allB     = {{emptyBitBoard}};
      96          308 :       allPieces = {{emptyBitBoard}};
      97          308 :       mat       = {{{{0}}}};
      98          308 :       h         = nullHash;
      99          308 :       ph        = nullHash;
     100          308 :       lastMove  = INVALIDMINIMOVE;
     101          308 :       moves     = 0;
     102          308 :       halfmoves = 0;
     103          308 :       king      = {INVALIDSQUARE, INVALIDSQUARE};
     104              :       //root     = nullptr;
     105          308 :       ep        = INVALIDSQUARE;
     106          308 :       fifty     = 0;
     107          308 :       castling  = C_none;
     108          308 :       c         = Co_White;
     109              :    }
     110              : 
     111              :    //Position & operator=(const Position & p2);
     112              :    //Position(const Position& p);
     113              : 
     114              : #ifdef DEBUG_FIFTY_COLLISION
     115              :    [[nodiscard]] bool operator== (const Position &p)const{
     116              :       return _allB == p._allB && ep == p.ep && castling == p.castling && c == p.c;
     117              :    }
     118              :    [[nodiscard]] bool operator!= (const Position &p)const{
     119              :       return _allB != p._allB || ep != p.ep || castling != p.castling || c != p.c;
     120              :    }
     121              : #endif
     122              : 
     123              :    [[nodiscard]] FORCE_FINLINE RootInformation& rootInfo() {
     124    149093056 :       assert(root);
     125              :       return *root;
     126              :    }
     127              : 
     128              :    [[nodiscard]] FORCE_FINLINE const RootInformation& rootInfo() const {
     129     14453171 :       assert(root);
     130              :       return *root;
     131              :    }
     132              : 
     133    402863938 :    [[nodiscard]] FORCE_FINLINE const Piece& board_const(const Square k) const { return _b[k]; }
     134    179518446 :    [[nodiscard]] FORCE_FINLINE Piece&       board      (const Square k)       { return _b[k]; }
     135              : 
     136    344496684 :    [[nodiscard]] FORCE_FINLINE BitBoard occupancy() const { return allPieces[Co_White] | allPieces[Co_Black]; }
     137              : 
     138     13649408 :    [[nodiscard]] FORCE_FINLINE BitBoard allKing()   const { return _allB[5]; }
     139     17220899 :    [[nodiscard]] FORCE_FINLINE BitBoard allQueen()  const { return _allB[4]; }
     140     16423936 :    [[nodiscard]] FORCE_FINLINE BitBoard allRook()   const { return _allB[3]; }
     141     16423996 :    [[nodiscard]] FORCE_FINLINE BitBoard allBishop() const { return _allB[2]; }
     142      5790404 :    [[nodiscard]] FORCE_FINLINE BitBoard allKnight() const { return _allB[1]; }
     143       796968 :    [[nodiscard]] FORCE_FINLINE BitBoard allPawn()   const { return _allB[0]; }
     144              : 
     145     43653193 :    [[nodiscard]] FORCE_FINLINE BitBoard blackKing()   const { return _allB[5] & allPieces[Co_Black]; }
     146     48799078 :    [[nodiscard]] FORCE_FINLINE BitBoard blackQueen()  const { return _allB[4] & allPieces[Co_Black]; }
     147     44471781 :    [[nodiscard]] FORCE_FINLINE BitBoard blackRook()   const { return _allB[3] & allPieces[Co_Black]; }
     148     58083089 :    [[nodiscard]] FORCE_FINLINE BitBoard blackBishop() const { return _allB[2] & allPieces[Co_Black]; }
     149     43676217 :    [[nodiscard]] FORCE_FINLINE BitBoard blackKnight() const { return _allB[1] & allPieces[Co_Black]; }
     150     49792373 :    [[nodiscard]] FORCE_FINLINE BitBoard blackPawn()   const { return _allB[0] & allPieces[Co_Black]; }
     151              : 
     152    166249740 :    [[nodiscard]] FORCE_FINLINE BitBoard whitePawn()   const { return _allB[0] & allPieces[Co_White]; }
     153    157098204 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteKnight() const { return _allB[1] & allPieces[Co_White]; }
     154    172408326 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteBishop() const { return _allB[2] & allPieces[Co_White]; }
     155    162569770 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteRook()   const { return _allB[3] & allPieces[Co_White]; }
     156    161304110 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteQueen()  const { return _allB[4] & allPieces[Co_White]; }
     157    157036089 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteKing()   const { return _allB[5] & allPieces[Co_White]; }
     158              : 
     159       796968 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteLightBishop() const { return whiteBishop() & BB::whiteSquare; }
     160       796968 :    [[nodiscard]] FORCE_FINLINE BitBoard whiteDarkBishop()  const { return whiteBishop() & BB::blackSquare; }
     161       796968 :    [[nodiscard]] FORCE_FINLINE BitBoard blackLightBishop() const { return blackBishop() & BB::whiteSquare; }
     162       796968 :    [[nodiscard]] FORCE_FINLINE BitBoard blackDarkBishop()  const { return blackBishop() & BB::blackSquare; }
     163              : 
     164              :    template<Piece pp> [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Color cc) const {
     165              :       assert(pp > P_none);
     166              :       assert(pp < P_end);
     167     74178426 :       assert(cc == Co_White || cc == Co_Black);
     168     86185112 :       return _allB[pp - 1] & allPieces[cc];
     169              :    }
     170              :    [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Color cc, const Piece pp) const {
     171     36372036 :       assert(pp > P_none);
     172              :       assert(pp < P_end);
     173     70209278 :       assert(cc == Co_White || cc == Co_Black);
     174     76043179 :       return _allB[pp - 1] & allPieces[cc];
     175              :    }
     176              :    [[nodiscard]] FORCE_FINLINE BitBoard pieces_const(const Piece pp) const {
     177            0 :       assert(pp != P_none);
     178            0 :       assert(pp < P_end);
     179            0 :       assert(pp >= P_bk);
     180            0 :       return _allB[Abs(pp) - 1] & allPieces[pp > 0 ? Co_White : Co_Black];
     181              :    }
     182              :    // next one is kinda "private"
     183              :    [[nodiscard]] FORCE_FINLINE BitBoard& _pieces(const Piece pp) {
     184       359636 :       assert(pp != P_none);
     185    190428043 :       assert(pp < P_end);
     186    190428043 :       assert(pp >= P_bk);
     187    369701035 :       return _allB[Abs(pp) - 1];
     188              :    }
     189              : 
     190              : #ifdef WITH_NNUE
     191              :    void associateEvaluator(NNUEEvaluator& evaluator, bool dirty = true) { 
     192      5403534 :       associatedEvaluator = &evaluator; 
     193      5403534 :       evaluator.dirty = dirty;
     194              :    }
     195              : 
     196              :    void dissociateEvaluator() { 
     197            0 :       associatedEvaluator = nullptr; 
     198              :    }
     199              : 
     200              :    [[nodiscard]] NNUEEvaluator& evaluator() {
     201    175305545 :       assert(associatedEvaluator);
     202              :       return *associatedEvaluator;
     203              :    }
     204              :    [[nodiscard]] const NNUEEvaluator& evaluator() const {
     205      7530209 :       assert(associatedEvaluator);
     206              :       return *associatedEvaluator;
     207              :    }
     208              :    [[nodiscard]] bool hasEvaluator() const {
     209          308 :       return associatedEvaluator != nullptr;
     210              :    }
     211              : 
     212              :    // Vastly taken from Seer implementation.
     213              :    // see https://github.com/connormcmonigle/seer-nnue
     214              : 
     215      8634774 :    template<Color c> void resetNNUEIndices_(NNUEEvaluator& nnueEvaluator) const {
     216              :       //us
     217    110278718 :       BB::applyOn(pieces_const<P_wp>(c), [&](const Square & k) {
     218     50821972 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wp)); 
     219              :       });
     220     26723550 :       BB::applyOn(pieces_const<P_wn>(c), [&](const Square & k) {
     221      9044388 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wn)); 
     222              :       });
     223     26703814 :       BB::applyOn(pieces_const<P_wb>(c), [&](const Square & k) {
     224      9034520 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wb)); 
     225              :       });
     226     36012810 :       BB::applyOn(pieces_const<P_wr>(c), [&](const Square & k) {
     227     13689018 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wr));
     228              :       });
     229     18840972 :       BB::applyOn(pieces_const<P_wq>(c), [&](const Square & k) {
     230      5103099 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wq)); 
     231              :       });
     232     25904322 :       BB::applyOn(pieces_const<P_wk>(c), [&](const Square & k) {
     233      8634774 :          nnueEvaluator.template us<c>().insert(NNUEIndiceUs(king[c], k, P_wk));
     234              :       });
     235              :       //them
     236    109332378 :       BB::applyOn(pieces_const<P_wp>(~c), [&](const Square & k) {
     237     50348802 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wp)); 
     238              :       });
     239     26884060 :       BB::applyOn(pieces_const<P_wn>(~c), [&](const Square & k) {
     240      9124643 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wn)); 
     241              :       });
     242     26913852 :       BB::applyOn(pieces_const<P_wb>(~c), [&](const Square & k) {
     243      9139539 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wb)); 
     244              :       });
     245     36303432 :       BB::applyOn(pieces_const<P_wr>(~c), [&](const Square & k) {
     246     13834329 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wr));
     247              :       });
     248     18828310 :       BB::applyOn(pieces_const<P_wq>(~c), [&](const Square & k) {
     249      5096768 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wq)); 
     250              :       });
     251     25904322 :       BB::applyOn(pieces_const<P_wk>(~c), [&](const Square & k) {
     252      8634774 :          nnueEvaluator.template us<c>().insert(NNUEIndiceThem(king[c], k, P_wk));
     253              :       });
     254      8634774 :    }
     255              : 
     256         1218 :    void resetNNUEEvaluator(NNUEEvaluator& nnueEvaluator) const {
     257              :       START_TIMER
     258              :       nnueEvaluator.clear();
     259         1218 :       resetNNUEIndices_<Co_White>(nnueEvaluator);
     260         1218 :       resetNNUEIndices_<Co_Black>(nnueEvaluator);
     261         1218 :       nnueEvaluator.dirty = false;
     262              :       STOP_AND_SUM_TIMER(ResetNNUE)
     263         1218 :    }
     264              : 
     265      8632338 :    void resetNNUEEvaluator(NNUEEvaluator& nnueEvaluator, Color color) const {
     266              :       START_TIMER
     267              :       nnueEvaluator.clear(color);
     268      8632338 :       if (color == Co_White)
     269      1735711 :          resetNNUEIndices_<Co_White>(nnueEvaluator);
     270              :       else
     271      6896627 :          resetNNUEIndices_<Co_Black>(nnueEvaluator);
     272      8632338 :       nnueEvaluator.dirty = false;
     273              :       STOP_AND_SUM_TIMER(ResetNNUE)
     274      8632338 :    }
     275              : 
     276              : #endif
     277              : };
     278              : 
     279              : /*!
     280              :  * RootPosition only specific responsability is to
     281              :  * allocate and delete root pointer
     282              :  */
     283              : struct RootPosition : public Position {
     284           89 :    RootPosition(){
     285              :       // a shared pointer here will be too slow
     286           89 :       root = new RootInformation;
     287           89 :    }
     288              : 
     289              :    RootPosition(const std::string& fen, bool withMoveCount = true);
     290              : 
     291            0 :    RootPosition(const RootPosition& p): Position(p) {
     292            0 :       assert(p.root);
     293              :       // we take a copy of the RootInformation of the copied RootPosition
     294            0 :       root = new RootInformation(*p.root);
     295            0 :    };
     296              : 
     297              :    // Root position cannot be copied
     298              :    // use this kind of thing instead
     299              :    // const bool b = readFEN(fen, rootPos, false, true);
     300              :    RootPosition & operator=(const RootPosition &) = delete;
     301              : 
     302           89 :    ~RootPosition() override {
     303           89 :       delete root;
     304           89 :    }
     305              : 
     306              : };
     307              : 
     308              : #ifdef WITH_NNUE
     309    158320064 : template<Color c> void updateNNUEEvaluator(NNUEEvaluator& nnueEvaluator, const MoveInfo& moveInfo) {
     310              :    START_TIMER
     311    158320064 :    const Piece fromType = Abs(moveInfo.fromP);
     312    158320064 :    const Piece toType = Abs(moveInfo.toP);
     313    158320064 :    nnueEvaluator.template us<c>().erase(NNUEIndiceUs(moveInfo.king[c], moveInfo.from, fromType));
     314    158320064 :    nnueEvaluator.template them<c>().erase(NNUEIndiceThem(moveInfo.king[~c], moveInfo.from, fromType));
     315    158320064 :    if (isPromotion(moveInfo.type)) {
     316       422359 :       const Piece promPieceType = promShift(moveInfo.type);
     317       422359 :       nnueEvaluator.template us<c>().insert(NNUEIndiceUs(moveInfo.king[c], moveInfo.to, promPieceType));
     318       422359 :       nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, promPieceType));
     319              :    }
     320              :    else {
     321    157897705 :       nnueEvaluator.template us<c>().insert(NNUEIndiceUs(moveInfo.king[c], moveInfo.to, fromType));
     322    157897705 :       nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, fromType));
     323              :    }
     324    158320064 :    if (moveInfo.type == T_ep) {
     325        58151 :       const Square epSq = moveInfo.ep + (c == Co_White ? -8 : +8);
     326        58151 :       nnueEvaluator.template us<c>().erase(NNUEIndiceThem(moveInfo.king[c], epSq, P_wp));
     327        58151 :       nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], epSq, P_wp));
     328              :    }
     329    158261913 :    else if (toType != P_none) {
     330      8593216 :       nnueEvaluator.template us<c>().erase(NNUEIndiceThem(moveInfo.king[c], moveInfo.to, toType));
     331      8593216 :       nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], moveInfo.to, toType));
     332              :    }
     333    158320064 :    nnueEvaluator.dirty = false;
     334              :    STOP_AND_SUM_TIMER(UpdateNNUE)
     335    158320064 : }
     336              : 
     337      8352932 : template<Color c> void updateNNUEEvaluatorThemOnly(NNUEEvaluator& nnueEvaluator, const MoveInfo& moveInfo) {
     338              :    START_TIMER
     339      8352932 :    const Piece fromType = Abs(moveInfo.fromP);
     340      8352932 :    const Piece toType = Abs(moveInfo.toP);
     341      8352932 :    nnueEvaluator.template them<c>().erase(NNUEIndiceThem(moveInfo.king[~c], moveInfo.from, fromType));
     342      8352932 :    if (isPromotion(moveInfo.type)) {
     343            0 :       const Piece promPieceType = promShift(moveInfo.type);
     344            0 :       nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, promPieceType));
     345              :    }
     346              :    else {
     347      8352932 :       nnueEvaluator.template them<c>().insert(NNUEIndiceThem(moveInfo.king[~c], moveInfo.to, fromType));
     348              :    }
     349      8352932 :    if (moveInfo.type == T_ep) {
     350            0 :       const Square epSq = moveInfo.ep + (c == Co_White ? -8 : +8);
     351            0 :       nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], epSq, P_wp));
     352              :    }
     353      8352932 :    else if (toType != P_none) {
     354       441434 :       nnueEvaluator.template them<c>().erase(NNUEIndiceUs(moveInfo.king[~c], moveInfo.to, toType));
     355              :    }
     356      8352932 :    nnueEvaluator.dirty = false;
     357              :    STOP_AND_SUM_TIMER(UpdateNNUE)
     358      8352932 : }
     359              : #endif
        

Generated by: LCOV version 2.0-1