From 9942832b185a0938f69c68c42c3d694d91a66700 Mon Sep 17 00:00:00 2001 From: Karma Riuk Date: Fri, 7 Feb 2025 17:35:14 +0100 Subject: [PATCH] caching check and nlm --- cpp/src/controller/ai_vs_ai.cpp | 4 +- cpp/src/controller/manual.cpp | 4 +- cpp/src/main.cpp | 11 +-- cpp/src/model/ais/v1_pure_minimax.cpp | 4 +- cpp/src/model/board/board.cpp | 64 ++++++------- cpp/src/model/board/board.hpp | 16 ++-- cpp/src/model/perft/perft.cpp | 126 ++++++++++---------------- cpp/src/model/pieces/king.cpp | 12 +-- cpp/src/model/pieces/piece.cpp | 6 +- 9 files changed, 105 insertions(+), 142 deletions(-) diff --git a/cpp/src/controller/ai_vs_ai.cpp b/cpp/src/controller/ai_vs_ai.cpp index 1beab9f..bad15fd 100644 --- a/cpp/src/controller/ai_vs_ai.cpp +++ b/cpp/src/controller/ai_vs_ai.cpp @@ -29,10 +29,10 @@ void AIvsAIController::make_move(Move move) { view.update_board(board, -1, {}); Colour current_colour = board.white_to_play ? White : Black; - if (board.is_checkmate_for(current_colour)) + if (board.is_checkmate()) view.notify_checkmate(current_colour); - if (board.is_stalemate_for(current_colour)) + if (board.is_stalemate()) view.notify_stalemate(current_colour); } diff --git a/cpp/src/controller/manual.cpp b/cpp/src/controller/manual.cpp index 159ff8d..3e99c4e 100644 --- a/cpp/src/controller/manual.cpp +++ b/cpp/src/controller/manual.cpp @@ -55,9 +55,9 @@ void ManualController::make_move(Move move) { reset_selection(); Colour current_colour = board.white_to_play ? White : Black; - if (board.is_checkmate_for(current_colour)) + if (board.is_checkmate()) view.notify_checkmate(current_colour); - if (board.is_stalemate_for(current_colour)) + if (board.is_stalemate()) view.notify_stalemate(current_colour); } diff --git a/cpp/src/main.cpp b/cpp/src/main.cpp index 39d3c2a..071e211 100644 --- a/cpp/src/main.cpp +++ b/cpp/src/main.cpp @@ -17,11 +17,8 @@ int main(int argc, char* argv[]) { // "; // pos for ai timing< - // std::string pos = - // "r3k2r/p1ppqpb1/Bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPB1PPP/R3K2R b KQkq - 0 - // 3"; - std::string pos = "r3k2r/p1p1qpb1/bn1ppnp1/3PN3/1p2P3/P1N2Q1p/1PPBBPPP/" - "1R2K2R b Kkq - 0 4"; + std::string pos = + "r3k2r/p1ppqpb1/Bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPB1PPP/R3K2R b KQkq - 0 3 "; Board b = Board::setup_fen_position(pos); @@ -36,8 +33,8 @@ int main(int argc, char* argv[]) { Controller& controller = manual; - // controller.start(); + controller.start(); - perft(pos); + // perft(); return 0; } diff --git a/cpp/src/model/ais/v1_pure_minimax.cpp b/cpp/src/model/ais/v1_pure_minimax.cpp index e5d2024..550ad9d 100644 --- a/cpp/src/model/ais/v1_pure_minimax.cpp +++ b/cpp/src/model/ais/v1_pure_minimax.cpp @@ -61,8 +61,8 @@ int ai::v1_pure_minimax::_search(const Board& b, int depth) { if (depth == 0 || stop_computation) return eval(b); - if (b.no_legal_moves_for(b.white_to_play ? White : Black)) { - if (b.is_check_for(b.white_to_play ? White : Black)) + if (b.no_legal_moves()) { + if (b.is_check()) return -INFINITY; return 0; } diff --git a/cpp/src/model/board/board.cpp b/cpp/src/model/board/board.cpp index be21f03..e15bd30 100644 --- a/cpp/src/model/board/board.cpp +++ b/cpp/src/model/board/board.cpp @@ -94,10 +94,8 @@ Board Board::setup_fen_position(std::string fen) { index = fen.find(' ', index) + 1; board.n_full_moves = std::stoi(fen.substr(index)); - board.w_check = board._is_check_for(White); - board.b_check = board._is_check_for(Black); - board.w_nlm = board._no_legal_moves_for(White); - board.b_nlm = board._no_legal_moves_for(Black); + board.check = board._is_check_for(board.white_to_play ? White : Black); + board.nlm = board._no_legal_moves_for(board.white_to_play ? White : Black); return board; } @@ -175,6 +173,13 @@ std::string Board::to_fen() const { return ret; } +Board Board::skip_turn() const { + Board ret = *this; + ret.white_to_play = !ret.white_to_play; + ret.check = ret._is_check_for(ret.white_to_play ? White : Black); + return ret; +} + Board Board::make_move(Move move, bool recurse_call) const { Board ret; std::copy( @@ -284,10 +289,8 @@ Board Board::make_move(Move move, bool recurse_call) const { } if (recurse_call) { - ret.w_check = ret._is_check_for(White); - ret.b_check = ret._is_check_for(Black); - ret.w_nlm = ret._no_legal_moves_for(White); - ret.b_nlm = ret._no_legal_moves_for(Black); + ret.check = ret._is_check_for(ret.white_to_play ? White : Black); + ret.nlm = ret._no_legal_moves_for(ret.white_to_play ? White : Black); } return ret; } @@ -354,17 +357,9 @@ bool Board::_is_check_for(Colour colour) const { all_moves.insert(all_moves.end(), moves.begin(), moves.end()); } - for (const Move& move : all_moves) { - // if (colour == White - // && move.target_square - // == Coords::from_algebraic("b6").to_index()) - // std::cout << "am here" << std::endl; - if (move.target_square == king_idx) { - std::cout << "indeed check for " << to_string(colour) - << std::endl; + for (const Move& move : all_moves) + if (move.target_square == king_idx) return true; - } - } all_moves.clear(); } return false; @@ -372,36 +367,35 @@ bool Board::_is_check_for(Colour colour) const { bool Board::_no_legal_moves_for(Colour colour) const { for (int i = 0; i < 64; i++) { - if (colour_at(i) == colour) { - std::vector moves = - legal_moves(squares[i], *this, Coords::from_index(i)); - if (moves.size() > 0) - return false; - } + if (squares[i] == Piece::None || colour_at(i) != colour) + continue; + std::vector moves; + moves = legal_moves(squares[i], *this, Coords::from_index(i)); + if (moves.size() > 0) + return false; } return true; } -bool Board::no_legal_moves_for(int8_t colour) const { - return colour == White ? w_nlm : b_nlm; +bool Board::no_legal_moves() const { + return nlm; } -bool Board::is_check_for(int8_t colour) const { - return colour == White ? w_check : b_check; +bool Board::is_check() const { + return check; } -bool Board::is_checkmate_for(Colour colour) const { - return no_legal_moves_for(colour) && is_check_for(colour); +bool Board::is_checkmate() const { + return check && nlm; } -bool Board::is_stalemate_for(Colour colour) const { - return no_legal_moves_for(colour) && !is_check_for(colour); +bool Board::is_stalemate() const { + return !check && nlm; } bool Board::is_terminal() const { - return n_half_moves == 100 || insufficient_material() || white_to_play - ? is_checkmate_for(White) || is_stalemate_for(White) - : is_checkmate_for(Black) || is_stalemate_for(Black); + return n_half_moves == 100 || insufficient_material() || is_checkmate() + || is_stalemate(); } std::vector Board::all_legal_moves() const { diff --git a/cpp/src/model/board/board.hpp b/cpp/src/model/board/board.hpp index 98a4703..274d4c4 100644 --- a/cpp/src/model/board/board.hpp +++ b/cpp/src/model/board/board.hpp @@ -11,7 +11,7 @@ struct Board { int8_t get_king_of(int8_t) const; bool _no_legal_moves_for(Colour) const; bool _is_check_for(Colour) const; - bool w_nlm = false, b_nlm = false, w_check = false, b_check = false; + bool nlm = false, check = false; public: int8_t squares[64] = {Piece::None}; @@ -19,15 +19,17 @@ struct Board { int8_t w_castle_rights = CastleSide::NeitherSide; int8_t b_castle_rights = CastleSide::NeitherSide; int8_t en_passant_target = -1; - uint8_t n_half_moves = 0; - uint8_t n_full_moves = 0; + int n_half_moves = 0; + int n_full_moves = 0; + static Board setup_fen_position(std::string fen); + Board skip_turn() const; Board make_move(Move, bool = true) const; std::string to_fen() const; - bool no_legal_moves_for(int8_t) const; - bool is_check_for(int8_t) const; + bool no_legal_moves() const; + bool is_check() const; bool insufficient_material_for(Colour) const; bool insufficient_material() const { @@ -37,9 +39,9 @@ struct Board { std::vector all_legal_moves() const; - bool is_checkmate_for(Colour) const; + bool is_checkmate() const; - bool is_stalemate_for(Colour) const; + bool is_stalemate() const; bool is_terminal() const; diff --git a/cpp/src/model/perft/perft.cpp b/cpp/src/model/perft/perft.cpp index 8f27734..a9a25c5 100644 --- a/cpp/src/model/perft/perft.cpp +++ b/cpp/src/model/perft/perft.cpp @@ -47,7 +47,7 @@ static std::map> pos2expected{ {3, 2812}, // 11 {4, 43238}, // 157 {5, 674624}, // 2199 - // {6, 11030083}, + {6, 11030083}, }, }, @@ -55,11 +55,11 @@ static std::map> pos2expected{ { "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 4", { - {1, 6}, // 0 - {2, 264}, // 1 - {3, 9467}, // 69 - {4, 422333}, // 3085 - // {5, 15833292}, // 124452 + {1, 6}, // 0 + {2, 264}, // 1 + {3, 9467}, // 69 + {4, 422333}, // 3085 + {5, 15833292}, // 124452 }, }, @@ -67,11 +67,11 @@ static std::map> pos2expected{ { "r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 5", { - {1, 6}, // 0 - {2, 264}, // 2 - {3, 9467}, // 104 - {4, 422333}, // 3742 - // {5, 15833292}, // 136784 + {1, 6}, // 0 + {2, 264}, // 2 + {3, 9467}, // 104 + {4, 422333}, // 3742 + {5, 15833292}, // 136784 }, }, @@ -79,10 +79,10 @@ static std::map> pos2expected{ { "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 6", { - {1, 44}, // 0 - {2, 1486}, // 12 - {3, 62379}, // 357 - // {4, 2103487}, // 13804 + {1, 44}, // 0 + {2, 1486}, // 12 + {3, 62379}, // 357 + {4, 2103487}, // 13804 // {5, 89941194}, // 1230428 }, }, @@ -92,43 +92,13 @@ static std::map> pos2expected{ "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 " "7", { - {1, 46}, // 0 - {2, 2079}, // 16 - {3, 89890}, // 602 - // {4, 3894594}, // 26612 + {1, 46}, // 0 + {2, 2079}, // 16 + {3, 89890}, // 602 + {4, 3894594}, // 26612 // {5, 164075551}, // 1230428 }, }, - - // -- Position 7 - { - "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 4 3", - { - {4, 4085603}, // - }, - }, - // -- Position 7 after a1b1 - { - "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/1R2K2R b Kkq - 5 3", - { - {3, 83348}, // - }, - }, - // -- Position 7 after a1b1 d7d6 - { - "r3k2r/p1p1qpb1/bn1ppnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/1R2K2R w Kkq - 0 4", - { - {2, 1919}, // - }, - }, - // -- Position 7 after a1b1 d7d6 a2a3 - { - "r3k2r/p1p1qpb1/bn1ppnp1/3PN3/1p2P3/P1N2Q1p/1PPBBPPP/1R2K2R b Kkq - 0 " - "4", - { - {1, 45}, // - }, - }, }; static std::stringstream res; @@ -142,43 +112,43 @@ int move_generation_test( } if (b.is_terminal()) - return 1; + return 0; if (depth == 0) return 1; std::vector moves = b.all_legal_moves(); - // if (depth == 1) - // return moves.size(); + if (depth == 1) + return moves.size(); int num_pos = 0; - // if (depth == max_depth) { - // // Parallel execution at the top level - // std::vector> futures; - // for (const Move& move : moves) { - // Board tmp_board = b.make_move(move); - // futures.push_back(pool.enqueue( - // move_generation_test, - // tmp_board, - // depth - 1, - // max_depth, - // std::ref(pool) - // )); - // } - // - // for (auto& future : futures) - // num_pos += future.get(); // Retrieve the result of each task - // } else { - // Regular sequential execution - for (const Move& move : moves) { - // std::cout << "Looking at " << move << std::endl; - Board tmp_board = b.make_move(move); - int n = move_generation_test(tmp_board, depth - 1, max_depth, pool); - if (depth == max_depth) - res << move << ": " << n << std::endl; - num_pos += n; + if (depth == max_depth) { + // Parallel execution at the top level + std::vector> futures; + for (const Move& move : moves) { + Board tmp_board = b.make_move(move); + futures.push_back(pool.enqueue( + move_generation_test, + tmp_board, + depth - 1, + max_depth, + std::ref(pool) + )); + } + + for (auto& future : futures) + num_pos += future.get(); // Retrieve the result of each task + } else { + // Regular sequential execution + for (const Move& move : moves) { + // std::cout << "Looking at " << move << std::endl; + Board tmp_board = b.make_move(move); + int n = move_generation_test(tmp_board, depth - 1, max_depth, pool); + if (depth == max_depth) + res << move << ": " << n << std::endl; + num_pos += n; + } } - // } return num_pos; } diff --git a/cpp/src/model/pieces/king.cpp b/cpp/src/model/pieces/king.cpp index 00771ab..a4b6714 100644 --- a/cpp/src/model/pieces/king.cpp +++ b/cpp/src/model/pieces/king.cpp @@ -11,7 +11,8 @@ static bool is_clear_king_side(const Board& b, const Coords xy) { std::optional move = move_for_position(b, xy, c); Board board_after_move = b.make_move(move.value(), false); - if (board_after_move.is_check_for(b.colour_at(xy))) + board_after_move = board_after_move.skip_turn(); + if (board_after_move.is_check()) return false; } return true; @@ -25,7 +26,8 @@ static bool is_clear_queen_side(const Board& b, const Coords xy) { std::optional move = move_for_position(b, xy, c); Board board_after_move = b.make_move(move.value(), false); - if (dx < 3 && board_after_move.is_check_for(b.colour_at(xy))) + board_after_move = board_after_move.skip_turn(); + if (dx < 3 && board_after_move.is_check()) return false; } return true; @@ -46,11 +48,9 @@ std::vector king_moves(const Board& b, const Coords xy) { } } - if (b.is_check_for(b.colour_at(xy))) { - std::cout << b.to_fen() << std::endl; - std::cout << "Check for " << to_string(b.colour_at(xy)) << std::endl; + + if (b.is_check()) return keep_only_blocking(ret, b); - } // -- Castles int8_t castling_rights = b.colour_at(xy) == Colour::White diff --git a/cpp/src/model/pieces/piece.cpp b/cpp/src/model/pieces/piece.cpp index b7ec4c2..cfc44a1 100644 --- a/cpp/src/model/pieces/piece.cpp +++ b/cpp/src/model/pieces/piece.cpp @@ -13,10 +13,10 @@ keep_only_blocking(const std::vector candidates, const Board& board) { std::vector ret; for (Move move : candidates) { Board board_after_move = board.make_move(move, false); - if (!board_after_move.is_check_for(my_colour)) + board_after_move = board_after_move.skip_turn(); + + if (!board_after_move.is_check()) ret.push_back(move); - else - std::cout << "removing " << move << std::endl; } return ret; }