Quellcode durchsuchen

better move undoing

Nicolas Winkler vor 7 Jahren
Ursprung
Commit
418a6bbdc4
6 geänderte Dateien mit 91 neuen und 32 gelöschten Zeilen
  1. 4 0
      src/Board.h
  2. 40 22
      src/ChessGame.cpp
  3. 25 6
      src/ChessGame.h
  4. 6 2
      src/Minimax.cpp
  5. 3 2
      src/UciParser.cpp
  6. 13 0
      src/UciParser.h

+ 4 - 0
src/Board.h

@@ -51,9 +51,13 @@ public:
     template<Side side>
     inline Bitboard* getBitboards  (void) { return side == WHITE_SIDE ? whites : blacks; }
 
+    inline Bitboard* getBitboards  (Side side) { return side == WHITE_SIDE ? whites : blacks; }
+
     template<Side side>
     inline const Bitboard* getBitboards(void) const { return side == WHITE_SIDE ? whites : blacks; }
 
+    inline const Bitboard* getBitboards(Side side) const { return side == WHITE_SIDE ? whites : blacks; }
+
 
     template<Side side>
     inline Bitboard& getPawns      (void) { return getBitboards<side>()[PAWN]; }

+ 40 - 22
src/ChessGame.cpp

@@ -42,7 +42,7 @@ void ChessGame::move(Move move)
     if (turn == BLACK_SIDE) {
         moveCount++;
     }
-    turn = turn == WHITE_SIDE ? BLACK_SIDE : WHITE_SIDE;
+    turn = otherSide(turn);
 }
 
 
@@ -73,25 +73,21 @@ void ChessGame::loadFromFen(const std::string& fenString)
     else if (turn == "b"s) this->turn = BLACK_SIDE;
     else throw runtime_error("invalid turn "s + turn);
 
-    canCastleQueenSide[WHITE_SIDE] = false;
-    canCastleKingSide[WHITE_SIDE] = false;
-    canCastleQueenSide[BLACK_SIDE] = false;
-    canCastleKingSide[BLACK_SIDE] = false;
-
+    castlingRights = 0;
     if (castling != "-")
         for (auto character : castling) {
             switch (character) {
                 case 'k':
-                    canCastleKingSide[WHITE_SIDE] = true;
+                    setCanCastleKingSide(WHITE_SIDE, true);
                     break;
                 case 'q':
-                    canCastleQueenSide[WHITE_SIDE] = true;
+                    setCanCastleQueenSide(WHITE_SIDE, true);
                     break;
                 case 'K':
-                    canCastleKingSide[BLACK_SIDE] = true;
+                    setCanCastleKingSide(BLACK_SIDE, true);
                     break;
                 case 'Q':
-                    canCastleQueenSide[BLACK_SIDE] = true;
+                    setCanCastleQueenSide(BLACK_SIDE, true);
                     break;
                 default:
                     throw runtime_error("invalid castling right: "s + character);
@@ -132,10 +128,10 @@ std::string ChessGame::generateFen(void) const
     string turn = this->turn == WHITE_SIDE ? "w"s : "b"s;
 
     string castlingRights =
-        (canCastleKingSide[BLACK_SIDE] ? "K"s : ""s) +
-        (canCastleQueenSide[BLACK_SIDE] ? "Q"s : ""s) +
-        (canCastleKingSide[WHITE_SIDE] ? "k"s : ""s) +
-        (canCastleQueenSide[WHITE_SIDE] ? "q"s : ""s);
+        (getCanCastleKingSide(BLACK_SIDE) ? "K"s : ""s) +
+        (getCanCastleQueenSide(BLACK_SIDE)? "Q"s : ""s) +
+        (getCanCastleKingSide(WHITE_SIDE) ? "k"s : ""s) +
+        (getCanCastleQueenSide(WHITE_SIDE) ? "q"s : ""s);
     if (castlingRights.empty())
         castlingRights = "-"s;
 
@@ -158,20 +154,38 @@ std::string ChessGame::generateFen(void) const
 UndoInfo ChessGame::doMove(const MoveInfo& mi)
 {
     UndoInfo ui;
-    ui.before = board;
 
+    ui.castlingRights = castlingRights;
     if (mi.movedPiece == KING) {
-        canCastleKingSide[turn] = false;
-        canCastleQueenSide[turn] = true;
+        setCanCastleKingSide(turn, false);
+        setCanCastleQueenSide(turn, false);
+    }
+
+    ui.type = mi.movedPiece;
+    Bitboard& b = board.getBitboards(turn)[ui.type];
+    ui.before = b;
+
+    Bitboard target = Bitboard::fromIndex(mi.move.destination);
+    b &= ~Bitboard::fromIndex(mi.move.origin);
+    b |= target;
+
+    ui.captured = PieceType::EMPTY;
+    for (int i = 0; i < 6; i++) {
+        Bitboard& e = board.getBitboards(otherSide(turn))[i];
+        if (target & e) {
+            ui.captured = static_cast<PieceType>(i);
+            ui.beforeCaptured = e;
+            e ^= target;
+            break;
+        }
     }
 
-    board.move(mi.move);
     turn = otherSide(turn);
     moveCount++;
+    ui.reversibleHalfMoves = reversibleHalfMoves;
     if(mi.movedPiece != PAWN &&
             board.getAtPosition(mi.move.destination) != EMPTY) {
         reversibleHalfMoves++;
-        ui.decrementReversibleHalfMoves = true;
     }
     return ui;
 }
@@ -179,9 +193,13 @@ UndoInfo ChessGame::doMove(const MoveInfo& mi)
 
 void ChessGame::undoMove(const UndoInfo& ui)
 {
-    board = ui.before;
     turn = otherSide(turn);
+
+    Bitboard& b = board.getBitboards(turn)[ui.type];
+    b = ui.before;
+    if (ui.captured != PieceType::EMPTY)
+        board.getBitboards(otherSide(turn))[ui.captured] = ui.beforeCaptured;
     moveCount--;
-    if (ui.decrementReversibleHalfMoves)
-        reversibleHalfMoves--;
+    reversibleHalfMoves = ui.reversibleHalfMoves;
+    castlingRights = ui.castlingRights;
 }

+ 25 - 6
src/ChessGame.h

@@ -39,8 +39,12 @@ struct chessy::MoveInfo
 
 struct chessy::UndoInfo
 {
-    Board before;
-    bool decrementReversibleHalfMoves;
+    Bitboard before;
+    Bitboard beforeCaptured;
+    PieceType type;
+    PieceType captured;
+    uint8_t reversibleHalfMoves;
+    uint8_t castlingRights;
 };
 
 
@@ -48,8 +52,11 @@ class chessy::ChessGame
 {
     Board board;
 
-    bool canCastleQueenSide[2] = { true, true };
-    bool canCastleKingSide [2] = { true, true };
+    //! stores the castling rights according to the following scheme:
+    //! <b> XXXXQKqk </b>,
+    //! where X is an unused bit, Q and K store weather black can castle
+    //! to queen side/king side and q and k store the same for white.
+    uint8_t castlingRights;
 
     short reversibleHalfMoves =     0;
 
@@ -75,12 +82,24 @@ public:
 
     inline bool getCanCastleKingSide(Side side) const
     {
-        return canCastleKingSide[side];
+        return castlingRights & (1 << (side == BLACK_SIDE ? 2 : 0));
+    }
+
+    inline void setCanCastleKingSide(Side side, bool canCastle)
+    {
+        castlingRights ^= (castlingRights ^ (canCastle ? -1 : 0)) &
+            (1 << (side == BLACK_SIDE ? 2 : 0));
     }
 
     inline bool getCanCastleQueenSide(Side side) const
     {
-        return canCastleQueenSide[side];
+        return castlingRights & (1 << (side == BLACK_SIDE ? 3 : 1));
+    }
+
+    inline void setCanCastleQueenSide(Side side, bool canCastle)
+    {
+        castlingRights ^= (castlingRights ^ (canCastle ? -1 : 0)) &
+            (1 << (side == BLACK_SIDE ? 3 : 1));
     }
 
     void move(Move move);

+ 6 - 2
src/Minimax.cpp

@@ -129,21 +129,25 @@ MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth,
     else
         generateAllMoves<BLACK_SIDE>(cg, moves);
 
+    bool thereIsMove = false;
     for (Move move : moves) {
         MoveInfo mi{ move, cg };
         UndoInfo ui = cg.doMove(mi);
         MoveValue val;
         if (isCheck())
             val = -1e+30;
-        else
+        else {
             val = -negamaxImplementation(cg, depth - 1, -beta, -alpha);
+            thereIsMove = true;
+        }
         cg.undoMove(ui);
         if(val >= beta)
             return beta;
         if(val > alpha)
             alpha = val;
     }
-
+    if (!thereIsMove)
+        return 0.0;
     return alpha;
 }
 

+ 3 - 2
src/UciParser.cpp

@@ -156,9 +156,10 @@ void UciParser::go(const vector<string>& args)
 
     chessy::Move bestMove;
     chessy::MoveValue value;
-    tie(bestMove, value) = chessy::miniMax(this->cg, 5);
+    int depth = 5;
+    tie(bestMove, value) = chessy::miniMax(this->cg, depth);
 
-    sendCommand("info", { "depth", "4", "score", "cp", to_string(value) });
+    write("info", "depth", depth, "score", "cp", value);
 
     sendCommand("bestmove", { bestMove.asString() });
     /*fst = make_unique<FixedSearchTimer>(cg, *this);

+ 13 - 0
src/UciParser.h

@@ -71,6 +71,19 @@ public:
     virtual void sendCommand(const std::string& command,
         const std::vector<std::string>& args = {});
 
+    template<typename T, typename... Args>
+    void write(T&& t, Args&&... args)
+    {
+        std::cout << t << " ";
+        write(args...);
+    }
+
+    template<typename T>
+    inline void write(T&& t)
+    {
+        std::cout << t << endl;
+    }
+
     // command handlers
     virtual void uci            (const std::vector<std::string>& args);
     virtual void debug          (const std::vector<std::string>& args);