Selaa lähdekoodia

Merge branch 'master' of https://gitlab.vis.ethz.ch/niwinkle/chessy

nicolaswinkler 7 vuotta sitten
vanhempi
commit
9ae6d0d062
9 muutettua tiedostoa jossa 315 lisäystä ja 6 poistoa
  1. 16 0
      src/Board.cpp
  2. 11 0
      src/Board.h
  3. 7 0
      src/ChessGame.cpp
  4. 2 0
      src/ChessGame.h
  5. 86 0
      src/Minimax.cpp
  6. 8 2
      src/Minimax.h
  7. 158 2
      src/MoveGeneration.cpp
  8. 23 0
      src/MoveGeneration.h
  9. 4 2
      src/UciParser.cpp

+ 16 - 0
src/Board.cpp

@@ -176,7 +176,23 @@ void Board::move(const Move& move)
 {
     Bitboard start = Bitboard::fromIndex(move.origin);
     Bitboard end = Bitboard::fromIndex(move.destination);
+
+    for (Bitboard& b : whites)
+        if (b & end) {
+            b ^= end;
+            goto move;
+        }
+    for (Bitboard& b : blacks)
+        if (b & end) {
+            b ^= end;
+            goto move;
+        }
+
+    move:
+
     for (Bitboard& b : whites) {
+        if (b & end)
+            b ^= end;
         if (b & start) {
             b &= ~start;
             b |= end;

+ 11 - 0
src/Board.h

@@ -68,6 +68,7 @@ public:
     template<Side side>
     inline Bitboard& getKing       (void) { return getBitboards<side>()[KING]; }
 
+
     template<Side side>
     inline const Bitboard& getPawns(void) const { return getBitboards<side>()[PAWN]; }
     template<Side side>
@@ -80,6 +81,16 @@ public:
     inline const Bitboard& getQueens(void) const  { return getBitboards<side>()[QUEEN]; }
     template<Side side>
     inline const Bitboard& getKing (void) const  { return getBitboards<side>()[KING]; }
+    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];
+    }
 
     /*!
      * parses the first part of a FEN string and sets the board

+ 7 - 0
src/ChessGame.cpp

@@ -4,6 +4,13 @@
 
 using namespace chessy;
 
+MoveInfo::MoveInfo(Move move, const ChessGame& cg) :
+    move{ move }, movedPiece{ cg.getBoard().getAtPosition(move.origin) },
+    enPassantTarget{ 0 }
+{
+}
+
+
 ChessGame::ChessGame(void)
 {
     board.resetBoard();

+ 2 - 0
src/ChessGame.h

@@ -32,6 +32,8 @@ struct chessy::MoveInfo
 
     inline MoveInfo(void) :
         enPassantTarget{ 0 } {}
+
+    MoveInfo(Move move, const ChessGame& cg);
 };
 
 

+ 86 - 0
src/Minimax.cpp

@@ -63,6 +63,92 @@ size_t chessy::perft(std::ostream& out, ChessGame& chessGame, int depth)
     return result;
 }
 
+
+Move chessy::miniMax(ChessGame& cg, int depth)
+{
+    std::vector<Move> moves;
+    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();
+    for (Move move : moves) {
+        MoveInfo mi{ move, cg };
+        UndoInfo ui = cg.doMove(mi);
+        MoveValue val = negamaxImplementation(cg, depth - 1);
+        cg.undoMove(ui);
+        if(val < best) {
+            best = val;
+            bestMove = move;
+        }
+    }
+    return bestMove; //negamaxImplementation(chessGame, 5);
+}
+
+
+MoveValue chessy::negamaxImplementation(ChessGame& cg, int depth)
+{
+    if (depth <= 0) {
+        if (cg.getTurn() == WHITE_SIDE)
+            return evaluate<WHITE_SIDE>(cg);
+        else
+            return evaluate<BLACK_SIDE>(cg);
+    }
+
+    std::vector<Move> moves;
+    if (cg.getTurn() == WHITE_SIDE)
+        generateAllMoves<WHITE_SIDE>(cg, moves);
+    else
+        generateAllMoves<BLACK_SIDE>(cg, moves);
+
+    for (Move move : moves) {
+        MoveInfo mi{ move, cg };
+        negamaxImplementation(cg, depth - 1);
+        UndoInfo ui = cg.doMove(mi);
+        cg.undoMove(ui);
+    }
+
+    return 0.0;
+}
+
+
+template<Side side>
+MoveValue chessy::evaluate(const ChessGame& game)
+{
+    int piecePoints = 0;
+    const Board& bd = game.getBoard();
+    Bitboard p = bd.getPawns<side>();
+    Bitboard n = bd.getKnights<side>();
+    Bitboard b = bd.getBishops<side>();
+    Bitboard r = bd.getRooks<side>();
+    Bitboard q = bd.getQueens<side>();
+    Bitboard k = bd.getKing<side>();
+    piecePoints += 1 * p.popcount();
+    piecePoints += 3 * n.popcount();
+    piecePoints += 3 * b.popcount();
+    piecePoints += 4 * r.popcount();
+    piecePoints += 6 * q.popcount();
+    if (k == Bitboard(0ULL))
+        piecePoints -= 100000;
+
+    const 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>();
+    piecePoints -= 1 * p.popcount();
+    piecePoints -= 3 * n.popcount();
+    piecePoints -= 3 * b.popcount();
+    piecePoints -= 4 * r.popcount();
+    piecePoints -= 6 * q.popcount();
+    if (k == Bitboard(0ULL))
+        piecePoints += 100000;
+
+    return piecePoints;
+}
 /*
 template MiniMax::BestMove MiniMax::minimax<WHITE_SIDE>(int);
 template MiniMax::BestMove MiniMax::minimax<BLACK_SIDE>(int);

+ 8 - 2
src/Minimax.h

@@ -7,7 +7,8 @@
 
 namespace chessy
 {
-    
+    using MoveValue = float;
+
     /*!
      * \brief conducts a performance test iterating through all positions
      *        up to a specified depth.
@@ -20,7 +21,12 @@ namespace chessy
      */
     size_t perft(std::ostream& out, ChessGame& chessGame, int depth);
 
-    Move miniMax(ChessGame& cg);
+    Move miniMax(ChessGame& chessGame, int depth);
+
+    MoveValue negamaxImplementation(ChessGame& cg, int depth);
+
+    template<Side side>
+    MoveValue chessy::evaluate(const ChessGame& game);
 }
 
 

+ 158 - 2
src/MoveGeneration.cpp

@@ -208,10 +208,163 @@ CastlingGenerator<side>::CastlingGenerator(const ChessGame& game) :
 }
 
 
+template<Side side>
+void chessy::generatePawnPushes(const ChessGame& cg, std::vector<Move>& moves)
+{
+    PawnPushGenerator<side> ppg{ cg };
+    for (const auto& move : ppg)
+        moves.push_back(move);
+}
+
+
+template<Side side>
+void chessy::generatePawnDoublePushes(const ChessGame& cg, std::vector<Move>& moves)
+{
+    PawnDoublePushGenerator<side> pdpg{ cg };
+    for (const auto& move : pdpg)
+        moves.push_back(move);
+}
+
+
+template<Side side>
+void chessy::generatePawnCaptures(const ChessGame& cg, std::vector<Move>& moves)
+{
+    PawnCaptureGenerator<side, LEFT> pcgl{ cg };
+    PawnCaptureGenerator<side, RIGHT> pcgr{ cg };
+    for (const auto& move : pcgl)
+        moves.push_back(move);
+    for (const auto& move : pcgr)
+        moves.push_back(move);
+}
+
+
+template<Side side>
+void chessy::generatePawnPromotions(const ChessGame& cg, std::vector<Move>& moves)
+{
+    PromotionGenerator<side> pg{ cg };
+    for (const auto& move : pg)
+        moves.push_back(move);
+
+}
+
+
+template<Side side>
+void chessy::generateKnightMoves(const ChessGame& cg, std::vector<Move>& moves)
+{
+    const Board& b = cg.getBoard();
+    PositionSet p{ b.getKnights<side>() };
+    for (auto pos : p) {
+        KnightMoveGenerator g{ pos, b.get<side>() };
+        for (auto target : g) {
+            moves.emplace_back(pos, target);
+        }
+    }
+}
+
+
+template<Side side, typename Generator>
+void generateMoves(Bitboard position, Bitboard enemies, Bitboard friendly,
+    std::vector<Move>& moves)
+{
+    PositionSet p{ position };
+    for (auto pos : p) {
+        Generator g{ pos, enemies, friendly };
+        for (auto target : g) {
+            moves.emplace_back(pos, target);
+        }
+    }
+}
+
+
+template<Side side>
+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
+    );
+}
+
+
+template<Side side>
+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
+    );
+}
+
+
+template<Side side>
+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
+    );
+}
+
+
+template<Side side>
+void chessy::generateKingMoves(const ChessGame& cg, std::vector<Move>& moves)
+{
+    const Board& b = cg.getBoard();
+    Bitboard king = b.getKing<side>();
+    Index kingIndex = king.getLeastSignificantBit();
+    for (auto pos : KingMoveGenerator{ king, b.get<side>() })
+        moves.emplace_back(kingIndex, pos);
+}
+
+
+template<Side side>
+void chessy::generateCastling(const ChessGame& cg, std::vector<Move>& moves)
+{
+    const Board& b = cg.getBoard();
+    Bitboard king = b.getKing<side>();
+    Bitboard allOccupied = b.getOccupied();
+    if (cg.getCanCastleKingSide(side)) {
+        Bitboard target = king.bits >> 2; // move king to the right
+        Bitboard rook = king.bits << 3;
+        Bitboard rookTarget = king.bits >> 1;
+        if (!(target & allOccupied) &&
+            !(rookTarget & allOccupied)) {
+            moves.emplace_back(king.getLeastSignificantBit(),
+                target.getLeastSignificantBit(), true);
+        }
+    }
+    if (cg.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)) {
+            moves.emplace_back(king.getLeastSignificantBit(),
+                target.getLeastSignificantBit(), true);
+        }
+    }
+}
+
+
+template<Side side>
+void chessy::generateAllMoves(const ChessGame& cg, std::vector<Move>& moves)
+{
+    generatePawnPushes<side>(cg, moves);
+    generatePawnDoublePushes<side>(cg, moves);
+    generatePawnCaptures<side>(cg, moves);
+    generatePawnPromotions<side>(cg, moves);
+    generateKnightMoves<side>(cg, moves);
+    generateQueenMoves<side>(cg, moves);
+    generateBishopMoves<side>(cg, moves);
+    generateRookMoves<side>(cg, moves);
+    generateKingMoves<side>(cg, 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>;
@@ -226,5 +379,8 @@ 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>&);
 }

+ 23 - 0
src/MoveGeneration.h

@@ -31,6 +31,29 @@ namespace chessy
     class KingMoveGenerator;
     template<Side side>
     class CastlingGenerator;
+
+    template<Side side>
+    void generatePawnPushes(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generatePawnDoublePushes(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generatePawnCaptures(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generatePawnPromotions(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateKnightMoves(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateQueenMoves(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateRookMoves(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateBishopMoves(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateKingMoves(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateCastling(const ChessGame& cg, std::vector<Move>& moves);
+    template<Side side>
+    void generateAllMoves(const ChessGame& cg, std::vector<Move>& moves);
 }
 
 

+ 4 - 2
src/UciParser.cpp

@@ -153,10 +153,12 @@ void UciParser::go(const vector<string>& args)
 {
     stop({});
 
-    fst = make_unique<FixedSearchTimer>(cg, *this);
+    chessy::Move bestMove = chessy::miniMax(this->cg, 4);
+    sendCommand("bestmove", { bestMove.asString() });
+    /*fst = make_unique<FixedSearchTimer>(cg, *this);
 
     fst->setThinkTime(std::chrono::milliseconds{ 1000 });
-    fst->startSearch();
+    fst->startSearch();*/
 
     //chessy::Move m = minimax.calculateBest(5);