Forráskód Böngészése

improved promotion stuff

Nicolas Winkler 7 éve
szülő
commit
d990b8b7d6
5 módosított fájl, 134 hozzáadás és 23 törlés
  1. 54 4
      src/BitBoard.h
  2. 12 1
      src/BitOperations.h
  3. 0 13
      src/Board.h
  4. 30 5
      src/MoveGeneration.cpp
  5. 38 0
      src/MoveGeneration.h

+ 54 - 4
src/BitBoard.h

@@ -10,6 +10,8 @@
 
 namespace chessy
 {
+    enum PieceType : char;
+
     struct Index;
 
     struct Move;
@@ -21,11 +23,25 @@ namespace chessy
     const Side WHITE_SIDE = 0;
     const Side BLACK_SIDE = 1;
 
-    inline constexpr Side otherSide(Side side) {
+    inline constexpr Side otherSide(Side side)
+    {
         return !side;
     }
 }
 
+
+enum chessy::PieceType : char
+{
+    EMPTY = -1,
+    PAWN = 0,
+    KNIGHT = 1,
+    BISHOP = 2,
+    ROOK = 3,
+    QUEEN = 4,
+    KING = 5,
+};
+
+
 /*!
  * data structure to index one field on a chess board
  */
@@ -53,11 +69,21 @@ struct chessy::Index
 };
 
 
+/*!
+ * data structure that holds a simple move
+ */
 struct chessy::Move
 {
     Index origin;
     Index destination;
 
+    //! If the move is a promotion move, this field stores
+    //! the type of the resulting piece.
+    //! If this field is equal to <code>PieceType::PAWN</code>,
+    //! it is indicated, that no promotion happened.
+    PieceType promotion;
+
+
     Move            (void)          = default;
     Move            (const Move&)   = default;
     Move            (Move&&)        = default;
@@ -65,20 +91,37 @@ struct chessy::Move
     Move& operator= (const Move&)   = default;
     Move& operator= (Move&&)        = default;
 
-    inline Move(const std::string& move)
+    inline Move(const std::string& move) :
+        promotion{ PieceType::PAWN }
     {
         if (move.length() < 4)
             return;
         origin = Index { move.substr(0, 2) };
         destination = Index { move.substr(2, 2) };
+        if (move.length() > 4) {
+            switch (move[4]) {
+            case 'n': promotion = PieceType::KNIGHT; break;
+            case 'b': promotion = PieceType::BISHOP; break;
+            case 'r': promotion = PieceType::ROOK; break;
+            case 'q': promotion = PieceType::QUEEN; break;
+            }
+        }
     }
 
     inline Move(Index origin, Index destination) :
-        origin{ origin }, destination{ destination } {}
+        origin{ origin }, destination{ destination },
+        promotion{ PieceType::PAWN } {}
+
+    inline Move(Index origin, Index destination, PieceType promotion) :
+        origin{ origin }, destination{ destination }, promotion{ promotion } {}
 
     inline std::string asString(void) const
     {
-        return origin.getName() + destination.getName();
+        return origin.getName() + destination.getName() +
+            (promotion == PieceType::KNIGHT ? "n" : "") +
+            (promotion == PieceType::BISHOP ? "b" : "") +
+            (promotion == PieceType::ROOK ? "r" : "") +
+            (promotion == PieceType::QUEEN ? "q" : "");
     }
 };
 
@@ -129,6 +172,13 @@ struct chessy::Bitboard
     inline void     moveSEOne   (void)      { bits = (bits >> 7) & ~aColumn; }
     inline Bitboard seOne       (void)      { return (bits >> 7) & ~aColumn; }
 
+    template<Side side>
+    inline void     pushOne     (void);
+    template<>
+    inline void     pushOne<WHITE_SIDE>(void) { moveNorthOne(); }
+    template<>
+    inline void     pushOne<BLACK_SIDE>(void) { moveSouthOne(); }
+
     inline void     operator &= (const Bitboard& b)         { bits &= b.bits; }
     inline void     operator |= (const Bitboard& b)         { bits |= b.bits; }
     inline void     operator ^= (const Bitboard& b)         { bits ^= b.bits; }

+ 12 - 1
src/BitOperations.h

@@ -5,6 +5,7 @@
 
 #ifdef _MSC_VER
 #include <intrin.h>
+#include <stdlib.h>
 #endif
 
 
@@ -23,6 +24,8 @@ namespace chessy
     {
 #if __GNUC__ > 4 && __GNUC_MINOR__ >= 3
         return __builtin_bswap64(x);
+#elif defined(_MSC_VER)
+        return _byteswap_uint64(x);
 #else
         return (x << 56) |
             ((x & 0xFF00) << 40) |
@@ -40,7 +43,13 @@ namespace chessy
     */
     inline int trailingZeroes(U64 x) {
 #if __GNUC__ > 4 && 0
-        return __builtin_ctzll(x);
+        return __builtin_ctzll(x)
+#elif defined(_MSC_VER)
+        unsigned long out;
+        if (_BitScanForward64(&out, x))
+            return out;
+        else
+            return 0;
 #else
         for (int i = 0; i < 64; i++)
             if (x & (1ULL << i))
@@ -69,6 +78,8 @@ namespace chessy
     inline int popcount(U64 x) {
 #if __GNUC__ > 4
         return __builtin_popcount(x);
+#elif defined(_MSC_VER) && defined(_M_X64)
+        return _mm_popcnt_u64(x);
 #else
         int result = 0;
         for (int i = 0; i < 64; i++)

+ 0 - 13
src/Board.h

@@ -8,24 +8,11 @@
 
 namespace chessy
 {
-    enum PieceType : int;
 
     class Board;
 }
 
 
-enum chessy::PieceType : int
-{
-    EMPTY = -1,
-    PAWN = 0,
-    KNIGHT = 1,
-    BISHOP = 2,
-    ROOK = 3,
-    QUEEN = 4,
-    KING = 5
-};
-
-
 class chessy::Board
 {
     Bitboard whites[6];

+ 30 - 5
src/MoveGeneration.cpp

@@ -8,6 +8,9 @@ namespace chessy
     template class PawnPushGenerator<WHITE_SIDE>;
     template class PawnPushGenerator<BLACK_SIDE>;
 
+    template class PromotionGenerator<WHITE_SIDE>;
+    template class PromotionGenerator<BLACK_SIDE>;
+
     template class PawnDoublePushGenerator<WHITE_SIDE>;
     template class PawnDoublePushGenerator<BLACK_SIDE>;
 
@@ -23,13 +26,12 @@ typename PawnPushGenerator<side>::MoveIterator PawnPushGenerator<side>::begin(vo
 {
     const Board& board = chessGame.getBoard();
     Bitboard movedPieces = board.getPawns<side>();
-    if (side == WHITE_SIDE)
-        movedPieces.moveNorthOne();
-    else
-        movedPieces.moveSouthOne();
+    movedPieces.pushOne<side>();
     
+    // can't push into occupied squares
     movedPieces &= ~board.getOccupied();
-    //movedPieces &= Bitboard(~0xFF000000000000FFULL);
+    // use different move generator for promotions
+    movedPieces &= Bitboard(~0xFF000000000000FFULL);
 
     return MoveIterator{ movedPieces };
 }
@@ -43,6 +45,29 @@ typename PawnPushGenerator<side>::MoveIterator PawnPushGenerator<side>::end(void
 
 
 template<Side side>
+typename PromotionGenerator<side>::MoveIterator PromotionGenerator<side>::begin(void) const
+{
+    const Board& board = chessGame.getBoard();
+    Bitboard movedPieces = board.getPawns<side>();
+    movedPieces.pushOne<side>();
+
+    // can't promote into occupied squares
+    movedPieces &= ~board.getOccupied();
+    // use different move generator for promotions
+    movedPieces &= Bitboard(0xFF000000000000FFULL);
+
+    return MoveIterator{ movedPieces, PieceType::KNIGHT };
+}
+
+
+template<Side side>
+typename PromotionGenerator<side>::MoveIterator PromotionGenerator<side>::end(void) const
+{
+    return MoveIterator{ 0 };
+}
+
+
+template<Side side>
 typename PawnDoublePushGenerator<side>::MoveIterator
     PawnDoublePushGenerator<side>::begin(void) const
 {

+ 38 - 0
src/MoveGeneration.h

@@ -19,6 +19,8 @@ namespace chessy
     template<Side side>
     class PawnPushGenerator;
     template<Side side>
+    class PromotionGenerator;
+    template<Side side>
     class PawnDoublePushGenerator;
     template<Side side, Leftright leftright>
     class PawnCaptureGenerator;
@@ -102,6 +104,42 @@ public:
 };
 
 
+// TODO: rewrite better
+template<chessy::Side side>
+class chessy::PromotionGenerator
+{
+    const ChessGame& chessGame;
+
+    struct MoveIterator
+    {
+        PositionSet::PositionSetIterator promotions;
+        PieceType promotionType;
+        inline Move operator *(void) const
+        {
+            Index pp = *promotions;
+            return Move{ int8_t(pp + (side != WHITE_SIDE ? 8 : -8)), pp, promotionType };
+        }
+
+        inline void operator ++(void)
+        {
+            if (promotionType == PieceType::QUEEN)
+                ++promotions;
+            else
+                promotionType = static_cast<PieceType>(promotionType + 1);
+        }
+
+        inline bool operator !=(const MoveIterator& psi) const
+        {
+            return promotions != psi.promotions;
+        }
+    };
+
+    inline PromotionGenerator(const ChessGame& cg) : chessGame{ cg } {}
+    MoveIterator begin(void) const;
+    MoveIterator end(void) const;
+};
+
+
 template<chessy::Side side>
 class chessy::PawnDoublePushGenerator
 {