nicolaswinkler 7 anni fa
parent
commit
646ef77831
9 ha cambiato i file con 175 aggiunte e 132 eliminazioni
  1. 25 15
      src/BitBoard.h
  2. 30 2
      src/ChessGame.h
  3. 25 0
      src/Minimax.cpp
  4. 13 1
      src/Minimax.h
  5. 2 2
      src/MoveGeneration.cpp
  6. 70 105
      src/Search.h
  7. 2 3
      src/UciParser.cpp
  8. 7 3
      src/main.cpp
  9. 1 1
      src/makefile

+ 25 - 15
src/BitBoard.h

@@ -149,15 +149,15 @@ struct chessy::Bitboard
 
     inline void     setBit      (Index i)     { bits |= U64(1) << i.index; }
     inline void     unsetBit    (Index i)     { bits |= ~(U64(1) << i.index); }
+    inline void     toggleBit   (Index i)     { bits ^= U64(1) << i.index; }
 
     inline void     setBit      (int row, int column)
         { setBit(row * 8 + column); }
     inline void     unsetBit    (int row, int column)
         { unsetBit(row * 8 + column); }
 
-
-    static const    U64 aColumn             = 0x0101010101010101ULL;
-    static const    U64 hColumn             = 0x8080808080808080ULL;
+    static const    U64 hColumn             = 0x0101010101010101ULL;
+    static const    U64 aColumn             = 0x8080808080808080ULL;
     inline void     moveNorth   (int dist)  { bits <<= (8 * dist); }
     inline Bitboard north       (int dist)  { return bits << (8 * dist); }
     inline void     moveSouth   (int dist)  { bits >>= (8 * dist); }
@@ -166,18 +166,28 @@ struct chessy::Bitboard
     inline Bitboard northOne    (void)      { return bits << 8; }
     inline void     moveSouthOne(void)      { bits >>= 8; }
     inline Bitboard southOne    (void)      { return bits >> 8; }
-    inline void     moveEastOne (void)      { bits = (bits & ~aColumn) >> 1; }
-    inline Bitboard eastOne     (void)      { return (bits & ~aColumn) >> 1; }
-    inline void     moveWestOne (void)      { bits = (bits & ~hColumn) << 1; }
-    inline Bitboard westOne     (void)      { return (bits & ~hColumn) << 1; }
-    inline void     moveNWOne   (void)      { bits = (bits << 7) & ~hColumn; }
-    inline Bitboard nwOne       (void)      { return (bits << 7) & ~hColumn; }
-    inline void     moveNEOne   (void)      { bits = (bits << 9) & ~aColumn; }
-    inline Bitboard neOne       (void)      { return (bits << 9) & ~aColumn; }
-    inline void     moveSWOne   (void)      { bits = (bits >> 9) & ~hColumn; }
-    inline Bitboard swOne       (void)      { return (bits >> 9) & ~hColumn; }
-    inline void     moveSEOne   (void)      { bits = (bits >> 7) & ~aColumn; }
-    inline Bitboard seOne       (void)      { return (bits >> 7) & ~aColumn; }
+    inline void     moveEastOne (void)      { bits = (bits & ~hColumn) >> 1; }
+    inline Bitboard eastOne     (void)      { return (bits & ~hColumn) >> 1; }
+    inline void     moveWestOne (void)      { bits = (bits & ~aColumn) << 1; }
+    inline Bitboard westOne     (void)      { return (bits & ~aColumn) << 1; }
+    inline void     moveNWOne   (void)      { bits = (bits << 7) & ~aColumn; }
+    inline Bitboard nwOne       (void)      { return (bits << 7) & ~aColumn; }
+    inline void     moveNEOne   (void)      { bits = (bits << 9) & ~hColumn; }
+    inline Bitboard neOne       (void)      { return (bits << 9) & ~hColumn; }
+    inline void     moveSWOne   (void)      { bits = (bits >> 9) & ~aColumn; }
+    inline Bitboard swOne       (void)      { return (bits >> 9) & ~aColumn; }
+    inline void     moveSEOne   (void)      { bits = (bits >> 7) & ~hColumn; }
+    inline Bitboard seOne       (void)      { return (bits >> 7) & ~hColumn; }
+
+    inline static Bitboard getColumn(int index)
+    {
+        return hColumn << index;
+    }
+    
+    inline static Bitboard getRow(int index)
+    {
+        return 0xFFULL << (index * 8);
+    }
 
     template<Side side>
     inline void     pushOne(void)

+ 30 - 2
src/ChessGame.h

@@ -8,10 +8,33 @@
 
 namespace chessy
 {
+    struct MoveInfo;
+
+    struct UndoInfo;
     class ChessGame;
 }
 
 
+/*!
+ * This structure holds additional information about a move.
+ */
+struct chessy::MoveInfo
+{
+    //! the move itself
+    Move move;
+
+    //! the type of the piece that was moved
+    PieceType movedPiece;
+
+    //! if the move is an en-passant move, this field holds the square of
+    //! the pawn, that was captured. Otherwise this index should be zero.
+    Index enPassantTarget;
+
+    inline MoveInfo(void) :
+        enPassantTarget{ 0 } {}
+};
+
+
 class chessy::ChessGame
 {
     Board board;
@@ -38,8 +61,8 @@ public:
     bool isValidMove(const Move& move) const;
     std::vector<Move> getValidMoves(void) const;
 
-    inline const Board& getBoard(void) const { return board; }
-    inline       Board& getBoard(void)       { return board; }
+    inline const Board& getBoard(void) const    { return board; }
+    inline       Board& getBoard(void)          { return board; }
 
     inline bool getCanCastleKingSide(Side side) const
     {
@@ -56,6 +79,11 @@ public:
 
     void loadFromFen(const std::string& fenString);
     std::string generateFen(void) const;
+
+    inline Index getEnPassantIndex(void) const  { return enPassant; }
+
+    UndoInfo doMove(const MoveInfo& mi);
+    void undoMove(const UndoInfo ui);
 };
 
 #endif // CHESSY_CHESSGAME_H

+ 25 - 0
src/Minimax.cpp

@@ -1,10 +1,35 @@
 #include "Minimax.h"
 #include "ChessGame.h"
+#include "Search.h"
 
+#include <functional>
 #include <limits>
 
 using namespace chessy;
 
+
+size_t Perft::search(void)
+{
+    size_t result = 0;
+    auto searcher = [&result] (const MoveInfo& mi, ChessGame& cg, int depth) {
+        if (depth > 0) {
+            cg.doMove(mi);
+            Perft p{ depth - 1, cg };
+            result += p.search();
+        }
+        else {
+            result++;
+        }
+    };
+
+    Search<decltype(searcher)> search (std::move(searcher), chessGame);
+
+    search.iterateAll<WHITE_SIDE>(chessGame, depth);
+
+    return result;
+}
+
+
 template MiniMax::BestMove MiniMax::minimax<WHITE_SIDE>(int);
 template MiniMax::BestMove MiniMax::minimax<BLACK_SIDE>(int);
 

+ 13 - 1
src/Minimax.h

@@ -2,14 +2,26 @@
 #define CHESSY_MINIMAX_H
 
 #include "MoveGeneration.h"
-//#include "Search.h"
 
 namespace chessy
 {
+    class Perft;
     class MiniMax;
 }
 
 
+class chessy::Perft
+{
+    int depth;
+    ChessGame& chessGame;
+public:
+    inline Perft(int depth, ChessGame& cg) :
+        depth{ depth }, chessGame{ cg } {}
+
+    size_t search(void);
+};
+
+
 class chessy::MiniMax
 {
     ChessGame& game;

+ 2 - 2
src/MoveGeneration.cpp

@@ -135,8 +135,8 @@ Bitboard KnightMoveGenerator::generateFromIndex(Index i) {
 std::array<Bitboard, 64> KnightMoveGenerator::generateKnightMoves(void)
 {
     std::array<Bitboard, 64> moves{};
-    for (int8_t i = 0; i < moves.size(); i++) {
-        moves[i] = generateFromIndex(Index{ i });
+    for (size_t i = 0; i < moves.size(); i++) {
+        moves[i] = generateFromIndex(Index{ (int8_t) i });
     }
     return moves;
 }

+ 70 - 105
src/Search.h

@@ -15,23 +15,36 @@ namespace chessy
 }
 
 
+/*!
+ * This structure holds additional information about a move.
+ */
 struct chessy::MoveInfo
 {
+    //! the move itself
     Move move;
+
+    //! the type of the piece that was moved
     PieceType movedPiece;
+
+    //! if the move is an en-passant move, this field holds the square of
+    //! the pawn, that was captured. Otherwise this index should be zero.
+    Index enPassantTarget;
+
+    inline MoveInfo(void) :
+        enPassantTarget{ 0 } {}
 };
 
 
 template<typename T>
 class chessy::Search
 {
-    T& handler;
+    T handler;
     ChessGame& game;
     Board& board;
     Bitboard whites;
     Bitboard blacks;
 public:
-    inline Search(T& handler, ChessGame& game) :
+    inline Search(T&& handler, ChessGame& game) :
         handler{ handler }, game{ game }, board{ game.getBoard() },
         whites{ board.getWhites() }, blacks{ board.getBlacks() } {}
 
@@ -71,6 +84,9 @@ public:
 
     template<Side side, typename... Args>
     inline void iteratePromotions(Args&&... args);
+
+    template<Side side, typename... Args>
+    inline void iterateEnPassant(Args&&... args);
 private:
 
     template<Side side>
@@ -115,68 +131,6 @@ inline void chessy::Search<T>::iterateAll(Args&&... args)
     iterateQueens<side, Args...>(std::forward<Args>(args)...);
     iterateKing<side, Args...>(std::forward<Args>(args)...);
     iterateCastling<side, Args...>(std::forward<Args>(args)...);
-
-    /*
-
-
-    Bitboard& rs = board.getRooks<side>();
-    PositionSet rooks { rs }; 
-    for (auto rook : rooks) {
-        for (auto pos : PrimitiveRookMoveGenerator{ rook, enemies, friends }) {
-            Move move = { rook, pos };
-            board.removeAt(move.destination);
-            rs.applyMove(move);
-            //BestMove m = minimax<otherSide(side)>(depth - 1);
-            m.move = move;
-            bestMove.overwriteIfBetter(m);
-            board = temp;
-        }
-    }
-
-    Bitboard& qs = board.getQueens<side>();
-    PositionSet queens { qs };
-    for (auto queen : queens) {
-        for (auto pos : PrimitiveQueenMoveGenerator{ queen, enemies, friends }) {
-            Move move = { queen, pos };
-            board.removeAt(move.destination);
-            qs.applyMove(move);
-            //BestMove m = minimax<otherSide(side)>(depth - 1);
-            m.move = move;
-            bestMove.overwriteIfBetter(m);
-            board = temp;
-        }
-    }
-
-    Bitboard& king = board.getKing<side>();
-    Index kingIndex = king.getLeastSignificantBit();
-    for (auto pos : KingMoveGenerator{ king, friends }) {
-        Move move = { kingIndex, pos };
-        board.removeAt(pos);
-        king.applyMove(move);
-        BestMove m = minimax<otherSide(side)>(depth - 1);
-        m.move = move;
-        //if (depth >= 3)
-        //    std::cout << m.move.asString() << " " << bestMove.value << " -> " << m.value << std::endl;
-        bestMove.overwriteIfBetter(m);
-        board = temp;
-    }
-
-    if (side == WHITE_SIDE) {
-        if (game.getCanCastleKingSide(side)) {
-            if((friends.bits & 0x6) == 0) {
-                Move kingMove = {3, 1};
-                Move rookMove = {0, 2};
-                king.applyMove(kingMove);
-                rs.applyMove(rookMove);
-                board = temp;
-            }
-        }
-    }
-
-    float v = evaluate<side>();
-    bestMove.value *= 0.9f;
-    bestMove.value += v * 0.2f;
-    return -bestMove;*/
 }
 
 
@@ -268,18 +222,31 @@ template<typename T>
 template<chessy::Side side, typename... Args>
 inline void chessy::Search<T>::iterateCastling(Args&&... args)
 {
+    Bitboard king = board.getKing<side>();
+    Bitboard allOccupied = whites | blacks;
     MoveInfo moveInfo;
     moveInfo.movedPiece = PieceType::KING;
     if (game.getCanCastleKingSide(side)) {
-        Bitboard king = board.getKing<side>();
         Bitboard target = king.bits >> 2; // move king to the right
-        Bitboard rook = king.bits >> 3;
+        Bitboard rook = king.bits << 3;
         Bitboard rookTarget = king.bits >> 1;
-        if (!(target | friends<WHITE_SIDE>() | friends<BLACK_SIDE>()) &&
-            !(rookTarget | friends<WHITE_SIDE>() | friends<BLACK_SIDE>())) {
-
+        if (!(target & allOccupied) &&
+            !(rookTarget & allOccupied)) {
+            moveInfo.move = Move{ king.getLeastSignificantBit(),
+                target.getLeastSignificantBit(), true };
+            handler(moveInfo, std::forward<Args>(args)...);
+        }
+    }
+    if (game.getCanCastleQueenSide(side)) {
+        Bitboard target = king.bits << 2; // move king to the left
+        Bitboard rook = king.bits >> 3;
+        Bitboard rookTarget = king.bits << 1;
+        if (!(target & allOccupied) &&
+            !(rookTarget & allOccupied)) {
+            moveInfo.move = Move{ king.getLeastSignificantBit(),
+                target.getLeastSignificantBit(), true };
+            handler(moveInfo, std::forward<Args>(args)...);
         }
-        moveInfo.move = Move{ king, target, true };
     }
 }
 
@@ -347,45 +314,43 @@ inline void chessy::Search<T>::iteratePromotions(Args&&... args)
 
 template<typename T>
 template<chessy::Side side, typename... Args>
-inline void chessy::Search<T>::iteratePawns(Args&&... args)
+inline void chessy::Search<T>::iterateEnPassant(Args&&... args)
 {
-    iterateSinglePawnPushes<side, Args...>(std::forward(args)...);
-    iterateDoublePawnPushes<side, Args...>(std::forward(args)...);
-    iteratePawnCaptures<side, Args...>(std::forward(args)...);
-    iteratePromotions<side, Args...>(std::forward(args)...);
-    /*
-    PawnCaptureGenerator<side, LEFT> pl{ game };
-    for (Move capture : pl) {
-        Bitboard& pawns = board.getPawns<side>();
-        board.removeAt(capture.destination);
-        pawns.applyMove(capture);
-        BestMove m = minimax<otherSide(side)>(depth - 1);
-        m.move = capture;
-        bestMove.overwriteIfBetter(m);
-        board = temp;
+    MoveInfo moveInfo;
+    moveInfo.movedPiece = PieceType::PAWN;
+    Index enPassant = game.getEnPassantIndex();
+    if (enPassant.index != -1) {
+        Bitboard pawns = board.getPawns<side>();
+        int rowIndex = side == WHITE_SIDE ? 4 : 3;
+        int targetRowIndex = side == WHITE_SIDE ? 5 : 2;
+        int columnIndex = enPassant.index;
+        Bitboard pawnColumns = 0;
+        if (columnIndex > 0) 
+            pawnColumns |= Bitboard::getColumn(columnIndex - 1);
+        if (columnIndex < 7) 
+            pawnColumns |= Bitboard::getColumn(columnIndex + 1);
+        pawns &= rowIndex & pawnColumns;
+
+        moveInfo.enPassantTarget = Index{ enPassant.index, rowIndex };
+        Index target{ enPassant.index, targetRowIndex };
+        PositionSet sources = pawns;
+        for (auto source : sources) {
+            moveInfo.move = Move{ source, target };
+            handler(moveInfo, std::forward<Args>(args)...);
+        }
     }
+}
 
-    PawnCaptureGenerator<side, RIGHT> pr{ game };
-    for (Move capture : pr) {
-        Bitboard& pawns = board.getPawns<side>();
-        board.removeAt(capture.destination);
-        pawns.applyMove(capture);
-        BestMove m = minimax<otherSide(side)>(depth - 1);
-        m.move = capture;
-        bestMove.overwriteIfBetter(m);
-        board = temp;
-    }
 
-    PromotionGenerator<side> pg{ game };
-    for (Move promotion : pg) {
-        Bitboard& pawns = board.getPawns<side>();
-        board.removeAt(promotion.destination);
-        pawns.applyMove(promotion);
-        BestMove m = minimax<otherSide(side)>(depth - 1);
-        m.move = promotion;
-        bestMove.overwriteIfBetter(m);
-        board = temp;
-    }*/
+template<typename T>
+template<chessy::Side side, typename... Args>
+inline void chessy::Search<T>::iteratePawns(Args&&... args)
+{
+    iterateSinglePawnPushes<side, Args...>(std::forward<Args>(args)...);
+    iterateDoublePawnPushes<side, Args...>(std::forward<Args>(args)...);
+    iteratePawnCaptures<side, Args...>(std::forward<Args>(args)...);
+    iteratePromotions<side, Args...>(std::forward<Args>(args)...);
+    iterateEnPassant<side, Args...>(std::forward<Args>(args)...);
 }
 
 

+ 2 - 3
src/UciParser.cpp

@@ -99,7 +99,6 @@ void UciParser::debug(const vector<string>& args)
 void UciParser::isready(const vector<string>& args)
 {
     sendCommand("readyok");
-    int a = this->cg.getBoard().getWhitePawns().popcount();
 }
 
 
@@ -120,7 +119,7 @@ void UciParser::ucinewgame(const vector<string>& args)
 void UciParser::position(const vector<string>& args)
 {
     try {
-        int movesIndex = 0;
+        size_t movesIndex = 0;
         if (args.at(0) == "fen") {
             string fenString = args.at(1) + " " + args.at(2) + " " +
                 args.at(3) + " " + args.at(4) + " " + args.at(5) + " " +
@@ -133,7 +132,7 @@ void UciParser::position(const vector<string>& args)
             movesIndex = 1;
         }
         if (args.size() > movesIndex + 1 && args.at(movesIndex) == "moves") {
-            for (int i = movesIndex + 1; i < args.size(); i++) {
+            for (size_t i = movesIndex + 1; i < args.size(); i++) {
                 using chessy::Move;
                 Move move = Move{ args[i] };
                 cg.move(move);

+ 7 - 3
src/main.cpp

@@ -13,18 +13,22 @@ using namespace chessy;
  */
 auto main(int argc, char** argv) -> int
 {
-    ChessGame cg{ "8/1pP5/3Qp2p/2K1P1P1/1p1p4/4p3/k2P3P/4b1n1 w - - 0 1" };
+    ChessGame cg;
+    Perft p{ 1 , cg };
+    cout << p.search() << endl;
+    return 0;
+    /*ChessGame cg{ "8/1pP5/3Qp2p/2K1P1P1/1p1p4/4p3/k2P3P/4b1n1 w - - 0 1" };
     auto printer = [](const MoveInfo& mi) {
         cout << mi.move.asString() << endl;
     };
 
-    Search<decltype(printer)> search{ printer, cg };
+    Search<decltype(printer)> search{ std::move(printer), cg };
     search.iterateAll<WHITE_SIDE>();
     cout << endl << endl;
     search.iterateAll<BLACK_SIDE>();
     cin.get();
 
-    return 0;
+    return 0;*/
 
 
 

+ 1 - 1
src/makefile

@@ -1,7 +1,7 @@
 IDIR=       .
 CXX=        g++
 STRIP=      strip
-CXXFLAGS=   -std=c++14
+CXXFLAGS=   -std=c++14 -Wall
 LNFLAGS=    
 DEPS=       Bitfield.h
 ifeq ($(OS),Windows_NT)