Better naming in endgame code
authorMarco Costalba <mcostalba@gmail.com>
Sun, 4 Jun 2017 09:03:23 +0000 (11:03 +0200)
committerJoona Kiiski <joona@zoox.com>
Sat, 17 Jun 2017 02:33:44 +0000 (19:33 -0700)
And small clean-up of magic bitboards code.

No functional change.

Closes #1138

src/Makefile
src/bitboard.cpp
src/bitboard.h
src/endgame.cpp
src/endgame.h
src/material.cpp
src/search.cpp
src/syzygy/tbprobe.cpp

index e56ea54c37818cf946fd286b70d23717532d3f3f..fd92838424ab7c001fe7d7f980058313f2d3cb7f 100644 (file)
@@ -452,7 +452,7 @@ install:
 
 #clean all
 clean: objclean profileclean
-       @rm -f .depend *~ core 
+       @rm -f .depend *~ core
 
 # clean binaries and objects
 objclean:
index 99070ef2c0a6f9e606781517af9a4a213c91cb35..555cd13ca78960895e22f84a1a47f03830deca2d 100644 (file)
@@ -26,9 +26,6 @@
 uint8_t PopCnt16[1 << 16];
 int SquareDistance[SQUARE_NB][SQUARE_NB];
 
-Magic RookMagics[SQUARE_NB];
-Magic BishopMagics[SQUARE_NB];
-
 Bitboard SquareBB[SQUARE_NB];
 Bitboard FileBB[FILE_NB];
 Bitboard RankBB[RANK_NB];
@@ -43,6 +40,9 @@ Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB];
 Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
 Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
 
+Magic RookMagics[SQUARE_NB];
+Magic BishopMagics[SQUARE_NB];
+
 namespace {
 
   // De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
@@ -54,7 +54,7 @@ namespace {
   Bitboard RookTable[0x19000];  // To store rook attacks
   Bitboard BishopTable[0x1480]; // To store bishop attacks
 
-  typedef unsigned (Fn)(Square, Bitboard);
+  typedef unsigned (Fn)(const Magic&, Bitboard);
 
   void init_magics(Bitboard table[], Magic magics[], Square deltas[], Fn index);
 
@@ -204,8 +204,8 @@ void Bitboards::init() {
   Square RookDeltas[] = { NORTH,  EAST,  SOUTH,  WEST };
   Square BishopDeltas[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
 
-  init_magics(RookTable, RookMagics, RookDeltas, magic_index<ROOK>);
-  init_magics(BishopTable, BishopMagics, BishopDeltas, magic_index<BISHOP>);
+  init_magics(RookTable, RookMagics, RookDeltas, magic_index);
+  init_magics(BishopTable, BishopMagics, BishopDeltas, magic_index);
 
   for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
   {
@@ -257,10 +257,7 @@ namespace {
                              {  728, 10316, 55013, 32803, 12281, 15100,  16645,   255 } };
 
     Bitboard occupancy[4096], reference[4096], edges, b;
-    int age[4096] = {0}, current = 0, i, size;
-
-    // attacks[s] is a pointer to the beginning of the attacks table for square 's'
-    magics[SQ_A1].attacks = table;
+    int epoch[4096] = {}, cnt = 0, size = 0;
 
     for (Square s = SQ_A1; s <= SQ_H8; ++s)
     {
@@ -272,8 +269,13 @@ namespace {
         // all the attacks for each possible subset of the mask and so is 2 power
         // the number of 1s of the mask. Hence we deduce the size of the shift to
         // apply to the 64 or 32 bits word to get the index.
-        magics[s].mask  = sliding_attack(deltas, s, 0) & ~edges;
-        magics[s].shift = (Is64Bit ? 64 : 32) - popcount(magics[s].mask);
+        Magic& m = magics[s];
+        m.mask  = sliding_attack(deltas, s, 0) & ~edges;
+        m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
+
+        // Set the offset for the attacks table of the square. We have individual
+        // table sizes for each square with "Fancy Magic Bitboards".
+        m.attacks = s == SQ_A1 ? table : magics[s - 1].attacks + size;
 
         // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
         // store the corresponding sliding attack bitboard in reference[].
@@ -283,17 +285,12 @@ namespace {
             reference[size] = sliding_attack(deltas, s, b);
 
             if (HasPext)
-                magics[s].attacks[pext(b, magics[s].mask)] = reference[size];
+                m.attacks[pext(b, m.mask)] = reference[size];
 
             size++;
-            b = (b - magics[s].mask) & magics[s].mask;
+            b = (b - m.mask) & m.mask;
         } while (b);
 
-        // Set the offset for the table of the next square. We have individual
-        // table sizes for each square with "Fancy Magic Bitboards".
-        if (s < SQ_H8)
-            magics[s + 1].attacks = magics[s].attacks + size;
-
         if (HasPext)
             continue;
 
@@ -301,28 +298,30 @@ namespace {
 
         // Find a magic for square 's' picking up an (almost) random number
         // until we find the one that passes the verification test.
-        do {
-            do
-                magics[s].magic = rng.sparse_rand<Bitboard>();
-            while (popcount((magics[s].magic * magics[s].mask) >> 56) < 6);
+        for (int i = 0; i < size; )
+        {
+            for (m.magic = 0; popcount((m.magic * m.mask) >> 56) < 6; )
+                m.magic = rng.sparse_rand<Bitboard>();
 
             // A good magic must map every possible occupancy to an index that
             // looks up the correct sliding attack in the attacks[s] database.
             // Note that we build up the database for square 's' as a side
-            // effect of verifying the magic.
-            for (++current, i = 0; i < size; ++i)
+            // effect of verifying the magic. Keep track of the attempt count
+            // and save it in epoch[], little speed-up trick to avoid resetting
+            // m.attacks[] after every failed attempt.
+            for (++cnt, i = 0; i < size; ++i)
             {
-                unsigned idx = index(s, occupancy[i]);
+                unsigned idx = index(m, occupancy[i]);
 
-                if (age[idx] < current)
+                if (epoch[idx] < cnt)
                 {
-                    age[idx] = current;
-                    magics[s].attacks[idx] = reference[i];
+                    epoch[idx] = cnt;
+                    m.attacks[idx] = reference[i];
                 }
-                else if (magics[s].attacks[idx] != reference[i])
+                else if (m.attacks[idx] != reference[i])
                     break;
             }
-        } while (i < size);
+        }
     }
   }
 }
index 3ea92bdf2e56400b273cafaf4f1689bc12a5de7e..38870a2be69fbd8a33ca8a50e610db4a29dd7c86 100644 (file)
@@ -76,6 +76,18 @@ extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB];
 extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB];
 
 
+/// Magic holds all magic bitboards relevant data for a single square
+struct Magic {
+  Bitboard  mask;
+  Bitboard  magic;
+  Bitboard* attacks;
+  unsigned  shift;
+};
+
+extern Magic RookMagics[SQUARE_NB];
+extern Magic BishopMagics[SQUARE_NB];
+
+
 /// Overloads of bitwise operators between a Bitboard and a Square for testing
 /// whether a given bit is set in a bitboard, and for setting and clearing bits.
 
@@ -209,47 +221,27 @@ template<> inline int distance<File>(Square x, Square y) { return distance(file_
 template<> inline int distance<Rank>(Square x, Square y) { return distance(rank_of(x), rank_of(y)); }
 
 
-/// Magic holds all magic relevant data for a single square
-struct Magic {
-
-    Bitboard  mask;
-    Bitboard  magic;
-    Bitboard* attacks;
-    unsigned  shift;
-};
-
 /// attacks_bb() returns a bitboard representing all the squares attacked by a
 /// piece of type Pt (bishop or rook) placed on 's'. The helper magic_index()
 /// looks up the index using the 'magic bitboards' approach.
-template<PieceType Pt>
-inline unsigned magic_index(Square s, Bitboard occupied) {
-
-  extern Magic RookMagics[SQUARE_NB];
-  extern Magic BishopMagics[SQUARE_NB];
-
-  const Magic* Magics = Pt == ROOK ? RookMagics : BishopMagics;
-  Bitboard mask  = Magics[s].mask;
-  Bitboard magic = Magics[s].magic;
-  unsigned shift = Magics[s].shift;
+inline unsigned magic_index(const Magic& m, Bitboard occupied) {
 
   if (HasPext)
-      return unsigned(pext(occupied, mask));
+      return unsigned(pext(occupied, m.mask));
 
   if (Is64Bit)
-      return unsigned(((occupied & mask) * magic) >> shift);
+      return unsigned(((occupied & m.mask) * m.magic) >> m.shift);
 
-  unsigned lo = unsigned(occupied) & unsigned(mask);
-  unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32);
-  return  (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift;
+  unsigned lo = unsigned(occupied) & unsigned(m.mask);
+  unsigned hi = unsigned(occupied >> 32) & unsigned(m.mask >> 32);
+  return (lo * unsigned(m.magic) ^ hi * unsigned(m.magic >> 32)) >> m.shift;
 }
 
 template<PieceType Pt>
 inline Bitboard attacks_bb(Square s, Bitboard occupied) {
 
-    extern Magic RookMagics[SQUARE_NB];
-    extern Magic BishopMagics[SQUARE_NB];
-
-    return (Pt == ROOK ? RookMagics : BishopMagics)[s].attacks[magic_index<Pt>(s, occupied)];
+  const Magic& M = Pt == ROOK ? RookMagics[s] : BishopMagics[s];
+  return M.attacks[magic_index(M, occupied)];
 }
 
 inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
index 136ee0f6529002db6f33d3cf016b7f2cec55ba1c..b64b75cbca63e22a0f375611d9e5e4be920ea864 100644 (file)
@@ -110,14 +110,6 @@ Endgames::Endgames() {
 }
 
 
-template<EndgameType E, typename T>
-void Endgames::add(const string& code) {
-  StateInfo st;
-  map<T>()[Position().set(code, WHITE, &st).material_key()] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(WHITE));
-  map<T>()[Position().set(code, BLACK, &st).material_key()] = std::unique_ptr<EndgameBase<T>>(new Endgame<E>(BLACK));
-}
-
-
 /// Mate with KX vs K. This function is used to evaluate positions with
 /// king and plenty of material vs a lone king. It simply gives the
 /// attacking side a bonus for driving the defending king towards the edge
index 509e8d4caac7fabc8589836d9c97fc89c7015027..5e181526201da79f4863db34f25b223b0ef94765 100644 (file)
 #include "types.h"
 
 
-/// EndgameType lists all supported endgames
+/// EndgameCode lists all supported endgame functions by corresponding codes
 
-enum EndgameType {
-
-  // Evaluation functions
+enum EndgameCode {
 
+  EVALUATION_FUNCTIONS,
   KNNK,  // KNN vs K
   KXK,   // Generic "mate lone king" eval
   KBNK,  // KBN vs K
@@ -47,10 +46,7 @@ enum EndgameType {
   KQKP,  // KQ vs KP
   KQKR,  // KQ vs KR
 
-
-  // Scaling functions
   SCALING_FUNCTIONS,
-
   KBPsK,   // KB and pawns vs K
   KQKRPs,  // KQ vs KR and pawns
   KRPKR,   // KRP vs KR
@@ -68,30 +64,28 @@ enum EndgameType {
 
 /// Endgame functions can be of two types depending on whether they return a
 /// Value or a ScaleFactor.
-template<EndgameType E> using
+template<EndgameCode E> using
 eg_type = typename std::conditional<(E < SCALING_FUNCTIONS), Value, ScaleFactor>::type;
 
 
-/// Base and derived templates for endgame evaluation and scaling functions
+/// Base and derived functors for endgame evaluation and scaling functions
 
 template<typename T>
 struct EndgameBase {
 
+  explicit EndgameBase(Color c) : strongSide(c), weakSide(~c) {}
   virtual ~EndgameBase() = default;
-  virtual Color strong_side() const = 0;
   virtual T operator()(const Position&) const = 0;
+
+  const Color strongSide, weakSide;
 };
 
 
-template<EndgameType E, typename T = eg_type<E>>
+template<EndgameCode E, typename T = eg_type<E>>
 struct Endgame : public EndgameBase<T> {
 
-  explicit Endgame(Color c) : strongSide(c), weakSide(~c) {}
-  Color strong_side() const { return strongSide; }
+  explicit Endgame(Color c) : EndgameBase<T>(c) {}
   T operator()(const Position&) const;
-
-private:
-  Color strongSide, weakSide;
 };
 
 
@@ -101,16 +95,22 @@ private:
 
 class Endgames {
 
-  template<typename T> using Map = std::map<Key, std::unique_ptr<EndgameBase<T>>>;
-
-  template<EndgameType E, typename T = eg_type<E>>
-  void add(const std::string& code);
+  template<typename T> using Ptr = std::unique_ptr<EndgameBase<T>>;
+  template<typename T> using Map = std::map<Key, Ptr<T>>;
 
   template<typename T>
   Map<T>& map() {
     return std::get<std::is_same<T, ScaleFactor>::value>(maps);
   }
 
+  template<EndgameCode E, typename T = eg_type<E>, typename P = Ptr<T>>
+  void add(const std::string& code) {
+
+    StateInfo st;
+    map<T>()[Position().set(code, WHITE, &st).material_key()] = P(new Endgame<E>(WHITE));
+    map<T>()[Position().set(code, BLACK, &st).material_key()] = P(new Endgame<E>(BLACK));
+  }
+
   std::pair<Map<Value>, Map<ScaleFactor>> maps;
 
 public:
index e5b8ddf2ac819cf6b11a71926eab3946d6d26c36..dc2a3a3b550c6eddaf9e8e1d378e5921c77bf72b 100644 (file)
@@ -155,7 +155,7 @@ Entry* probe(const Position& pos) {
 
   if ((sf = pos.this_thread()->endgames.probe<ScaleFactor>(key)) != nullptr)
   {
-      e->scalingFunction[sf->strong_side()] = sf; // Only strong color assigned
+      e->scalingFunction[sf->strongSide] = sf; // Only strong color assigned
       return e;
   }
 
index 4f943b4c561f7394dad2ee8241bbfb60fce37c2f..51d3ae8cba3910b48301adab0507316e09acb850 100644 (file)
@@ -335,7 +335,7 @@ void Thread::search() {
   MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
 
   std::memset(ss-4, 0, 7 * sizeof(Stack));
-  for(int i = 4; i > 0; i--)
+  for (int i = 4; i > 0; i--)
      (ss-i)->history = &this->counterMoveHistory[NO_PIECE][0]; // Use as sentinel
 
   bestValue = delta = alpha = -VALUE_INFINITE;
index 5d08549e5046f29f2876e6b3439ab0f8e041f794..48c448fd0dfeb8077f740d581acdae5a324fdd39 100644 (file)
@@ -531,14 +531,14 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
     //
     //       I(k) = k * d->span + d->span / 2      (1)
 
-    // First step is to get the 'k' of the I(k) nearest to our idx, using defintion (1)
+    // First step is to get the 'k' of the I(k) nearest to our idx, using definition (1)
     uint32_t k = idx / d->span;
 
     // Then we read the corresponding SparseIndex[] entry
     uint32_t block = number<uint32_t, LittleEndian>(&d->sparseIndex[k].block);
     int offset     = number<uint16_t, LittleEndian>(&d->sparseIndex[k].offset);
 
-    // Now compute the difference idx - I(k). From defintion of k we know that
+    // Now compute the difference idx - I(k). From definition of k we know that
     //
     //       idx = k * d->span + idx % d->span    (2)
     //