Advertisement
Guest User

Untitled

a guest
Jul 1st, 2019
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 45.14 KB | None | 0 0
  1. #include <iostream>
  2. #include <cstdint>
  3. #include <vector>
  4. #include <queue>
  5. #include <type_traits>
  6. #include <random>
  7. #include <array>
  8. #include <utility>
  9. #include <string>
  10. #include <queue>
  11. #include <intrin.h>
  12. #include <unordered_map>
  13. #include <chrono>
  14. #include <unordered_set>
  15. #include <memory>
  16. #include <stdio.h>
  17. #include <functional>
  18. #include <memory>
  19.  
  20. template <size_t ChunkSize>
  21. class TFixedAllocator {
  22.     union TNode { // union
  23.         char data[ChunkSize];
  24.         TNode* next; // free chunks of memory form a stack; pointer to the next (or nullptr)
  25.     };
  26.  
  27.     TNode* free; // the topmost free chunk of memory (or nullptr)
  28.     std::vector<TNode*> pools; // all allocated pools of memory
  29.     int size = 1; // size of the last allocated pool of memory
  30.     const int MAX_SIZE = 1024;
  31.  
  32.     void new_pool() { // allocate new pool of memory
  33.         if (size < MAX_SIZE) {
  34.             size *= 2;
  35.         }
  36.         free = new TNode[size];
  37.  
  38.         // form a stack of chunks of this pool
  39.         pools.push_back(free);
  40.         for (int i = 0; i < size; ++i) {
  41.             free[i].next = &free[i + 1];
  42.         }
  43.         free[size - 1].next = nullptr;
  44.     }
  45.     TFixedAllocator() { // private for singleton
  46.         new_pool();
  47.     }
  48. public:
  49.     TFixedAllocator(const TFixedAllocator&) = delete; // for singleton
  50.     static TFixedAllocator& instance() { // singleton
  51.         static TFixedAllocator instance;
  52.         return instance;
  53.     }
  54.     void* allocate() {
  55.         if (!free) {
  56.             new_pool();
  57.         }
  58.         TNode* result = free; // allocate the topmost element (saved in free)
  59.         free = free->next; // and pop it from the stack of free chunks
  60.         return static_cast<void*>(result);
  61.     }
  62.     void deallocate(void* elem) {
  63.         TNode* node = static_cast<TNode*>(elem);
  64.  
  65.         // add to the stack of chunks
  66.         node->next = free;
  67.         free = node;
  68.     }
  69.     ~TFixedAllocator() {
  70.         for (auto ptr : pools) {
  71.             delete ptr;
  72.         }
  73.     }
  74. };
  75. template <class T>
  76. class TFSBAllocator : std::allocator<T> {
  77. public:
  78.     using value_type = T;
  79.     using pointer = T *;
  80.     using const_pointer = const T*;
  81.     using reference = T &;
  82.     using const_reference = const T &;
  83.  
  84.     template <class U>
  85.     class rebind {
  86.     public:
  87.         using other = TFSBAllocator<U>;
  88.     };
  89.  
  90.     constexpr TFSBAllocator() noexcept { // construct default allocator (do nothing)
  91.     }
  92.     constexpr TFSBAllocator(const TFSBAllocator&) noexcept = default;
  93.     template <class _Other>
  94.     constexpr TFSBAllocator(const TFSBAllocator<_Other>&) noexcept { // construct from a related allocator (do nothing)
  95.     }
  96.  
  97.     pointer allocate(size_t n) {
  98.         if (n == 1) {
  99.             return static_cast<T*>(TFixedAllocator<sizeof(T)>::instance().allocate());
  100.         }
  101.         else {
  102.             return std::allocator<T>().allocate(n);
  103.         }
  104.     }
  105.     void deallocate(pointer p, size_t n) {
  106.         if (n == 1) {
  107.             TFixedAllocator<sizeof(T)>::instance().deallocate(static_cast<void*>(p));
  108.         }
  109.         else {
  110.             return std::allocator<T>().deallocate(p, n);
  111.         }
  112.     }
  113.     void construct(pointer p, const_reference t) {
  114.         new (p) T(t);
  115.     }
  116.     void destroy(pointer p) {
  117.         p->~T();
  118.     }
  119. };
  120.  
  121. template <typename T, typename V>
  122. using MapType = std::unordered_map<T, V, std::hash<T>, std::equal_to<T>, TFSBAllocator< std::pair<const T, V>>>;
  123.  
  124. static constexpr int width = 6;
  125. static constexpr int height = 6;
  126.  
  127. static constexpr int reportEveryNPositions = 1<<16;
  128.  
  129. std::uint64_t murmur64(std::uint64_t h) {
  130.     h ^= h >> 33;
  131.     h *= 0xff51afd7ed558ccdULL;
  132.     h ^= h >> 33;
  133.     h *= 0xc4ceb9fe1a85ec53ULL;
  134.     h ^= h >> 33;
  135.     return h;
  136. }
  137.  
  138. enum struct PieceType : std::uint8_t
  139. {
  140.     None = 0,
  141.     King, // 1+
  142.     Knight, // ~1/2
  143.     Dabbaba, // ~2+
  144.     NumPieceTypes
  145. };
  146.  
  147. enum struct Color : std::uint8_t
  148. {
  149.     White = 0,
  150.     Black = 1,
  151.     NumColors
  152. };
  153.  
  154. Color oppositeColor(Color color)
  155. {
  156.     return color == Color::White ? Color::Black : Color::White;
  157. }
  158.  
  159. template <typename EnumT>
  160. constexpr auto ordinal(EnumT e)
  161. {
  162.     return static_cast<std::underlying_type_t<EnumT>>(e);
  163. }
  164.  
  165. template <typename EnumT, typename IntT>
  166. constexpr EnumT fromOrdinal(IntT v)
  167. {
  168.     return static_cast<EnumT>(v);
  169. }
  170.  
  171. constexpr int numPieceTypes = ordinal(PieceType::NumPieceTypes);
  172. constexpr int numColors = ordinal(Color::NumColors);
  173.  
  174. struct Piece
  175. {
  176.     static_assert(numColors == 2, "");
  177.  
  178.     static constexpr Piece none()
  179.     {
  180.         return Piece(PieceType::None, Color::White);
  181.     }
  182.  
  183.     constexpr Piece() :
  184.         Piece(PieceType::None, Color::White)
  185.     {
  186.  
  187.     }
  188.  
  189.     constexpr Piece(PieceType type, Color color) :
  190.         m_index((ordinal(type) << 1) | ordinal(color))
  191.     {
  192.     }
  193.  
  194.     constexpr Piece& operator=(const Piece& other) = default;
  195.  
  196.     constexpr friend bool operator==(Piece lhs, Piece rhs)
  197.     {
  198.         return lhs.m_index == rhs.m_index;
  199.     }
  200.  
  201.     constexpr friend bool operator!=(Piece lhs, Piece rhs)
  202.     {
  203.         return !(lhs == rhs);
  204.     }
  205.  
  206.     constexpr PieceType type() const
  207.     {
  208.         return fromOrdinal<PieceType>(m_index >> 1);
  209.     }
  210.  
  211.     constexpr Color color() const
  212.     {
  213.         return fromOrdinal<Color>(m_index & 1);
  214.     }
  215.  
  216.     std::uint64_t hash() const
  217.     {
  218.         return std::hash<std::uint8_t>{}(m_index);
  219.     }
  220.  
  221.     constexpr std::uint8_t index() const
  222.     {
  223.         return m_index;
  224.     }
  225.  
  226. private:
  227.     std::uint8_t m_index; // lowest bit is a color, 7 highest bits are a piece type
  228. };
  229.  
  230. constexpr int numAllPieces = numPieceTypes * numColors;
  231.  
  232. template <>
  233. constexpr auto ordinal(Piece e)
  234. {
  235.     return e.index();
  236. }
  237.  
  238. struct Square
  239. {
  240.     static constexpr Square fromIndex(int idx)
  241.     {
  242.         return Square(idx);
  243.     }
  244.  
  245.     static constexpr Square none()
  246.     {
  247.         return Square{};
  248.     }
  249.  
  250.     constexpr Square() :
  251.         m_index(width*height)
  252.     {
  253.  
  254.     }
  255.  
  256.     constexpr Square(int x, int y) :
  257.         m_index(x * height + y)
  258.     {
  259.  
  260.     }
  261.  
  262.     constexpr friend bool operator==(Square lhs, Square rhs)
  263.     {
  264.         return lhs.m_index == rhs.m_index;
  265.     }
  266.  
  267.     constexpr friend bool operator!=(Square lhs, Square rhs)
  268.     {
  269.         return !(lhs == rhs);
  270.     }
  271.  
  272.     constexpr std::uint8_t index() const
  273.     {
  274.         return m_index;
  275.     }
  276.  
  277.     constexpr int x() const
  278.     {
  279.         return m_index / height;
  280.     }
  281.  
  282.     constexpr int y() const
  283.     {
  284.         return m_index % height;
  285.     }
  286.  
  287. private:
  288.     std::uint8_t m_index;
  289.  
  290.     constexpr Square(int idx) :
  291.         m_index(idx)
  292.     {
  293.     }
  294. };
  295.  
  296. struct Move
  297. {
  298.     static Move none()
  299.     {
  300.         return Move(-1, Square(0, 0));
  301.     }
  302.  
  303.     Move(std::int8_t fromIdx, Square to) :
  304.         m_fromIdx(fromIdx),
  305.         m_to(to)
  306.     {
  307.     }
  308.  
  309.     friend bool operator==(Move lhs, Move rhs)
  310.     {
  311.         return lhs.m_fromIdx == rhs.m_fromIdx && lhs.m_to == rhs.m_to;
  312.     }
  313.  
  314.     std::int8_t fromIdx() const
  315.     {
  316.         return m_fromIdx;
  317.     }
  318.  
  319.     Square to() const
  320.     {
  321.         return m_to;
  322.     }
  323.  
  324.     bool isNone() const
  325.     {
  326.         return m_fromIdx == -1;
  327.     }
  328.  
  329. private:
  330.     std::int8_t m_fromIdx;
  331.     Square m_to;
  332. };
  333.  
  334. struct Offset
  335. {
  336.     constexpr Offset(int x, int y) :
  337.         m_dx(x),
  338.         m_dy(y)
  339.     {
  340.     }
  341.  
  342.     constexpr std::int8_t dx() const
  343.     {
  344.         return m_dx;
  345.     }
  346.  
  347.     constexpr std::int8_t dy() const
  348.     {
  349.         return m_dy;
  350.     }
  351.  
  352. private:
  353.     std::int8_t m_dx;
  354.     std::int8_t m_dy;
  355. };
  356.  
  357. struct BitBoardLayer
  358. {
  359.     // bits counted from the LSB
  360.  
  361.     static constexpr BitBoardLayer none()
  362.     {
  363.         return BitBoardLayer{};
  364.     }
  365.  
  366.     static constexpr BitBoardLayer all()
  367.     {
  368.         return ~none();
  369.     }
  370.  
  371.     constexpr BitBoardLayer() :
  372.         m_squares(0)
  373.     {
  374.     }
  375.  
  376.     constexpr bool isEmpty() const
  377.     {
  378.         return m_squares == 0;
  379.     }
  380.  
  381.     constexpr bool isSet(Square sq) const
  382.     {
  383.         return !!((m_squares >> sq.index()) & 1ull);
  384.     }
  385.  
  386.     constexpr void set(Square sq)
  387.     {
  388.         m_squares |= (1ull << sq.index());
  389.     }
  390.  
  391.     constexpr void unset(Square sq)
  392.     {
  393.         m_squares &= ~(1ull << sq.index());
  394.     }
  395.  
  396.     constexpr BitBoardLayer operator~() const
  397.     {
  398.         BitBoardLayer bb = *this;
  399.         bb.m_squares = ~m_squares;
  400.         return bb;
  401.     }
  402.  
  403.     constexpr BitBoardLayer& operator^=(Square sq)
  404.     {
  405.         m_squares ^= (1ull << sq.index());
  406.         return *this;
  407.     }
  408.  
  409.     constexpr BitBoardLayer& operator&=(Square sq)
  410.     {
  411.         m_squares &= (1ull << sq.index());
  412.         return *this;
  413.     }
  414.  
  415.     constexpr BitBoardLayer& operator|=(Square sq)
  416.     {
  417.         m_squares |= (1ull << sq.index());
  418.         return *this;
  419.     }
  420.  
  421.     constexpr BitBoardLayer operator^(Square sq) const
  422.     {
  423.         BitBoardLayer bb = *this;
  424.         bb ^= sq;
  425.         return bb;
  426.     }
  427.  
  428.     constexpr BitBoardLayer operator&(Square sq) const
  429.     {
  430.         BitBoardLayer bb = *this;
  431.         bb &= sq;
  432.         return bb;
  433.     }
  434.  
  435.     constexpr BitBoardLayer operator|(Square sq) const
  436.     {
  437.         BitBoardLayer bb = *this;
  438.         bb |= sq;
  439.         return bb;
  440.     }
  441.  
  442.     constexpr BitBoardLayer& operator^=(BitBoardLayer rhs)
  443.     {
  444.         m_squares ^= rhs.m_squares;
  445.         return *this;
  446.     }
  447.  
  448.     constexpr BitBoardLayer& operator&=(BitBoardLayer rhs)
  449.     {
  450.         m_squares &= rhs.m_squares;
  451.         return *this;
  452.     }
  453.  
  454.     constexpr BitBoardLayer& operator|=(BitBoardLayer rhs)
  455.     {
  456.         m_squares |= rhs.m_squares;
  457.         return *this;
  458.     }
  459.  
  460.     constexpr BitBoardLayer operator^(BitBoardLayer sq) const
  461.     {
  462.         BitBoardLayer bb = *this;
  463.         bb ^= sq;
  464.         return bb;
  465.     }
  466.  
  467.     constexpr BitBoardLayer operator&(BitBoardLayer sq) const
  468.     {
  469.         BitBoardLayer bb = *this;
  470.         bb &= sq;
  471.         return bb;
  472.     }
  473.  
  474.     constexpr BitBoardLayer operator|(BitBoardLayer sq) const
  475.     {
  476.         BitBoardLayer bb = *this;
  477.         bb |= sq;
  478.         return bb;
  479.     }
  480.  
  481.     int count() const
  482.     {
  483.         return __popcnt64(m_squares);
  484.     }
  485.  
  486.     bool any() const
  487.     {
  488.         return !!m_squares;
  489.     }
  490.  
  491.     Square firstSquare() const
  492.     {
  493.         unsigned long idx;
  494.         _BitScanReverse64(&idx, m_squares);
  495.         return Square::fromIndex(idx);
  496.     }
  497.  
  498.     constexpr BitBoardLayer& operator=(const BitBoardLayer& other) = default;
  499.  
  500. private:
  501.     std::uint64_t m_squares;
  502. };
  503.  
  504. void print(BitBoardLayer bb)
  505. {
  506.     std::string s;
  507.  
  508.     for (int y = 0; y < height; ++y)
  509.     {
  510.         for (int x = 0; x < width; ++x)
  511.         {
  512.             if (bb.isSet(Square(x, y)))
  513.             {
  514.                 s += '1';
  515.             }
  516.             else
  517.             {
  518.                 s += '0';
  519.             }
  520.         }
  521.  
  522.         s += '\n';
  523.     }
  524.  
  525.     std::cout << s;
  526. }
  527.  
  528. struct Board
  529. {
  530.     static constexpr int numDabbabas = 4;
  531.     static constexpr int numPieces = 2 + 1 + numDabbabas;
  532.     static constexpr Piece availablePieces[] = {
  533.         Piece(PieceType::King, Color::White),
  534.         Piece(PieceType::King, Color::Black),
  535.         Piece(PieceType::Knight, Color::Black),
  536.         Piece(PieceType::Dabbaba, Color::White),
  537.         Piece(PieceType::Dabbaba, Color::White),
  538.         Piece(PieceType::Dabbaba, Color::White),
  539.         Piece(PieceType::Dabbaba, Color::White)
  540.     };
  541.  
  542.     static constexpr int whites[] = { 0, 3, 4, 5, 6 };
  543.     static constexpr int blacks[] = { 1, 2 };
  544.  
  545.     Board()
  546.     {
  547.         std::fill(std::begin(m_pieces), std::end(m_pieces), Square::none());
  548.     }
  549.  
  550.     friend bool operator==(const Board& lhs, const Board& rhs)
  551.     {
  552.         return std::equal(std::begin(lhs.m_pieces), std::end(lhs.m_pieces), std::begin(rhs.m_pieces));
  553.     }
  554.  
  555.     Piece at(Square sq) const
  556.     {
  557.         for (int i = 0; i < numPieces; ++i)
  558.         {
  559.             if (m_pieces[i] == sq)
  560.             {
  561.                 return availablePieces[i];
  562.             }
  563.         }
  564.  
  565.         return Piece::none();
  566.     }
  567.  
  568.     void order()
  569.     {
  570.         auto end = std::end(m_pieces);
  571.         std::sort(end - numDabbabas, end, [](Square lhs, Square rhs) {return lhs.index() < rhs.index(); });
  572.     }
  573.  
  574.     void doMove(const Move& move)
  575.     {
  576.         const Square from = m_pieces[move.fromIdx()];
  577.         const Square to = move.to();
  578.  
  579.         for (int i = 0; i < numPieces; ++i)
  580.         {
  581.             if (m_pieces[i] == to)
  582.             {
  583.                 m_pieces[i] = Square::none();
  584.             }
  585.         }
  586.         m_pieces[move.fromIdx()] = to;
  587.  
  588.         order();
  589.     }
  590.  
  591.     void place(const Piece& piece, Square sq)
  592.     {
  593.         for (int i = 0; i < numPieces; ++i)
  594.         {
  595.             if (m_pieces[i] == sq)
  596.             {
  597.                 m_pieces[i] = Square::none();
  598.             }
  599.         }
  600.  
  601.         int idx = -1;
  602.         if (piece == Piece(PieceType::King, Color::White))
  603.         {
  604.             idx = 0;
  605.         }
  606.         else if (piece == Piece(PieceType::King, Color::Black))
  607.         {
  608.             idx = 1;
  609.         }
  610.         else if (piece.type() == PieceType::Knight)
  611.         {
  612.             idx = 2;
  613.         }
  614.         else
  615.         {
  616.             idx = 3;
  617.             for (int i = 0; i < numDabbabas; ++i)
  618.             {
  619.                 if (m_pieces[i + 3] == Square::none())
  620.                 {
  621.                     idx = i + 3;
  622.                 }
  623.             }
  624.         }
  625.         m_pieces[idx] = sq;
  626.  
  627.         order();
  628.     }
  629.  
  630.     BitBoardLayer bbByColor(Color c) const
  631.     {
  632.         BitBoardLayer bb{};
  633.  
  634.         if (c == Color::White)
  635.         {
  636.             for (int i : whites)
  637.             {
  638.                 const Square sq = m_pieces[i];
  639.                 if (sq != Square::none())
  640.                 {
  641.                     bb |= sq;
  642.                 }
  643.             }
  644.         }
  645.         else
  646.         {
  647.             for (int i : blacks)
  648.             {
  649.                 const Square sq = m_pieces[i];
  650.                 if (sq != Square::none())
  651.                 {
  652.                     bb |= sq;
  653.                 }
  654.             }
  655.         }
  656.  
  657.         return bb;
  658.     }
  659.  
  660.     BitBoardLayer bb() const
  661.     {
  662.         BitBoardLayer bb{};
  663.  
  664.         for (int i = 0; i < numPieces; ++i)
  665.         {
  666.             const Square sq = m_pieces[i];
  667.             if (sq != Square::none())
  668.             {
  669.                 bb |= sq;
  670.             }
  671.         }
  672.  
  673.         return bb;
  674.     }
  675.  
  676.     bool hasBothKings() const
  677.     {
  678.         return whiteKing() != Square::none() && blackKing() != Square::none();
  679.     }
  680.  
  681.     BitBoardLayer bbAttackedByPiece(int i) const;
  682.  
  683.     BitBoardLayer bbAttackedByColor(Color color) const
  684.     {
  685.         BitBoardLayer bb{};
  686.  
  687.         if (color == Color::White)
  688.         {
  689.             for (int i : whites)
  690.             {
  691.                 bb |= bbAttackedByPiece(i);
  692.             }
  693.         }
  694.         else
  695.         {
  696.             for (int i : blacks)
  697.             {
  698.                 bb |= bbAttackedByPiece(i);
  699.             }
  700.         }
  701.  
  702.         return bb;
  703.     }
  704.  
  705.     bool hasNoKings() const
  706.     {
  707.         return whiteKing() == Square::none() && blackKing() == Square::none();
  708.     }
  709.  
  710.     bool kingsAttackEachOther() const;
  711.  
  712.     Square whiteKing() const
  713.     {
  714.         return m_pieces[0];
  715.     }
  716.  
  717.     Square blackKing() const
  718.     {
  719.         return m_pieces[1];
  720.     }
  721.  
  722.     Square blackKnight() const
  723.     {
  724.         return m_pieces[2];
  725.     }
  726.  
  727.     Square whiteDabbaba(int i) const
  728.     {
  729.         return m_pieces[3 + i];
  730.     }
  731.  
  732.     Square pieceSquare(int i) const
  733.     {
  734.         return m_pieces[i];
  735.     }
  736.  
  737.     const auto& pieces() const
  738.     {
  739.         return m_pieces;
  740.     }
  741.  
  742. private:
  743.     std::array<Square, numPieces> m_pieces;
  744. };
  745.  
  746. template <PieceType PieceTypeV>
  747. struct MoveGenerator;
  748.  
  749. template <int SizeV>
  750. constexpr BitBoardLayer generateMovesForLeaper(Square sq, const std::array<Offset, SizeV>& offsets)
  751. {
  752.     BitBoardLayer bb{};
  753.  
  754.     const int x = sq.x();
  755.     const int y = sq.y();
  756.  
  757.     for (auto&& offset : offsets)
  758.     {
  759.         const int xx = x + offset.dx();
  760.         const int yy = y + offset.dy();
  761.         if (xx < 0 || xx >= width || yy < 0 || yy >= height)
  762.         {
  763.             continue;
  764.         }
  765.  
  766.         Square sq2(xx, yy);
  767.         bb.set(sq2);
  768.     }
  769.  
  770.     return bb;
  771. }
  772.  
  773. template <int SizeV>
  774. constexpr std::array<BitBoardLayer, width* height> generateMovesForLeaper(const std::array<Offset, SizeV>& offsets)
  775. {
  776.     std::array<BitBoardLayer, width* height> moves;
  777.  
  778.     for (int x = 0; x < width; ++x)
  779.     {
  780.         for (int y = 0; y < height; ++y)
  781.         {
  782.             const Square sq(x, y);
  783.  
  784.             moves[sq.index()] = generateMovesForLeaper(sq, offsets);
  785.         }
  786.     }
  787.  
  788.     return moves;
  789. }
  790.  
  791. template <>
  792. struct MoveGenerator<PieceType::Knight>
  793. {
  794.     BitBoardLayer movesFromSquare(const Board& position, Square from) const
  795.     {
  796.         const Color fromColor = position.at(from).color();
  797.         return m_moves[from.index()] & ~(position.bbByColor(fromColor));
  798.     }
  799.  
  800.     BitBoardLayer movesToSquare(const Board& position, Square to) const
  801.     {
  802.         return m_moves[to.index()] & ~(position.bb());
  803.     }
  804.  
  805.     BitBoardLayer attacksFromSquare(const Board& position, Square from) const
  806.     {
  807.         return m_moves[from.index()];
  808.     }
  809.  
  810. private:
  811.     static constexpr std::array<Offset, 8> m_offsets{ { {-1, -2}, {-1, 2}, {1, -2}, {1, 2}, {-2, -1}, {-2, 1}, {2, -1}, {2, 1} } };
  812.     static constexpr std::array<BitBoardLayer, width* height> m_moves = generateMovesForLeaper(m_offsets);
  813. };
  814.  
  815. template <>
  816. struct MoveGenerator<PieceType::Dabbaba>
  817. {
  818.     BitBoardLayer movesFromSquare(const Board& position, Square from) const
  819.     {
  820.         const Color fromColor = position.at(from).color();
  821.         return m_moves[from.index()] & ~(position.bbByColor(fromColor));
  822.     }
  823.  
  824.     BitBoardLayer movesToSquare(const Board& position, Square to) const
  825.     {
  826.         return m_moves[to.index()] & ~(position.bb());
  827.     }
  828.  
  829.     BitBoardLayer attacksFromSquare(const Board& position, Square from) const
  830.     {
  831.         return m_moves[from.index()];
  832.     }
  833.  
  834. private:
  835.     static constexpr std::array<Offset, 4> m_offsets{ { {-2, 0}, {2, 0}, {0, -2}, {0, 2} } };
  836.     static constexpr std::array<BitBoardLayer, width* height> m_moves = generateMovesForLeaper(m_offsets);
  837. };
  838.  
  839. template <>
  840. struct MoveGenerator<PieceType::King>
  841. {
  842.     BitBoardLayer movesFromSquare(const Board& position, Square from) const
  843.     {
  844.         const Color fromColor = position.at(from).color();
  845.         return m_moves[from.index()] & ~(position.bbByColor(fromColor));
  846.     }
  847.  
  848.     BitBoardLayer movesToSquare(const Board& position, Square to) const
  849.     {
  850.         return m_moves[to.index()] & ~(position.bb());
  851.     }
  852.  
  853.     BitBoardLayer attacksFromSquare(const Board& position, Square from) const
  854.     {
  855.         return m_moves[from.index()];
  856.     }
  857.  
  858. private:
  859.     static constexpr std::array<Offset, 8> m_offsets{ { {-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1} } };
  860.     static constexpr std::array<BitBoardLayer, width* height> m_moves = generateMovesForLeaper(m_offsets);
  861. };
  862.  
  863. BitBoardLayer Board::bbAttackedByPiece(int i) const
  864. {
  865.     MoveGenerator<PieceType::Knight> knightMoveGenerator;
  866.     MoveGenerator<PieceType::Dabbaba> dabbabaMoveGenerator;
  867.     MoveGenerator<PieceType::King> kingMoveGenerator;
  868.  
  869.     const Square sq = m_pieces[i];
  870.     if (sq == Square::none()) return {};
  871.     PieceType pieceType = Board::availablePieces[i].type();
  872.  
  873.     BitBoardLayer bb{};
  874.  
  875.     switch (pieceType)
  876.     {
  877.     case PieceType::King:
  878.         bb |= kingMoveGenerator.movesFromSquare(*this, sq);
  879.         break;
  880.  
  881.     case PieceType::Knight:
  882.         bb |= knightMoveGenerator.movesFromSquare(*this, sq);
  883.         break;
  884.  
  885.     case PieceType::Dabbaba:
  886.         bb |= dabbabaMoveGenerator.movesFromSquare(*this, sq);
  887.         break;
  888.     }
  889.  
  890.     return bb;
  891. }
  892.  
  893. bool Board::kingsAttackEachOther() const
  894. {
  895.     MoveGenerator<PieceType::King> kingMoveGenerator;
  896.  
  897.     Square wk = whiteKing();
  898.     Square bk = blackKing();
  899.  
  900.     return (kingMoveGenerator.attacksFromSquare(*this, wk) & bk).any();
  901. }
  902.  
  903. struct Zobrist
  904. {
  905.     Zobrist()
  906.     {
  907.         std::mt19937_64 rng;
  908.         std::uniform_int_distribution<std::uint64_t> d;
  909.         std::generate_n(data(), width * height * numPieceTypes * numColors, [&]() {return d(rng); });
  910.  
  911.         for (int i = 0; i < width * height; ++i)
  912.         {
  913.             m_hash[i][Piece(PieceType::None, Color::White).index()] = m_hash[i][Piece(PieceType::None, Color::Black).index()];
  914.         }
  915.  
  916.         m_sideChangeHash = d(rng);
  917.     }
  918.  
  919.     std::uint64_t hash(const Board& board, Color sideToMove) const
  920.     {
  921.         std::uint64_t h = 0;
  922.  
  923.         for (int x = 0; x < width; ++x)
  924.         {
  925.             for (int y = 0; y < height; ++y)
  926.             {
  927.                 const Square sq(x, y);
  928.  
  929.                 h ^= m_hash[sq.index()][board.at(sq).index()];
  930.             }
  931.         }
  932.  
  933.         if (sideToMove == Color::Black)
  934.         {
  935.             h ^= m_sideChangeHash;
  936.         }
  937.  
  938.         return h;
  939.     }
  940.  
  941.     std::uint64_t emptySquareHash(Square sq) const
  942.     {
  943.         return m_hash[sq.index()][Piece::none().index()];
  944.     }
  945.  
  946.     std::uint64_t hashAfterMove(std::uint64_t hash, const Board& board, const Move& move) const
  947.     {
  948.         const Square from = board.pieceSquare(move.fromIdx());
  949.         const Square to = move.to();
  950.  
  951.         hash ^= m_hash[from.index()][board.at(from).index()];
  952.         hash ^= emptySquareHash(from);
  953.  
  954.         hash ^= m_hash[to.index()][board.at(to).index()];
  955.         hash ^= m_hash[to.index()][board.at(from).index()];
  956.  
  957.         hash ^= m_sideChangeHash;
  958.  
  959.         return hash;
  960.     }
  961.  
  962.     std::uint64_t hashAfterPieceReplaced(std::uint64_t hash, const Board& board, const Piece& piece, Square sq) const
  963.     {
  964.         hash ^= m_hash[sq.index()][board.at(sq).index()];
  965.         hash ^= m_hash[sq.index()][piece.index()];
  966.  
  967.         return hash;
  968.     }
  969.  
  970. private:
  971.     std::uint64_t m_hash[width * height][numAllPieces];
  972.     std::uint64_t m_sideChangeHash;
  973.  
  974.     std::uint64_t* data()
  975.     {
  976.         return &(m_hash[0][0]);
  977.     }
  978. } g_zobrist{};
  979.  
  980. enum struct GameState
  981. {
  982.     Invalid,
  983.     Win,
  984.     Loss,
  985.     Valid
  986. };
  987.  
  988. struct Position;
  989.  
  990.  
  991. struct Moves
  992. {
  993.     Moves() :
  994.         m_moves{}
  995.     {
  996.  
  997.         std::fill(std::begin(m_moves), std::end(m_moves), BitBoardLayer::none());
  998.     }
  999.  
  1000.     BitBoardLayer& operator[](int fromIdx)
  1001.     {
  1002.         return m_moves[fromIdx];
  1003.     }
  1004.  
  1005.     const BitBoardLayer& operator[](int fromIdx) const
  1006.     {
  1007.         return m_moves[fromIdx];
  1008.     }
  1009.  
  1010.     template <typename FuncT>
  1011.     void forEach(FuncT&& f) const
  1012.     {
  1013.         for (int i = 0; i < Board::numPieces; ++i)
  1014.         {
  1015.             BitBoardLayer bb = m_moves[i];
  1016.             while (!bb.isEmpty())
  1017.             {
  1018.                 const Square to = bb.firstSquare();
  1019.                 bb.unset(to);
  1020.                 f(Move(i, to));
  1021.             }
  1022.         }
  1023.     }
  1024.  
  1025. private:
  1026.     std::array<BitBoardLayer, Board::numPieces> m_moves;
  1027. };
  1028.  
  1029. Moves generateAllMovesForward(const Position& position);
  1030. void print(const Position& pos);
  1031.  
  1032. struct Position
  1033. {
  1034.     static Position empty(Color nextMoveColor)
  1035.     {
  1036.         return Position(nextMoveColor);
  1037.     }
  1038.  
  1039.     Position& operator=(const Position& other) = default;
  1040.  
  1041.     friend bool operator==(const Position& lhs, const Position& rhs)
  1042.     {
  1043.         return lhs.m_sideToMove == rhs.m_sideToMove && lhs.m_board == rhs.m_board;
  1044.     }
  1045.  
  1046.     bool hasTheSamePieces(const Position& other) const
  1047.     {
  1048.         for (int i = 0; i < numAllPieces; ++i)
  1049.         {
  1050.             if ((m_board.pieceSquare(i) == Square::none()) != (other.m_board.pieceSquare(i) == Square::none()))
  1051.             {
  1052.                 return false;
  1053.             }
  1054.         }
  1055.         return true;
  1056.     }
  1057.  
  1058.     Piece at(Square sq) const
  1059.     {
  1060.         return m_board.at(sq);
  1061.     }
  1062.  
  1063.     std::uint64_t hash() const
  1064.     {
  1065.         return murmur64(*reinterpret_cast<const std::uint64_t*>(this));
  1066.     }
  1067.  
  1068.     void doMove(const Move& move)
  1069.     {
  1070.         m_board.doMove(move);
  1071.  
  1072.         m_sideToMove = oppositeColor(m_sideToMove);
  1073.     }
  1074.  
  1075.     void doMove(const Move& move, Piece capturedPiece)
  1076.     {
  1077.         const Square sq = m_board.pieceSquare(move.fromIdx()); // since it changes after a move is made
  1078.  
  1079.         doMove(move);
  1080.         if (capturedPiece.type() != PieceType::None)
  1081.         {
  1082.             place(capturedPiece, sq);
  1083.         }
  1084.     }
  1085.  
  1086.     void place(const Piece& piece, Square sq)
  1087.     {
  1088.         m_board.place(piece, sq);
  1089.     }
  1090.  
  1091.     Color sideToMove() const
  1092.     {
  1093.         return m_sideToMove;
  1094.     }
  1095.  
  1096.     BitBoardLayer bbByColor(Color c) const
  1097.     {
  1098.         return m_board.bbByColor(c);
  1099.     }
  1100.  
  1101.     BitBoardLayer bb() const
  1102.     {
  1103.         return m_board.bb();
  1104.     }
  1105.  
  1106.     bool hasBothKings() const
  1107.     {
  1108.         return m_board.hasBothKings();
  1109.     }
  1110.  
  1111.     const Board& board() const
  1112.     {
  1113.         return m_board;
  1114.     }
  1115.  
  1116.     BitBoardLayer bbKing(Color color) const
  1117.     {
  1118.         if (color == Color::White)
  1119.         {
  1120.             return BitBoardLayer::none() | m_board.whiteKing();
  1121.         }
  1122.         else
  1123.         {
  1124.             return BitBoardLayer::none() | m_board.blackKing();
  1125.         }
  1126.     }
  1127.  
  1128.     bool isInCheck(Color color) const
  1129.     {
  1130.         const BitBoardLayer bbAttack = m_board.bbAttackedByColor(oppositeColor(color));
  1131.         return (bbAttack & bbKing(color)).any();
  1132.     }
  1133.  
  1134.     bool isInCheck() const
  1135.     {
  1136.         return isInCheck(m_sideToMove);
  1137.     }
  1138.  
  1139.     bool isOpponentInCheck() const
  1140.     {
  1141.         return isInCheck(oppositeColor(m_sideToMove));
  1142.     }
  1143.  
  1144.     bool isCheckmate() const
  1145.     {
  1146.         if (!isInCheck())
  1147.         {
  1148.             return false;
  1149.         }
  1150.  
  1151.         bool checkmate = true;
  1152.         const Moves moves = generateAllMovesForward(*this);
  1153.         moves.forEach([&](Move move) {
  1154.             Position nextPos = *this;
  1155.             nextPos.doMove(move);
  1156.             if (!nextPos.isOpponentInCheck())
  1157.             {
  1158.                 checkmate = false;
  1159.             }
  1160.         });
  1161.  
  1162.         return checkmate;
  1163.     }
  1164.  
  1165.     GameState gameState() const
  1166.     {
  1167.         if (!hasBothKings())
  1168.         {
  1169.             return GameState::Invalid;
  1170.         }
  1171.  
  1172.         if (isInCheck(oppositeColor(m_sideToMove)))
  1173.         {
  1174.             return GameState::Invalid;
  1175.         }
  1176.  
  1177.         if (isCheckmate())
  1178.         {
  1179.             if (m_sideToMove == Color::White)
  1180.             {
  1181.                 return GameState::Loss;
  1182.             }
  1183.             else
  1184.             {
  1185.                 return GameState::Win;
  1186.             }
  1187.         }
  1188.  
  1189.         return GameState::Valid;
  1190.     }
  1191.  
  1192. private:
  1193.     Board m_board;
  1194.     Color m_sideToMove;
  1195.  
  1196.     Position(Color c) :
  1197.         m_board{},
  1198.         m_sideToMove(c)
  1199.     {
  1200.     }
  1201. };
  1202.  
  1203. static_assert(sizeof(Position) == 8, "must be 8 to allow fast hash computation to work");
  1204.  
  1205. static constexpr int sb = sizeof(Board);
  1206. static constexpr int sp = sizeof(Position);
  1207.  
  1208. namespace std
  1209. {
  1210.     template<> struct hash<Position>
  1211.     {
  1212.         using argument_type = Position;
  1213.         using result_type = std::uint64_t;
  1214.         result_type operator()(const argument_type& s) const noexcept
  1215.         {
  1216.             return s.hash();
  1217.         }
  1218.     };
  1219. }
  1220.  
  1221. Moves generateAllMovesForward(const Position& position)
  1222. {
  1223.     MoveGenerator<PieceType::Knight> knightMoveGenerator;
  1224.     MoveGenerator<PieceType::Dabbaba> dabbabaMoveGenerator;
  1225.     MoveGenerator<PieceType::King> kingMoveGenerator;
  1226.  
  1227.     Moves moves;
  1228.  
  1229.     const Color sideToMove = position.sideToMove();
  1230.  
  1231.     for (int i = 0; i < Board::numPieces; ++i)
  1232.     {
  1233.         const Square sq = position.board().pieceSquare(i);
  1234.         if (sq == Square::none()) continue;
  1235.  
  1236.         const Piece piece = position.at(sq);
  1237.         if (piece.type() == PieceType::None || piece.color() != sideToMove)
  1238.         {
  1239.             continue;
  1240.         }
  1241.  
  1242.         switch (piece.type())
  1243.         {
  1244.         case PieceType::Knight:
  1245.             moves[i] = knightMoveGenerator.movesFromSquare(position.board(), sq);
  1246.             break;
  1247.  
  1248.         case PieceType::Dabbaba:
  1249.             moves[i] = dabbabaMoveGenerator.movesFromSquare(position.board(), sq);
  1250.             break;
  1251.  
  1252.         case PieceType::King:
  1253.             moves[i] = kingMoveGenerator.movesFromSquare(position.board(), sq);
  1254.             break;
  1255.         }
  1256.     }
  1257.  
  1258.     return moves;
  1259. }
  1260.  
  1261. Moves generateAllMovesBackward(const Position& position)
  1262. {
  1263.     MoveGenerator<PieceType::Knight> knightMoveGenerator;
  1264.     MoveGenerator<PieceType::Dabbaba> dabbabaMoveGenerator;
  1265.     MoveGenerator<PieceType::King> kingMoveGenerator;
  1266.  
  1267.     Moves moves;
  1268.  
  1269.     const Color sideToMove = oppositeColor(position.sideToMove());
  1270.  
  1271.     for (int i = 0; i < Board::numPieces; ++i)
  1272.     {
  1273.         const Square sq = position.board().pieceSquare(i);
  1274.         if (sq == Square::none()) continue;
  1275.  
  1276.         const Piece piece = position.at(sq);
  1277.         if (piece.type() == PieceType::None || piece.color() != sideToMove)
  1278.         {
  1279.             continue;
  1280.         }
  1281.  
  1282.         switch (piece.type())
  1283.         {
  1284.         case PieceType::Knight:
  1285.             moves[i] = knightMoveGenerator.movesToSquare(position.board(), sq);
  1286.             break;
  1287.  
  1288.         case PieceType::Dabbaba:
  1289.             moves[i] = dabbabaMoveGenerator.movesToSquare(position.board(), sq);
  1290.             break;
  1291.  
  1292.         case PieceType::King:
  1293.             moves[i] = kingMoveGenerator.movesToSquare(position.board(), sq);
  1294.             break;
  1295.         }
  1296.     }
  1297.  
  1298.     return moves;
  1299. }
  1300.  
  1301. struct DtmEntry
  1302. {
  1303.     using ScoreType = int;
  1304.  
  1305.     static DtmEntry draw()
  1306.     {
  1307.         return DtmEntry(Move::none(), 0);
  1308.     }
  1309.  
  1310.     static DtmEntry win()
  1311.     {
  1312.         return DtmEntry(Move::none(), std::numeric_limits<ScoreType>::max());
  1313.     }
  1314.  
  1315.     static DtmEntry loss()
  1316.     {
  1317.         return DtmEntry(Move::none(), std::numeric_limits<ScoreType>::min());
  1318.     }
  1319.  
  1320.     bool isDraw() const
  1321.     {
  1322.         return m_score == 0;
  1323.     }
  1324.  
  1325.     bool isWin() const
  1326.     {
  1327.         return m_score == std::numeric_limits<ScoreType>::max();
  1328.     }
  1329.  
  1330.     bool isLoss() const
  1331.     {
  1332.         return m_score == std::numeric_limits<ScoreType>::min();
  1333.     }
  1334.  
  1335.     Move nextMove() const
  1336.     {
  1337.         return m_nextMove;
  1338.     }
  1339.  
  1340.     ScoreType score() const
  1341.     {
  1342.         return m_score;
  1343.     }
  1344.  
  1345.     void setScore(ScoreType score)
  1346.     {
  1347.         m_score = score;
  1348.     }
  1349.  
  1350.     ScoreType dtm() const
  1351.     {
  1352.         if (isDraw()) return std::numeric_limits<ScoreType>::max();
  1353.  
  1354.         if (m_score > 0)
  1355.         {
  1356.             return std::numeric_limits<ScoreType>::max() - m_score;
  1357.         }
  1358.         else
  1359.         {
  1360.             return std::numeric_limits<ScoreType>::min() - m_score;
  1361.         }
  1362.     }
  1363.  
  1364.     void setNextMove(Move move)
  1365.     {
  1366.         m_nextMove = move;
  1367.     }
  1368.  
  1369. private:
  1370.     Move m_nextMove;
  1371.     ScoreType m_score;
  1372.  
  1373.     DtmEntry(Move move, ScoreType score) :
  1374.         m_nextMove(move),
  1375.         m_score(score)
  1376.     {
  1377.     }
  1378. };
  1379.  
  1380. static_assert(sizeof(DtmEntry) == 8);
  1381. static_assert(sizeof(MapType<Position, DtmEntry>::value_type) == 16);
  1382.  
  1383. struct PositionGenerator
  1384. {
  1385.     MapType<Position, DtmEntry> allReachable(const Position& initialPosition)
  1386.     {
  1387.         MapType<Position, DtmEntry> positions;
  1388.  
  1389.         auto addPosition = [&](const Position& pos, GameState gs)
  1390.         {
  1391.             switch (gs)
  1392.             {
  1393.             case GameState::Loss:
  1394.                 return positions.emplace(
  1395.                     std::piecewise_construct,
  1396.                     std::forward_as_tuple(pos),
  1397.                     std::forward_as_tuple(DtmEntry::loss())
  1398.                 );
  1399.  
  1400.             case GameState::Win:
  1401.                 return positions.emplace(
  1402.                     std::piecewise_construct,
  1403.                     std::forward_as_tuple(pos),
  1404.                     std::forward_as_tuple(DtmEntry::win())
  1405.                 );
  1406.  
  1407.             case GameState::Valid:
  1408.                 return positions.emplace(
  1409.                     std::piecewise_construct,
  1410.                     std::forward_as_tuple(pos),
  1411.                     std::forward_as_tuple(DtmEntry::draw())
  1412.                 );
  1413.             }
  1414.         };
  1415.  
  1416.         std::queue<const Position*> positionQueue;
  1417.         GameState gs = initialPosition.gameState();
  1418.         if (gs == GameState::Invalid) return positions;
  1419.  
  1420.         positionQueue.emplace(&initialPosition);
  1421.         addPosition(initialPosition, gs);
  1422.  
  1423.         int i = 0;
  1424.  
  1425.         while (!positionQueue.empty())
  1426.         {
  1427.             const Position& pos = *positionQueue.front();
  1428.             positionQueue.pop();
  1429.  
  1430.             ++i;
  1431.             if (i % reportEveryNPositions == 0)
  1432.             {
  1433.                 std::cout << "Number of positions enumerated: " << i << '\n';
  1434.             }
  1435.  
  1436.             Moves moves = generateAllMovesForward(pos);
  1437.             moves.forEach(
  1438.                 [&](const Move & move) {
  1439.                     Position nextPos = pos;
  1440.                     auto h = nextPos.board().pieces();
  1441.                     nextPos.doMove(move);
  1442.                     GameState gs = nextPos.gameState();
  1443.                     if (gs == GameState::Invalid || positions.count(nextPos) > 0)
  1444.                     {
  1445.                         return;
  1446.                     }
  1447.  
  1448.                     auto it = addPosition(nextPos, gs);
  1449.                     positionQueue.emplace(&(it.first->first));
  1450.                 }
  1451.             );
  1452.         }
  1453.  
  1454.         return positions;
  1455.     }
  1456. };
  1457.  
  1458. struct Solver
  1459. {
  1460.     void generateDtm(MapType<Position, DtmEntry>& positions, const Position& initialPos)
  1461.     {
  1462.         std::vector<std::pair<const Position, DtmEntry>*> candidates;
  1463.         std::vector<std::pair<const Position, DtmEntry>*> nextCandidates;
  1464.  
  1465.         int numPositionsExactTotal = 0;
  1466.         {
  1467.             for (auto&& p : positions)
  1468.             {
  1469.                 auto&& pos = p.first;
  1470.                 auto&& entry = p.second;
  1471.  
  1472.                 if (pos.hasTheSamePieces(initialPos))
  1473.                 {
  1474.                     ++numPositionsExactTotal;
  1475.                 }
  1476.             }
  1477.         }
  1478.  
  1479.         for (auto&& p : positions)
  1480.         {
  1481.             auto&& pos = p.first;
  1482.             auto&& entry = p.second;
  1483.  
  1484.             if (!entry.isDraw())
  1485.             {
  1486.                 continue;
  1487.             }
  1488.  
  1489.             nextCandidates.emplace_back(&p);
  1490.         }
  1491.  
  1492.         int numWonPositionsTotal = 0;
  1493.         int numLostPositionsTotal = 0;
  1494.         int numWonPositionsTotalExact = 0;
  1495.         int numLostPositionsTotalExact = 0;
  1496.         for (int i = 0;;++i)
  1497.         {
  1498.             std::cout << "Started DTM = " << i + 1 << " plies ...\n";
  1499.             int numWonPositions = 0;
  1500.             int numLostPositions = 0;
  1501.             int numWonPositionsExact = 0;
  1502.             int numLostPositionsExact = 0;
  1503.  
  1504.             candidates = std::move(nextCandidates);
  1505.             nextCandidates = std::vector<std::pair<const Position, DtmEntry>*>{};
  1506.  
  1507.             std::sort(std::begin(candidates), std::end(candidates), std::less<>());
  1508.             candidates.erase(std::unique(std::begin(candidates), std::end(candidates), std::equal_to<>()), std::end(candidates));
  1509.  
  1510.             int j = 0;
  1511.  
  1512.             bool anyChange = false;
  1513.             for (auto&& p : candidates)
  1514.             {
  1515.                 auto&& pos = p->first;
  1516.                 auto&& entry = p->second;
  1517.  
  1518.                 ++j;
  1519.                 if (j % reportEveryNPositions == 0)
  1520.                 {
  1521.                     std::cout << "\tNumber of positions examined: " << j << " of " << candidates.size() << " (" << static_cast<float>(j)/candidates.size()*100.0f << "%)\n";
  1522.                 }
  1523.  
  1524.                 Move bestNextMove = Move::none();
  1525.                 DtmEntry::ScoreType bestScore = pos.sideToMove() == Color::White ? std::numeric_limits<DtmEntry::ScoreType>::min() : std::numeric_limits<DtmEntry::ScoreType>::max();
  1526.                 if (!entry.isDraw())
  1527.                 {
  1528.                     continue;
  1529.                 }
  1530.  
  1531.                 Moves moves = generateAllMovesForward(pos);
  1532.                 moves.forEach(
  1533.                     [&](const Move & move) {
  1534.                         Position nextPos = pos;
  1535.                         nextPos.doMove(move);
  1536.                         GameState gs = nextPos.gameState();
  1537.                         if (gs == GameState::Invalid)
  1538.                         {
  1539.                             return;
  1540.                         }
  1541.  
  1542.                         auto it = positions.find(nextPos);
  1543.                         if (it == std::end(positions))
  1544.                         {
  1545.                             return;
  1546.                         }
  1547.  
  1548.                         auto& nextEntry = it->second;
  1549.                         if (!nextEntry.isDraw() && (nextEntry.dtm() > i || nextEntry.dtm() < -i))
  1550.                         {
  1551.                             return;
  1552.                         }
  1553.  
  1554.                         if (pos.sideToMove() == Color::White)
  1555.                         {
  1556.                             // highest score
  1557.                             if (nextEntry.score() > bestScore)
  1558.                             {
  1559.                                 bestScore = nextEntry.score();
  1560.                                 bestNextMove = move;
  1561.                             }
  1562.                         }
  1563.                         else
  1564.                         {
  1565.                             // lowest score
  1566.                             if (nextEntry.score() < bestScore)
  1567.                             {
  1568.                                 bestScore = nextEntry.score();
  1569.                                 bestNextMove = move;
  1570.                             }
  1571.                         }
  1572.                     }
  1573.                 );
  1574.  
  1575.                 if (bestNextMove == Move::none())
  1576.                 {
  1577.                     continue;
  1578.                 }
  1579.  
  1580.                 const bool exact = pos.hasTheSamePieces(initialPos);
  1581.  
  1582.                 if (bestScore > 0)
  1583.                 {
  1584.                     ++numWonPositions;
  1585.                     if (exact) ++numWonPositionsExact;
  1586.                     bestScore -= 1;
  1587.                 }
  1588.                 else if (bestScore < 0)
  1589.                 {
  1590.                     ++numLostPositions;
  1591.                     if (exact) ++numLostPositionsExact;
  1592.                     bestScore += 1;
  1593.                 }
  1594.  
  1595.                 if (bestScore == entry.score())
  1596.                 {
  1597.                     continue;
  1598.                 }
  1599.  
  1600.                 anyChange = true;
  1601.  
  1602.                 entry.setScore(bestScore);
  1603.                 entry.setNextMove(bestNextMove);
  1604.  
  1605.                 {
  1606.                     // queue up all the moves that can lead to this position
  1607.  
  1608.                     Moves moves = generateAllMovesBackward(pos);
  1609.                     moves.forEach(
  1610.                         [&](const Move & move) {
  1611.                             for (int i = 0; i < Board::numPieces; ++i)
  1612.                             {
  1613.                                 if (initialPos.board().pieceSquare(i) != Square::none() && pos.board().pieceSquare(i) == Square::none())
  1614.                                 {
  1615.                                     Position prevPos = pos;
  1616.                                     prevPos.doMove(move, Board::availablePieces[i]);
  1617.                                     GameState gs = prevPos.gameState();
  1618.                                     if (gs == GameState::Invalid)
  1619.                                     {
  1620.                                         continue;
  1621.                                     }
  1622.  
  1623.                                     auto it = positions.find(prevPos);
  1624.                                     if (it == std::end(positions))
  1625.                                     {
  1626.                                         continue;
  1627.                                     }
  1628.  
  1629.                                     nextCandidates.emplace_back(&*it);
  1630.                                 }
  1631.                             }
  1632.  
  1633.                             Position prevPos = pos;
  1634.                             prevPos.doMove(move, Piece::none());
  1635.                             GameState gs = prevPos.gameState();
  1636.                             if (gs == GameState::Invalid)
  1637.                             {
  1638.                                 return;
  1639.                             }
  1640.  
  1641.                             auto it = positions.find(prevPos);
  1642.                             if (it == std::end(positions))
  1643.                             {
  1644.                                 return;
  1645.                             }
  1646.  
  1647.                             nextCandidates.emplace_back(&*it);
  1648.                         }
  1649.                     );
  1650.                 }
  1651.             }
  1652.  
  1653.             std::cout << "Among positions with all starting pieces:\n";
  1654.             std::cout << "W/L: " << numWonPositionsExact << "/" << numLostPositionsExact << " positions\n";
  1655.             std::cout << "Among all postions:\n";
  1656.             std::cout << "W/L: " << numWonPositions << "/" << numLostPositions << " positions\n\n";
  1657.             numWonPositionsTotal += numWonPositions;
  1658.             numLostPositionsTotal += numLostPositions;
  1659.             numWonPositionsTotalExact += numWonPositionsExact;
  1660.             numLostPositionsTotalExact += numLostPositionsExact;
  1661.  
  1662.             if (!anyChange)
  1663.             {
  1664.                 break;
  1665.             }
  1666.         }
  1667.  
  1668.         const int numDrawnPositionsTotalExact = numPositionsExactTotal - numWonPositionsTotalExact - numLostPositionsTotalExact;
  1669.         const int numDrawnPositionsTotal = positions.size() - numWonPositionsTotal - numLostPositionsTotal;
  1670.  
  1671.         std::cout << "Among positions with all starting pieces:\n";
  1672.         std::cout << "WDL: " << numWonPositionsTotalExact << ' ' << numDrawnPositionsTotalExact << ' ' << numLostPositionsTotalExact << '\n';
  1673.         std::cout << "WDL: "
  1674.             << numWonPositionsTotalExact * 100.0f / numPositionsExactTotal << "% "
  1675.             << numDrawnPositionsTotalExact * 100.0f / numPositionsExactTotal << "% "
  1676.             << numLostPositionsTotalExact * 100.0f / numPositionsExactTotal << "%\n";
  1677.         std::cout << "Among all postions:\n";
  1678.         std::cout << "WDL: " << numWonPositionsTotal << ' ' << numDrawnPositionsTotal << ' ' << numLostPositionsTotal << '\n';
  1679.         std::cout << "WDL: "
  1680.             << numWonPositionsTotal * 100.0f / positions.size() << "% "
  1681.             << numDrawnPositionsTotal * 100.0f / positions.size() << "% "
  1682.             << numLostPositionsTotal * 100.0f / positions.size() << "%\n";
  1683.     }
  1684. };
  1685.  
  1686. const Position* findLongestDtm(MapType<Position, DtmEntry>& positions, const Position& initialPosition)
  1687. {
  1688.     const Position* bestPos = nullptr;
  1689.     const DtmEntry* bestEntry = nullptr;
  1690.     for (auto&& [pos, entry] : positions)
  1691.     {
  1692.         if (entry.isDraw()) continue;
  1693.  
  1694.         if (bestEntry != nullptr && std::abs(bestEntry->dtm()) >= std::abs(entry.dtm()))
  1695.         {
  1696.             continue;
  1697.         }
  1698.  
  1699.         if (!pos.hasTheSamePieces(initialPosition))
  1700.         {
  1701.             continue;
  1702.         }
  1703.  
  1704.         bestPos = &pos;
  1705.         bestEntry = &entry;
  1706.     }
  1707.  
  1708.     return bestPos;
  1709. }
  1710.  
  1711. void print(const Position& pos)
  1712. {
  1713.     for (int y = 0; y < height; ++y)
  1714.     {
  1715.         for (int x = 0; x < width; ++x)
  1716.         {
  1717.             const Square sq(x, y);
  1718.             const Piece piece = pos.at(sq);
  1719.  
  1720.             if (piece == Piece(PieceType::King, Color::White)) std::cout << "K";
  1721.             else if (piece == Piece(PieceType::Knight, Color::White)) std::cout << "N";
  1722.             else if (piece == Piece(PieceType::Dabbaba, Color::White)) std::cout << "D";
  1723.             else if (piece == Piece(PieceType::King, Color::Black)) std::cout << "k";
  1724.             else if (piece == Piece(PieceType::Knight, Color::Black)) std::cout << "n";
  1725.             else if (piece == Piece(PieceType::Dabbaba, Color::Black)) std::cout << "d";
  1726.             else std::cout << ".";
  1727.         }
  1728.         std::cout << '\n';
  1729.     }
  1730.     std::cout << (pos.sideToMove() == Color::White ? "WHITE\n" : "BLACK\n");
  1731. }
  1732.  
  1733. int main()
  1734. {
  1735.     PositionGenerator pg;
  1736.     Position initialPos = Position::empty(Color::White);
  1737.     initialPos.place(Piece(PieceType::King, Color::White), Square(2, 0));
  1738.     initialPos.place(Piece(PieceType::Dabbaba, Color::White), Square(0, 0));
  1739.     //initialPos.place(Piece(PieceType::Dabbaba, Color::White), Square(0, 1));
  1740.     //initialPos.place(Piece(PieceType::Dabbaba, Color::White), Square(1, 0));
  1741.     //initialPos.place(Piece(PieceType::Dabbaba, Color::White), Square(1, 1));
  1742.     initialPos.place(Piece(PieceType::Knight, Color::Black), Square(width-1, height-2));
  1743.     initialPos.place(Piece(PieceType::King, Color::Black), Square(width-1, height-1));
  1744.  
  1745.     auto a = std::chrono::high_resolution_clock::now();
  1746.     auto positions = pg.allReachable(initialPos);
  1747.     auto b = std::chrono::high_resolution_clock::now();
  1748.     std::cout << (b - a).count() / 1000000000.0f << '\n';
  1749.     std::cout << positions.size() << '\n';
  1750.     Solver solver;
  1751.     std::chrono::high_resolution_clock::now();
  1752.     solver.generateDtm(positions, initialPos);
  1753.     std::chrono::high_resolution_clock::now();
  1754.     std::cout << (b - a).count() / 1000000000.0f << '\n';
  1755.  
  1756.     auto posPtr = findLongestDtm(positions, initialPos);
  1757.     if (posPtr == nullptr)
  1758.     {
  1759.         std::cout << "No mate possible\n";
  1760.         return 0;
  1761.     }
  1762.  
  1763.     auto pos = *posPtr;
  1764.  
  1765.     std::cout << positions.at(pos).dtm() << '\n';
  1766.  
  1767.     for (;;)
  1768.     {
  1769.         auto& entry = positions.at(pos);
  1770.  
  1771.         print(pos);
  1772.  
  1773.         auto nextMove = entry.nextMove();
  1774.         if (nextMove == Move::none())
  1775.         {
  1776.             break;
  1777.         }
  1778.  
  1779.         pos.doMove(nextMove);
  1780.     }
  1781. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement