Nicolas Winkler 7 سال پیش
والد
کامیت
7bcb19b216
8فایلهای تغییر یافته به همراه61 افزوده شده و 22 حذف شده
  1. 12 3
      src/BitBoard.h
  2. 2 2
      src/BitOperations.h
  3. 4 4
      src/Board.cpp
  4. 15 0
      src/ChessGame.cpp
  5. 3 0
      src/ChessGame.h
  6. 15 8
      src/Minimax.cpp
  7. 2 1
      src/Minimax.h
  8. 8 4
      src/MoveGeneration.cpp

+ 12 - 3
src/BitBoard.h

@@ -81,6 +81,7 @@ struct chessy::Move
     PieceType promotion;
 
     bool isCastling;
+    bool isEnPassant;
 
 
     Move            (void)          = default;
@@ -91,7 +92,8 @@ struct chessy::Move
     Move& operator= (Move&&)        = default;
 
     inline Move(const std::string& move) :
-        promotion{ PieceType::PAWN }, isCastling{ false }
+        promotion{ PieceType::PAWN }, isCastling{ false },
+        isEnPassant{ false }
     {
         if (move.length() < 4)
             return;
@@ -109,7 +111,8 @@ struct chessy::Move
 
     inline Move(Index origin, Index destination) :
         origin{ origin }, destination{ destination },
-        promotion{ PieceType::PAWN }, isCastling{ false } {}
+        promotion{ PieceType::PAWN }, isCastling{ false },
+        isEnPassant{ false } {}
 
     inline Move(Index origin, Index destination, PieceType promotion) :
         origin{ origin }, destination{ destination }, promotion{ promotion },
@@ -117,7 +120,13 @@ struct chessy::Move
 
     inline Move(Index origin, Index destination, bool isCastling) :
         origin{ origin }, destination{ destination },
-        promotion{ PieceType::PAWN }, isCastling{ isCastling } {}
+        promotion{ PieceType::PAWN }, isCastling{ isCastling },
+        isEnPassant{ false } {}
+
+    inline Move(Index origin, Index destination, bool isCastling, bool isEnPassant) :
+        origin{ origin }, destination{ destination },
+        promotion{ PieceType::PAWN }, isCastling{ isCastling },
+        isEnPassant{ isEnPassant } {}
 
     inline std::string asString(void) const
     {

+ 2 - 2
src/BitOperations.h

@@ -44,7 +44,7 @@ namespace chessy
     inline int trailingZeroes(U64 x) {
 #if __GNUC__ > 4 && 0
         return __builtin_ctzll(x)
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && defined(_M_X64)
         unsigned long out;
         if (_BitScanForward64(&out, x))
             return out;
@@ -87,7 +87,7 @@ namespace chessy
         x = (x & 0x00FF00FF00FF00FF) + ((x & 0xFF00FF00FF00FF00) >> 8);
         x = (x & 0x0000FFFF0000FFFF) + ((x & 0xFFFF0000FFFF0000) >> 16);
         x = (x & 0x00000000FFFFFFFF) + ((x & 0xFFFFFFFF00000000) >> 32);
-        return x;
+        return int(x);
 #endif
     }
 }

+ 4 - 4
src/Board.cpp

@@ -266,20 +266,20 @@ bool Board::isCheck(void) const
     if (side == WHITE_SIDE) {
         if (kingIndex.getRow() < 6) {
             if (kingIndex.getColumn() > 0)
-                if (getKing<side>().neOne() & getPawns<enemy>())
+                if (getKing<side>().nwOne() & getPawns<enemy>())
                     return true;
             if (kingIndex.getColumn() < 7)
-                if (getKing<side>().nwOne() & getPawns<enemy>())
+                if (getKing<side>().neOne() & getPawns<enemy>())
                     return true;
         }
     }
     else {
         if (kingIndex.getRow() > 1) {
             if (kingIndex.getColumn() > 0)
-                if (getKing<side>().seOne() & getPawns<enemy>())
+                if (getKing<side>().swOne() & getPawns<enemy>())
                     return true;
             if (kingIndex.getColumn() < 7)
-                if (getKing<side>().swOne() & getPawns<enemy>())
+                if (getKing<side>().seOne() & getPawns<enemy>())
                     return true;
         }
     }

+ 15 - 0
src/ChessGame.cpp

@@ -154,12 +154,23 @@ UndoInfo ChessGame::doMove(const MoveInfo& mi)
 {
     UndoInfo ui;
 
+    // adjust castling rights
     ui.castlingRights = castlingRights;
     if (mi.movedPiece == KING) {
         setCanCastleKingSide(turn, false);
         setCanCastleQueenSide(turn, false);
     }
 
+    // update possible en-passant moves
+    ui.enPassantBefore = enPassant;
+    if (mi.movedPiece == PAWN &&
+        std::abs(mi.move.destination.getRow() - mi.move.destination.getRow()) == 2) {
+        enPassant = mi.move.origin.getRow();
+    }
+    else {
+        enPassant = -1;
+    }
+
     ui.type = mi.movedPiece;
     Bitboard& b = board.getBitboards(turn)[ui.type];
     ui.before = b;
@@ -177,6 +188,9 @@ UndoInfo ChessGame::doMove(const MoveInfo& mi)
     }
 
     ui.captured = PieceType::EMPTY;
+    if (mi.move.isEnPassant)
+        target = Bitboard::fromIndex(Index{
+            turn == WHITE_SIDE ? 5 : 2, mi.move.destination.getColumn() });
     for (int i = 0; i < 6; i++) {
         Bitboard& e = board.getBitboards(otherSide(turn))[i];
         if (target & e) {
@@ -211,5 +225,6 @@ void ChessGame::undoMove(const UndoInfo& ui)
     moveCount--;
     reversibleHalfMoves = ui.reversibleHalfMoves;
     castlingRights = ui.castlingRights;
+    enPassant = ui.enPassantBefore;
 }
 

+ 3 - 0
src/ChessGame.h

@@ -45,6 +45,7 @@ struct chessy::UndoInfo
     PieceType type;
     PieceType captured;
     PieceType promotion;
+    Index enPassantBefore;
     uint8_t reversibleHalfMoves;
     uint8_t castlingRights;
 };
@@ -104,6 +105,8 @@ public:
             (1 << (side == BLACK_SIDE ? 3 : 1));
     }
 
+    inline int getCastlingRights(void) const { return castlingRights; }
+
     void move(Move move);
     inline Side getTurn(void) const { return turn; }
 

+ 15 - 8
src/Minimax.cpp

@@ -161,7 +161,7 @@ MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth,
 
 
 template<Side side>
-MoveValue chessy::evaluate(const ChessGame& game)
+MoveValue chessy::evaluatePositives(const ChessGame& game)
 {
     MoveValue piecePoints = 0;
     const Board& bd = game.getBoard();
@@ -177,11 +177,17 @@ MoveValue chessy::evaluate(const ChessGame& game)
     piecePoints += 5 * r.popcount();
     piecePoints += 9 * q.popcount();
 
-    //for (auto knight : PositionSet{ n })
-    //    piecePoints += KnightMoveGenerator{ knight, bd.get<side>() }.getBitboard().popcount() * 0.15;
+    for (auto knight : PositionSet{ n })
+        piecePoints += KnightMoveGenerator{ knight, bd.get<side>() }.getBitboard().popcount() * 0.05;
     for (auto bishop : PositionSet{ b })
-        piecePoints += PrimitiveBishopMoveGenerator{ bishop, bd.get<otherSide(side)>(), bd.get<side>() }.getBitboard().popcount() * 0.2;
+        piecePoints += PrimitiveBishopMoveGenerator{ bishop, bd.get<otherSide(side)>(), bd.get<side>() }.getBitboard().popcount() * 0.03;
+    for (auto rook : PositionSet{ r })
+        piecePoints += PrimitiveRookMoveGenerator{ rook, bd.get<otherSide(side)>(), bd.get<side>() }.getBitboard().popcount() * 0.03;
+    for (auto queen : PositionSet{ q })
+        piecePoints += PrimitiveQueenMoveGenerator{ queen, bd.get<otherSide(side)>(), bd.get<side>() }.getBitboard().popcount() * 0.02;
 
+    return piecePoints;
+    /*
     constexpr Side other = otherSide(side);
     p = bd.getPawns<other>();
     n = bd.getKnights<other>();
@@ -199,17 +205,18 @@ MoveValue chessy::evaluate(const ChessGame& game)
     //    piecePoints -= KnightMoveGenerator{ knight, bd.get<otherSide(side)>() }.getBitboard().popcount() * 0.2;
     for (auto bishop : PositionSet{ b })
         piecePoints -= PrimitiveBishopMoveGenerator{ bishop, bd.get<side>(), bd.get<otherSide(side)>() }.getBitboard().popcount() * 0.2;
-
-    return piecePoints;
+        */
 }
 
 
 MoveValue chessy::evaluate(Side side, const ChessGame& game)
 {
     if (side == WHITE_SIDE)
-        return evaluate<WHITE_SIDE>(game);
+        return evaluatePositives<WHITE_SIDE>(game) -
+            evaluatePositives<BLACK_SIDE>(game);
     else
-        return evaluate<BLACK_SIDE>(game);
+        return evaluatePositives<BLACK_SIDE>(game) -
+            evaluatePositives<WHITE_SIDE>(game);
 }
 
 

+ 2 - 1
src/Minimax.h

@@ -28,7 +28,8 @@ namespace chessy
             MoveValue alpha, MoveValue beta);
 
     template<Side side>
-    MoveValue evaluate(const ChessGame& game);
+    MoveValue evaluatePositives(const ChessGame& game);
+
     MoveValue evaluate(Side side, const ChessGame& game);
 }
 

+ 8 - 4
src/MoveGeneration.cpp

@@ -54,7 +54,7 @@ bool PromotionGenerator<side>::MoveIterator::valid(void) const
     if (direction == 0)
         return !(Bitboard::fromIndex(*pawns +
                 (side == WHITE_SIDE ? 8 : -8)) &
-                chessGame.getBoard().get<otherSide(side)>());
+                chessGame.getBoard().getOccupied());
     else
         return (Bitboard::fromIndex(*pawns +
                 (side == WHITE_SIDE ? 8 : -8) + direction) &
@@ -387,7 +387,11 @@ template<Side side>
 void chessy::generateEnPassant(const ChessGame& cg, std::vector<Move>& moves)
 {
     if (cg.getEnPassantIndex() != -1) {
-        //Bitboard mask = side == WHITE_SIDE ? 0x000000FF00000000;
+        Bitboard mask = side == WHITE_SIDE ? 0x000000FF00000000 : 0x00000000FF000000;
+        Bitboard pawns = cg.getBoard().getPawns<side>();
+        for (auto pawn : PositionSet{ pawns & mask })
+            moves.emplace_back(pawn, Index{ side == WHITE_SIDE ? 5 : 2,
+                cg.getEnPassantIndex() }, false, true);
     }
 }
 
@@ -417,9 +421,9 @@ void chessy::orderMoves(const ChessGame& cg, std::vector<Move>& moves)
     auto b = moves.end() - 1;
     Bitboard enemies = cg.getBoard().get<otherSide(side)>();
     while(a < b) {
-        while (a < b && (Bitboard::fromIndex(a->destination) & enemies))
+        while (a < b && (Bitboard::fromIndex(a->destination) & enemies || a->isEnPassant))
             ++a;
-        while (!(Bitboard::fromIndex(b->destination) & enemies) && a < b)
+        while (!(Bitboard::fromIndex(b->destination) & enemies) && !b->isEnPassant && a < b)
             --b;
         if (a < b)
             std::iter_swap(a, b);