Extract Variant::conclude from header file
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 23 Apr 2023 18:41:24 +0000 (20:41 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 23 Apr 2023 18:41:24 +0000 (20:41 +0200)
No functional change.

src/variant.cpp
src/variant.h

index 6332047..d477eb6 100644 (file)
@@ -1885,6 +1885,141 @@ void VariantMap::init() {
 }
 
 
+// Pre-calculate derived properties
+Variant* Variant::conclude() {
+    // Enforce consistency to allow runtime optimizations
+    if (!doubleStep)
+        doubleStepRegion[WHITE] = doubleStepRegion[BLACK] = 0;
+    if (!doubleStepRegion[WHITE] && !doubleStepRegion[BLACK])
+        doubleStep = false;
+
+    // Determine optimizations
+    bool restrictedMobility = false;
+    for (PieceSet ps = pieceTypes; !restrictedMobility && ps;)
+    {
+        PieceType pt = pop_lsb(ps);
+        if (mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt])
+          restrictedMobility = true;
+    }
+    fastAttacks =  !(pieceTypes & ~(CHESS_PIECES | COMMON_FAIRY_PIECES))
+                  && kingType == KING
+                  && !restrictedMobility
+                  && !cambodianMoves
+                  && !diagonalLines;
+    fastAttacks2 =  !(pieceTypes & ~(SHOGI_PIECES | COMMON_STEP_PIECES))
+                  && kingType == KING
+                  && !restrictedMobility
+                  && !cambodianMoves
+                  && !diagonalLines;
+
+    // Initialize calculated NNUE properties
+    nnueKing =  pieceTypes & KING ? KING
+              : extinctionPieceCount == 0 && (extinctionPieceTypes & COMMONER) ? COMMONER
+              : NO_PIECE_TYPE;
+    // The nnueKing has to present exactly once and must not change in count
+    if (nnueKing != NO_PIECE_TYPE)
+    {
+        // If the nnueKing is involved in promotion, count might change
+        if (   ((promotionPawnTypes[WHITE] | promotionPawnTypes[BLACK]) & nnueKing)
+            || ((promotionPieceTypes[WHITE] | promotionPieceTypes[BLACK]) & nnueKing)
+            || std::find(std::begin(promotedPieceType), std::end(promotedPieceType), nnueKing) != std::end(promotedPieceType))
+            nnueKing = NO_PIECE_TYPE;
+    }
+    if (nnueKing != NO_PIECE_TYPE)
+    {
+        std::string fenBoard = startFen.substr(0, startFen.find(' '));
+        // Switch NNUE from KA to A if there is no unique piece
+        if (   std::count(fenBoard.begin(), fenBoard.end(), pieceToChar[make_piece(WHITE, nnueKing)]) != 1
+            || std::count(fenBoard.begin(), fenBoard.end(), pieceToChar[make_piece(BLACK, nnueKing)]) != 1)
+            nnueKing = NO_PIECE_TYPE;
+    }
+    // We can not use popcount here yet, as the lookup tables are initialized after the variants
+    int nnueSquares = (maxRank + 1) * (maxFile + 1);
+    nnueUsePockets = (pieceDrops && (capturesToHand || (!mustDrop && std::bitset<64>(pieceTypes).count() != 1))) || seirawanGating;
+    int nnuePockets = nnueUsePockets ? 2 * int(maxFile + 1) : 0;
+    int nnueNonDropPieceIndices = (2 * std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnueSquares;
+    int nnuePieceIndices = nnueNonDropPieceIndices + 2 * (std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnuePockets;
+    int i = 0;
+    for (PieceSet ps = pieceTypes; ps;)
+    {
+        // Make sure that the nnueKing type gets the last index, since the NNUE architecture relies on that
+        PieceType pt = lsb(ps != piece_set(nnueKing) ? ps & ~piece_set(nnueKing) : ps);
+        ps ^= pt;
+        assert(pt != nnueKing || !ps);
+
+        for (Color c : { WHITE, BLACK})
+        {
+            pieceSquareIndex[c][make_piece(c, pt)] = 2 * i * nnueSquares;
+            pieceSquareIndex[c][make_piece(~c, pt)] = (2 * i + (pt != nnueKing)) * nnueSquares;
+            pieceHandIndex[c][make_piece(c, pt)] = 2 * i * nnuePockets + nnueNonDropPieceIndices;
+            pieceHandIndex[c][make_piece(~c, pt)] = (2 * i + 1) * nnuePockets + nnueNonDropPieceIndices;
+        }
+        i++;
+    }
+
+    // Map king squares to enumeration of actually available squares.
+    // E.g., for xiangqi map from 0-89 to 0-8.
+    // Variants might be initialized before bitboards, so do not rely on precomputed bitboards (like SquareBB).
+    // Furthermore conclude() might be called on invalid configuration during validation,
+    // therefore skip proper initialization in case of invalid board size.
+    int nnueKingSquare = 0;
+    if (nnueKing && nnueSquares <= SQUARE_NB)
+        for (Square s = SQ_A1; s < nnueSquares; ++s)
+        {
+            Square bitboardSquare = Square(s + s / (maxFile + 1) * (FILE_MAX - maxFile));
+            if (   !mobilityRegion[WHITE][nnueKing] || !mobilityRegion[BLACK][nnueKing]
+                || (mobilityRegion[WHITE][nnueKing] & make_bitboard(bitboardSquare))
+                || (mobilityRegion[BLACK][nnueKing] & make_bitboard(relative_square(BLACK, bitboardSquare, maxRank))))
+            {
+                kingSquareIndex[s] = nnueKingSquare++ * nnuePieceIndices;
+            }
+        }
+    else
+        kingSquareIndex[SQ_A1] = nnueKingSquare++ * nnuePieceIndices;
+    nnueDimensions = nnueKingSquare * nnuePieceIndices;
+
+    // Determine maximum piece count
+    std::istringstream ss(startFen);
+    ss >> std::noskipws;
+    unsigned char token;
+    nnueMaxPieces = 0;
+    while ((ss >> token) && !isspace(token))
+    {
+        if (pieceToChar.find(token) != std::string::npos || pieceToCharSynonyms.find(token) != std::string::npos)
+            nnueMaxPieces++;
+    }
+    if (twoBoards)
+        nnueMaxPieces *= 2;
+
+    // For endgame evaluation to be applicable, no special win rules must apply.
+    // Furthermore, rules significantly changing game mechanics also invalidate it.
+    endgameEval = extinctionValue == VALUE_NONE
+                  && checkmateValue == -VALUE_MATE
+                  && stalemateValue == VALUE_DRAW
+                  && !materialCounting
+                  && !(flagRegion[WHITE] || flagRegion[BLACK])
+                  && !mustCapture
+                  && !checkCounting
+                  && !makpongRule
+                  && !connectN
+                  && !blastOnCapture
+                  && !capturesToHand
+                  && !twoBoards
+                  && !restrictedMobility
+                  && kingType == KING;
+
+    shogiStylePromotions = false;
+    for (PieceType current: promotedPieceType)
+        if (current != NO_PIECE_TYPE)
+        {
+            shogiStylePromotions = true;
+            break;
+        }
+
+    return this;
+}
+
+
 /// VariantMap::parse_istream reads variants from an INI-style configuration input stream.
 
 template <bool DoCheck>
index 3e5dcb5..b342c73 100644 (file)
@@ -211,139 +211,7 @@ struct Variant {
       return this;
   }
 
-  // Pre-calculate derived properties
-  Variant* conclude() {
-      // Enforce consistency to allow runtime optimizations
-      if (!doubleStep)
-          doubleStepRegion[WHITE] = doubleStepRegion[BLACK] = 0;
-      if (!doubleStepRegion[WHITE] && !doubleStepRegion[BLACK])
-          doubleStep = false;
-
-      // Determine optimizations
-      bool restrictedMobility = false;
-      for (PieceSet ps = pieceTypes; !restrictedMobility && ps;)
-      {
-          PieceType pt = pop_lsb(ps);
-          if (mobilityRegion[WHITE][pt] || mobilityRegion[BLACK][pt])
-            restrictedMobility = true;
-      }
-      fastAttacks =  !(pieceTypes & ~(CHESS_PIECES | COMMON_FAIRY_PIECES))
-                   && kingType == KING
-                   && !restrictedMobility
-                   && !cambodianMoves
-                   && !diagonalLines;
-      fastAttacks2 =  !(pieceTypes & ~(SHOGI_PIECES | COMMON_STEP_PIECES))
-                    && kingType == KING
-                    && !restrictedMobility
-                    && !cambodianMoves
-                    && !diagonalLines;
-
-      // Initialize calculated NNUE properties
-      nnueKing =  pieceTypes & KING ? KING
-                : extinctionPieceCount == 0 && (extinctionPieceTypes & COMMONER) ? COMMONER
-                : NO_PIECE_TYPE;
-      // The nnueKing has to present exactly once and must not change in count
-      if (nnueKing != NO_PIECE_TYPE)
-      {
-          // If the nnueKing is involved in promotion, count might change
-          if (   ((promotionPawnTypes[WHITE] | promotionPawnTypes[BLACK]) & nnueKing)
-              || ((promotionPieceTypes[WHITE] | promotionPieceTypes[BLACK]) & nnueKing)
-              || std::find(std::begin(promotedPieceType), std::end(promotedPieceType), nnueKing) != std::end(promotedPieceType))
-              nnueKing = NO_PIECE_TYPE;
-      }
-      if (nnueKing != NO_PIECE_TYPE)
-      {
-          std::string fenBoard = startFen.substr(0, startFen.find(' '));
-          // Switch NNUE from KA to A if there is no unique piece
-          if (   std::count(fenBoard.begin(), fenBoard.end(), pieceToChar[make_piece(WHITE, nnueKing)]) != 1
-              || std::count(fenBoard.begin(), fenBoard.end(), pieceToChar[make_piece(BLACK, nnueKing)]) != 1)
-              nnueKing = NO_PIECE_TYPE;
-      }
-      // We can not use popcount here yet, as the lookup tables are initialized after the variants
-      int nnueSquares = (maxRank + 1) * (maxFile + 1);
-      nnueUsePockets = (pieceDrops && (capturesToHand || (!mustDrop && std::bitset<64>(pieceTypes).count() != 1))) || seirawanGating;
-      int nnuePockets = nnueUsePockets ? 2 * int(maxFile + 1) : 0;
-      int nnueNonDropPieceIndices = (2 * std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnueSquares;
-      int nnuePieceIndices = nnueNonDropPieceIndices + 2 * (std::bitset<64>(pieceTypes).count() - (nnueKing != NO_PIECE_TYPE)) * nnuePockets;
-      int i = 0;
-      for (PieceSet ps = pieceTypes; ps;)
-      {
-          // Make sure that the nnueKing type gets the last index, since the NNUE architecture relies on that
-          PieceType pt = lsb(ps != piece_set(nnueKing) ? ps & ~piece_set(nnueKing) : ps);
-          ps ^= pt;
-          assert(pt != nnueKing || !ps);
-
-          for (Color c : { WHITE, BLACK})
-          {
-              pieceSquareIndex[c][make_piece(c, pt)] = 2 * i * nnueSquares;
-              pieceSquareIndex[c][make_piece(~c, pt)] = (2 * i + (pt != nnueKing)) * nnueSquares;
-              pieceHandIndex[c][make_piece(c, pt)] = 2 * i * nnuePockets + nnueNonDropPieceIndices;
-              pieceHandIndex[c][make_piece(~c, pt)] = (2 * i + 1) * nnuePockets + nnueNonDropPieceIndices;
-          }
-          i++;
-      }
-
-      // Map king squares to enumeration of actually available squares.
-      // E.g., for xiangqi map from 0-89 to 0-8.
-      // Variants might be initialized before bitboards, so do not rely on precomputed bitboards (like SquareBB).
-      // Furthermore conclude() might be called on invalid configuration during validation,
-      // therefore skip proper initialization in case of invalid board size.
-      int nnueKingSquare = 0;
-      if (nnueKing && nnueSquares <= SQUARE_NB)
-          for (Square s = SQ_A1; s < nnueSquares; ++s)
-          {
-              Square bitboardSquare = Square(s + s / (maxFile + 1) * (FILE_MAX - maxFile));
-              if (   !mobilityRegion[WHITE][nnueKing] || !mobilityRegion[BLACK][nnueKing]
-                  || (mobilityRegion[WHITE][nnueKing] & make_bitboard(bitboardSquare))
-                  || (mobilityRegion[BLACK][nnueKing] & make_bitboard(relative_square(BLACK, bitboardSquare, maxRank))))
-              {
-                  kingSquareIndex[s] = nnueKingSquare++ * nnuePieceIndices;
-              }
-          }
-      else
-          kingSquareIndex[SQ_A1] = nnueKingSquare++ * nnuePieceIndices;
-      nnueDimensions = nnueKingSquare * nnuePieceIndices;
-
-      // Determine maximum piece count
-      std::istringstream ss(startFen);
-      ss >> std::noskipws;
-      unsigned char token;
-      nnueMaxPieces = 0;
-      while ((ss >> token) && !isspace(token))
-      {
-          if (pieceToChar.find(token) != std::string::npos || pieceToCharSynonyms.find(token) != std::string::npos)
-              nnueMaxPieces++;
-      }
-      if (twoBoards)
-          nnueMaxPieces *= 2;
-
-      // For endgame evaluation to be applicable, no special win rules must apply.
-      // Furthermore, rules significantly changing game mechanics also invalidate it.
-      endgameEval = extinctionValue == VALUE_NONE
-                    && checkmateValue == -VALUE_MATE
-                    && stalemateValue == VALUE_DRAW
-                    && !materialCounting
-                    && !(flagRegion[WHITE] || flagRegion[BLACK])
-                    && !mustCapture
-                    && !checkCounting
-                    && !makpongRule
-                    && !connectN
-                    && !blastOnCapture
-                    && !capturesToHand
-                    && !twoBoards
-                    && !restrictedMobility
-                    && kingType == KING;
-
-      shogiStylePromotions = false;
-      for (PieceType current: promotedPieceType)
-          if (current != NO_PIECE_TYPE)
-          {
-              shogiStylePromotions = true;
-              break;
-          }
-
-      return this;
-  }
+  Variant* conclude();
 };
 
 class VariantMap : public std::map<std::string, const Variant*> {