소스 검색

improving move generation

nicolaswinkler 7 년 전
부모
커밋
55cf085f88
7개의 변경된 파일126개의 추가작업 그리고 48개의 파일을 삭제
  1. 3 0
      src/BitBoard.h
  2. 6 6
      src/Board.h
  3. 39 12
      src/Minimax.cpp
  4. 5 3
      src/Minimax.h
  5. 46 15
      src/MoveGeneration.cpp
  6. 19 10
      src/MoveGeneration.h
  7. 8 2
      src/UciParser.cpp

+ 3 - 0
src/BitBoard.h

@@ -220,6 +220,9 @@ struct chessy::Bitboard
     inline Bitboard mirror(void) const                      { return byteswap(bits); }
     inline Index    getLeastSignificantBit (void) const     { return trailingZeroes(bits); }
     inline int      popcount    (void) const                { return chessy::popcount(bits); }
+
+    static const uint64_t aFile = 0x8080808080808080ULL;
+    static const uint64_t hFile = 0x0101010101010101ULL;
 };
 
 

+ 6 - 6
src/Board.h

@@ -84,12 +84,12 @@ public:
     template<Side side>
     inline Bitboard get            (void) const
     {
-        return  getBitboards<side>()[0] |
-                getBitboards<side>()[1] |
-                getBitboards<side>()[2] |
-                getBitboards<side>()[3] |
-                getBitboards<side>()[4] |
-                getBitboards<side>()[5];
+        return  getBitboards<side>()[PAWN] |
+                getBitboards<side>()[KNIGHT] |
+                getBitboards<side>()[BISHOP] |
+                getBitboards<side>()[ROOK] |
+                getBitboards<side>()[QUEEN] |
+                getBitboards<side>()[KING];
     }
 
     /*!

+ 39 - 12
src/Minimax.cpp

@@ -63,31 +63,39 @@ size_t chessy::perft(std::ostream& out, ChessGame& chessGame, int depth)
     return result;
 }
 
+#include <iostream>
+using namespace std;
 
-Move chessy::miniMax(ChessGame& cg, int depth)
+std::pair<Move, MoveValue> chessy::miniMax(ChessGame& cg, int depth)
 {
     std::vector<Move> moves;
+    moves.reserve(200);
     if (cg.getTurn() == WHITE_SIDE)
         generateAllMoves<WHITE_SIDE>(cg, moves);
     else
         generateAllMoves<BLACK_SIDE>(cg, moves);
-    Move bestMove;
-    MoveValue best = std::numeric_limits<MoveValue>::min();
+    Move bestMove{ 0, 0 };
+    //MoveValue best = -1e+30;
+    MoveValue alpha = -1e+30;
+    MoveValue beta = 1e+30;
     for (Move move : moves) {
         MoveInfo mi{ move, cg };
         UndoInfo ui = cg.doMove(mi);
-        MoveValue val = negamaxImplementation(cg, depth - 1);
+        MoveValue val = -negamaxImplementation(cg,  depth - 1, -beta, -alpha);
+        //cout << move.asString() << ": " << val << ", " << best << ((val > best) ? " good" : " bad") << endl;
+        //MoveValue val = 0.0;
         cg.undoMove(ui);
-        if(val < best) {
-            best = val;
+        if(val > alpha) {
+            alpha = val;
             bestMove = move;
         }
     }
-    return bestMove; //negamaxImplementation(chessGame, 5);
+    return { bestMove, alpha }; //negamaxImplementation(chessGame, 5);
 }
 
 
-MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth)
+MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth,
+        chessy::MoveValue alpha, chessy::MoveValue beta)
 {
     if (depth <= 0) {
         if (cg.getTurn() == WHITE_SIDE)
@@ -102,21 +110,35 @@ MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth)
     else
         generateAllMoves<BLACK_SIDE>(cg, moves);
 
+    const Board& b = cg.getBoard();
     for (Move move : moves) {
         MoveInfo mi{ move, cg };
-        negamaxImplementation(cg, depth - 1);
         UndoInfo ui = cg.doMove(mi);
+        /*Index king = b.getKing<side>().getLeastSignificantBit();
+        if((KnightMoveGenerator{ king }.getBitboard() &
+                b.getKnights<otherSide(side)>()) ||
+                (PrimitiveBishopMoveGenerator{ king, b.get<otherSide(side)>(),
+                b.get<side>() }.getBitboard() & (b.getBishops<otherSide(side)>() |
+                    b.getQueens<otherSide(side)>())) ||
+                PrimitiveRookMoveGenerator{ king, b.get<otherSide(side)>(),
+                b.get<side>() }.getBitboard() & (b.getRooks<otherSide(side)>() |
+                    b.getQueens<otherSide(side)>()))*/
+        MoveValue val = -negamaxImplementation(cg, depth - 1, -beta, -alpha);
         cg.undoMove(ui);
+        if(val >= beta)
+            return beta;
+        if(val > alpha)
+            alpha = val;
     }
 
-    return 0.0;
+    return alpha;
 }
 
 
 template<Side side>
 MoveValue chessy::evaluate(const ChessGame& game)
 {
-    int piecePoints = 0;
+    MoveValue piecePoints = 0;
     const Board& bd = game.getBoard();
     Bitboard p = bd.getPawns<side>();
     Bitboard n = bd.getKnights<side>();
@@ -124,6 +146,8 @@ MoveValue chessy::evaluate(const ChessGame& game)
     Bitboard r = bd.getRooks<side>();
     Bitboard q = bd.getQueens<side>();
     Bitboard k = bd.getKing<side>();
+    for (auto pawn : PositionSet{ p })
+        piecePoints += 0.5 / 8.0 * pawn.getRow() + 1.0;
     piecePoints += 1 * p.popcount();
     piecePoints += 3 * n.popcount();
     piecePoints += 3 * b.popcount();
@@ -132,13 +156,15 @@ MoveValue chessy::evaluate(const ChessGame& game)
     if (k == Bitboard(0ULL))
         piecePoints -= 100000;
 
-    const Side other = otherSide(side);
+    constexpr Side other = otherSide(side);
     p = bd.getPawns<other>();
     n = bd.getKnights<other>();
     b = bd.getBishops<other>();
     r = bd.getRooks<other>();
     q = bd.getQueens<other>();
     k = bd.getKing<other>();
+    for (auto pawn : PositionSet{ p })
+        piecePoints += 0.5 / 8.0 * (7 - pawn.getRow()) + 1.0;
     piecePoints -= 1 * p.popcount();
     piecePoints -= 3 * n.popcount();
     piecePoints -= 3 * b.popcount();
@@ -149,6 +175,7 @@ MoveValue chessy::evaluate(const ChessGame& game)
 
     return piecePoints;
 }
+
 /*
 template MiniMax::BestMove MiniMax::minimax<WHITE_SIDE>(int);
 template MiniMax::BestMove MiniMax::minimax<BLACK_SIDE>(int);

+ 5 - 3
src/Minimax.h

@@ -2,6 +2,7 @@
 #define CHESSY_MINIMAX_H
 
 #include <iostream>
+#include <utility>
 
 #include "MoveGeneration.h"
 
@@ -21,12 +22,13 @@ namespace chessy
      */
     size_t perft(std::ostream& out, ChessGame& chessGame, int depth);
 
-    Move miniMax(ChessGame& chessGame, int depth);
+    std::pair<Move, MoveValue> miniMax(ChessGame& chessGame, int depth);
 
-    MoveValue negamaxImplementation(ChessGame& cg, int depth);
+    MoveValue negamaxImplementation(ChessGame& cg, int depth,
+            MoveValue alpha, MoveValue beta);
 
     template<Side side>
-    MoveValue chessy::evaluate(const ChessGame& game);
+    MoveValue evaluate(const ChessGame& game);
 }
 
 

+ 46 - 15
src/MoveGeneration.cpp

@@ -29,25 +29,55 @@ typename PawnPushGenerator<side>::MoveIterator PawnPushGenerator<side>::end(void
 
 
 template<Side side>
+void PromotionGenerator<side>::MoveIterator::next(void)
+{
+    if (direction != 1) {
+        direction++;
+    }
+    else if (promotionType != QUEEN) {
+        promotionType = static_cast<PieceType>(promotionType + 1);
+        direction = -1;
+    }
+    else {
+        promotionType = PieceType::KNIGHT;
+        direction = -1;
+        ++pawns;
+    }
+}
+
+
+template<Side side>
+bool PromotionGenerator<side>::MoveIterator::valid(void) const
+{
+    if (pawns.bitboard == Bitboard{ 0 })
+        return true;
+    if (direction == 0)
+        return !(Bitboard::fromIndex(*pawns +
+                (side == WHITE_SIDE ? 8 : -8)) &
+                chessGame.getBoard().get<otherSide(side)>());
+    else
+        return (Bitboard::fromIndex(*pawns +
+                (side == WHITE_SIDE ? 8 : -8) + direction) &
+                Bitboard(~(Bitboard::aFile | Bitboard::hFile))  &
+                chessGame.getBoard().get<otherSide(side)>());
+}
+
+
+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>();
+    Bitboard pawns = board.getPawns<side>();
+    pawns &= Bitboard(0xFF000000000000FFULL);
 
-    // can't promote into occupied squares
-    movedPieces &= ~board.getOccupied();
-    // use different move generator for promotions
-    movedPieces &= Bitboard(0xFF000000000000FFULL);
-
-    return MoveIterator{ movedPieces, PieceType::KNIGHT };
+    return MoveIterator{ chessGame, pawns, PieceType::KNIGHT, -1 };
 }
 
 
 template<Side side>
 typename PromotionGenerator<side>::MoveIterator PromotionGenerator<side>::end(void) const
 {
-    return MoveIterator{ 0 };
+    return MoveIterator{ chessGame, 0, PieceType::PAWN, 0 };
 }
 
 
@@ -99,7 +129,7 @@ typename PawnCaptureGenerator<side, leftright>::MoveIterator
         movedPieces.moveWestOne();
     
     movedPieces &= (side == BLACK_SIDE ? board.getWhites() : board.getBlacks());
-    //movedPieces &= Bitboard(~0xFF000000000000FFULL);
+    movedPieces &= Bitboard(~0xFF000000000000FFULL);
 
     return MoveIterator{ movedPieces };
 }
@@ -281,7 +311,7 @@ void chessy::generateQueenMoves(const ChessGame& cg, std::vector<Move>& moves)
 {
     const Board& b = cg.getBoard();
     generateMoves<side, PrimitiveQueenMoveGenerator>(
-        b.getKnights<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
+        b.getQueens<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
     );
 }
 
@@ -291,7 +321,7 @@ void chessy::generateRookMoves(const ChessGame& cg, std::vector<Move>& moves)
 {
     const Board& b = cg.getBoard();
     generateMoves<side, PrimitiveRookMoveGenerator>(
-        b.getKnights<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
+        b.getRooks<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
     );
 }
 
@@ -301,7 +331,7 @@ void chessy::generateBishopMoves(const ChessGame& cg, std::vector<Move>& moves)
 {
     const Board& b = cg.getBoard();
     generateMoves<side,PrimitiveBishopMoveGenerator>(
-        b.getKnights<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
+        b.getBishops<side>(), b.get<otherSide(side)>(), b.get<side>(), moves
     );
 }
 
@@ -361,10 +391,11 @@ void chessy::generateAllMoves(const ChessGame& cg, std::vector<Move>& moves)
     generateCastling<side>(cg, moves);
 }
 
+
 // explicit instatiations
 namespace chessy
 {
-    /*template class PawnPushGenerator<WHITE_SIDE>;
+    template class PawnPushGenerator<WHITE_SIDE>;
     template class PawnPushGenerator<BLACK_SIDE>;
 
     template class PromotionGenerator<WHITE_SIDE>;
@@ -379,7 +410,7 @@ namespace chessy
     template class PawnCaptureGenerator<BLACK_SIDE, RIGHT>;
 
     template class CastlingGenerator<WHITE_SIDE>;
-    template class CastlingGenerator<BLACK_SIDE>;*/
+    template class CastlingGenerator<BLACK_SIDE>;
 
     template void generateAllMoves<WHITE_SIDE>(const ChessGame&, std::vector<Move>&);
     template void generateAllMoves<BLACK_SIDE>(const ChessGame&, std::vector<Move>&);

+ 19 - 10
src/MoveGeneration.h

@@ -65,7 +65,8 @@ public:
 
     inline PositionSet(Bitboard b) : bitboard{ b } {}
 
-    inline void setBitboard(Bitboard b) { bitboard = b; }
+    inline void     setBitboard(Bitboard b) { bitboard = b; }
+    inline Bitboard getBitboard(void) const { return bitboard; }
 
     struct PositionSetIterator
     {
@@ -139,25 +140,33 @@ class chessy::PromotionGenerator
 
     struct MoveIterator
     {
-        PositionSet::PositionSetIterator promotions;
+        const ChessGame& chessGame;
+        PositionSet::PositionSetIterator pawns;
         PieceType promotionType;
+        char direction;
+
         inline Move operator *(void) const
         {
-            Index pp = *promotions;
-            return Move{ int8_t(pp + (side != WHITE_SIDE ? 8 : -8)), pp, promotionType };
+            Index pp = *pawns;
+            return Move{ pp, int8_t(pp + (side == WHITE_SIDE ? 8 : -8) +
+                    direction), promotionType };
         }
 
+    private:
+        void next(void);
+        bool valid(void) const;
+    public:
+
         inline void operator ++(void)
         {
-            if (promotionType == PieceType::QUEEN)
-                ++promotions;
-            else
-                promotionType = static_cast<PieceType>(promotionType + 1);
+            do {
+                next();
+            } while(!valid());
         }
 
         inline bool operator !=(const MoveIterator& psi) const
         {
-            return promotions != psi.promotions;
+            return pawns != psi.pawns;
         }
     };
 
@@ -235,7 +244,7 @@ public:
 
 
 /*!
- * extends \link PositionSet so that all possible destinations for
+ * extends \link PositionSet \endlink so that all possible destinations for
  * a knight can be iterated over.
  */
 class chessy::KnightMoveGenerator :

+ 8 - 2
src/UciParser.cpp

@@ -3,6 +3,7 @@
 #include <thread>
 
 #include "ChessGame.h"
+#include "EngineInfo.h"
 
 using namespace std;
 
@@ -85,7 +86,7 @@ void UciParser::sendCommand(const std::string& command,
 
 void UciParser::uci(const std::vector<std::string>& args)
 {
-    sendCommand("id", { "name", "Chessy", "1.0" });
+    sendCommand("id", { "name", "Chessy", chessy::info::versionString });
     sendCommand("id", { "author", "N. Winkler" });
     sendCommand("uciok");
 }
@@ -153,7 +154,12 @@ void UciParser::go(const vector<string>& args)
 {
     stop({});
 
-    chessy::Move bestMove = chessy::miniMax(this->cg, 4);
+    chessy::Move bestMove;
+    chessy::MoveValue value;
+    tie(bestMove, value) = chessy::miniMax(this->cg, 5);
+
+    sendCommand("info", { "depth", "4", "score", "cp", to_string(value) });
+
     sendCommand("bestmove", { bestMove.asString() });
     /*fst = make_unique<FixedSearchTimer>(cg, *this);