diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..aa2e50b --- /dev/null +++ b/.clang-format @@ -0,0 +1,44 @@ +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveDeclarations: Consecutive +AlignEscapedNewlines: DontAlign +AlignOperands: AlignAfterOperator +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AlwaysBreakTemplateDeclarations: Yes +BasedOnStyle: WebKit +BitFieldColonSpacing: After +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: false + AfterClass: false + AfterControlStatement: false + BeforeElse: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakStringLiterals: false +ColumnLimit: 100 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentWidth: 4 +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +PackConstructorInitializers: Never +ReflowComments: false +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeCaseColon: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeInheritanceColon: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 \ No newline at end of file diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 0000000..6707b4c --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,30 @@ +name: Clang Format + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + clang-format: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Clang + run: | + sudo apt-get install -y clang-format + + - name: Run clang-format Check on MediaProcessor + run: | + find src -regex '.*\.\(cpp\|h\)' -exec clang-format --dry-run --Werror {} + + + - name: Display Message if Formatting Fails + if: failure() + run: echo "Code formatting issues found. Please run clang-format to fix them." + diff --git a/src/Makefile b/src/Makefile index f7ee73e..dcbe538 100644 --- a/src/Makefile +++ b/src/Makefile @@ -16,6 +16,16 @@ all: $(EXE) clean: $(RM) $(EXE) *.o bench/*.o chess/*.o utils/*.o +.PHONY: format # Mark `format` as a phony target so it runs each time +# Set the format command based on the OS +ifeq ($(OS),Windows_NT) +format: + powershell -Command "Get-ChildItem -Recurse -Include *.cpp, *.h | ForEach-Object { clang-format -i $$_.FullName }" +else +format: + find . -type f \( -name "*.cpp" -o -name "*.h" \) -exec clang-format -i {} + +endif + ### ### Compiler: ### diff --git a/src/bench/benchmark.cpp b/src/bench/benchmark.cpp index b54d3c9..3fc6dc7 100644 --- a/src/bench/benchmark.cpp +++ b/src/bench/benchmark.cpp @@ -49,17 +49,17 @@ std::vector bench_positions = { "4rrk1/1p1nq3/p7/2p1P1pp/3P2bp/3Q1Bn1/PPPB4/1K2R1NR w - - 40 21", "r3k2r/3nnpbp/q2pp1p1/p7/Pp1PPPP1/4BNN1/1P5P/R2Q1RK1 w kq - 0 16", "3Qb1k1/1r2ppb1/pN1n2q1/Pp1Pp1Pr/4P2p/4BP2/4B1R1/1R5K b - - 11 40", - "4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1", + "4k3/3q1r2/1N2r1b1/3ppN2/2nPP3/1B1R2n1/2R1Q3/3K4 w - - 5 1", // 5-man positions - "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate - "8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate - "8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw + "8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", // Kc2 - mate + "8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", // Na2 - mate + "8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", // draw // 6-man positions - "8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate - "8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate - "8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw + "8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", // Re5 - mate + "8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", // Ka2 - mate + "8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", // Nd2 - draw // 7-man positions - "8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw + "8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", // Draw // Mate and stalemate positions "6k1/3b3r/1p1p4/p1n2p2/1PPNpP1q/P3Q1p1/1R1RB1P1/5K2 b - - 0 1", "r2r1n2/pp2bk2/2p1p2p/3q4/3PN1QP/2P3R1/P4PP1/5RK1 w - - 0 1", @@ -72,18 +72,19 @@ std::vector bench_positions = { namespace sonic { void run_bench() { - const std::vector go_params = {"go", "depth", "6"}; - std::uint64_t node_count = 0; - TimePoint start = current_time(); - Position pos; - SearchInfo search_info; - for(size_t i = 0; i < bench_positions.size(); i++) { - std::string fen = "position fen " + bench_positions[i]; + const std::vector go_params = {"go", "depth", "6"}; + std::uint64_t node_count = 0; + TimePoint start = current_time(); + Position pos; + SearchInfo search_info; + for (size_t i = 0; i < bench_positions.size(); i++) { + std::string fen = "position fen " + bench_positions[i]; std::vector params = split_string(fen, ' '); parse_position(pos, search_info, params); parse_go(pos, search_info, go_params); TT.clear(); - std::cout << "Position [" << i + 1 << "/" << bench_positions.size() << "]" << " (" << pos.fen() << ")" << std::endl; + std::cout << "Position [" << i + 1 << "/" << bench_positions.size() << "]" + << " (" << pos.fen() << ")" << std::endl; search(pos, search_info); node_count += search_info.nodes; std::cout << "\n"; diff --git a/src/bench/perft.cpp b/src/bench/perft.cpp index 2fb2c97..2becea5 100644 --- a/src/bench/perft.cpp +++ b/src/bench/perft.cpp @@ -13,15 +13,15 @@ namespace sonic { // Count number of leaf nodes. std::uint64_t perft(Position& pos, int depth) { - if(depth == 0) { + if (depth == 0) { return 1; } std::uint64_t node_count = 0; - MoveList movelist; + MoveList movelist; generate_moves(pos, movelist); - for(const Move& m : movelist) { + for (const Move& m : movelist) { UndoInfo info; - if(!pos.make_move(m, info)) { + if (!pos.make_move(m, info)) { pos.unmake_move(info); continue; } @@ -33,6 +33,7 @@ std::uint64_t perft(Position& pos, int depth) { } void bench_perft() { + // clang-format off const std::vector perft_tests = { {"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", 119060324ULL, 6}, {"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1", 193690690ULL, 5}, @@ -42,14 +43,15 @@ void bench_perft() { {"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 89941194ULL, 5}, {"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10", 164075551ULL, 5}, }; + // clang-format on - for(std::size_t i = 0; i < perft_tests.size(); i++) { + for (std::size_t i = 0; i < perft_tests.size(); i++) { const auto& test = perft_tests[i]; - Position pos(test.fen); + Position pos(test.fen); - TimePoint start = current_time(); + TimePoint start = current_time(); std::uint64_t node_count = perft(pos, test.depth); - std::uint64_t ms = time_elapsed(start); + std::uint64_t ms = time_elapsed(start); std::cout << "Position [" << i + 1 << "/" << perft_tests.size() << "]:"; std::cout << std::left; diff --git a/src/bench/perft.h b/src/bench/perft.h index c86228b..61f593d 100644 --- a/src/bench/perft.h +++ b/src/bench/perft.h @@ -8,12 +8,12 @@ namespace sonic { struct PerftTest { - std::string fen; + std::string fen; std::uint64_t expected_node_count; - int depth; + int depth; }; std::uint64_t perft(Position& pos, int depth); -void bench_perft(); +void bench_perft(); } // namespace sonic \ No newline at end of file diff --git a/src/book.cpp b/src/book.cpp index bf08994..0ebc18e 100644 --- a/src/book.cpp +++ b/src/book.cpp @@ -11,7 +11,7 @@ namespace sonic { void Book::open(const std::string& file) { book = fopen(file.c_str(), "rb+"); - if(book == NULL) { + if (book == NULL) { return; } fseek(book, 0, SEEK_END); @@ -25,20 +25,20 @@ void Book::close() { // Select a random book move. Move Book::book_move(const Position& pos) const { - if(!is_open()) { + if (!is_open()) { return MOVE_NONE; } // Convert polyglot move format to ours. auto convert_move = [&](int move) -> Move { - int to_file = move & 7; - int to_rank = (move >> 3) & 7; - int from_file = (move >> 6) & 7; - int from_rank = (move >> 9) & 7; - int promotion_piece = (move >> 12) & 7; - Square from = Square(File(from_file), Rank(from_rank)); - Square to = Square(File(to_file), Rank(to_rank)); - Move::Promotion promotion = Move::Promotion::None; - if(promotion_piece != 0) { + int to_file = move & 7; + int to_rank = (move >> 3) & 7; + int from_file = (move >> 6) & 7; + int from_rank = (move >> 9) & 7; + int promotion_piece = (move >> 12) & 7; + Square from = Square(File(from_file), Rank(from_rank)); + Square to = Square(File(to_file), Rank(to_rank)); + Move::Promotion promotion = Move::Promotion::None; + if (promotion_piece != 0) { // Our piece order is reversed. promotion = Move::Promotion(5 - promotion_piece); } @@ -46,21 +46,21 @@ Move Book::book_move(const Position& pos) const { }; MoveList movelist; generate_moves(pos, movelist); - Move best_move = MOVE_NONE; - int best_score = 0; - for(int i = find_key(pos.hashkey()); i < book_size; i++) { + Move best_move = MOVE_NONE; + int best_score = 0; + for (int i = find_key(pos.hashkey()); i < book_size; i++) { Book::Entry entry = read_entry(i); - if(entry.key != pos.hashkey()) { + if (entry.key != pos.hashkey()) { break; } Move move = convert_move(entry.move); // Check if the given move is in movelist. This can filter out chess960 moves. - if(!movelist.contains(move)) { + if (!movelist.contains(move)) { continue; } int score = entry.count; best_score += score; - if(int(rng() % best_score) < score) { + if (int(rng() % best_score) < score) { best_move = move; } } @@ -70,10 +70,10 @@ Move Book::book_move(const Position& pos) const { // Binary search the file to find the first occurance of the key. int Book::find_key(std::uint64_t key) const { int l = 0, r = book_size - 1; - while(l < r) { - int mid = (l + r) / 2; + while (l < r) { + int mid = (l + r) / 2; Book::Entry entry = read_entry(mid); - if(key <= entry.key) { + if (key <= entry.key) { r = mid; } else { l = mid + 1; @@ -86,7 +86,7 @@ int Book::find_key(std::uint64_t key) const { Book::Entry Book::read_entry(int pos) const { auto read_int = [&](int bytes) -> std::uint64_t { std::uint64_t result = 0; - for(int i = 0; i < bytes; i++) { + for (int i = 0; i < bytes; i++) { int byte = fgetc(book); assert(byte != EOF); result = (result << 8) | byte; @@ -95,11 +95,11 @@ Book::Entry Book::read_entry(int pos) const { }; assert(fseek(book, pos * 16, SEEK_SET) == 0); Book::Entry entry; - entry.key = read_int(8); - entry.move = read_int(2); + entry.key = read_int(8); + entry.move = read_int(2); entry.count = read_int(2); - entry.n = read_int(2); - entry.sum = read_int(2); + entry.n = read_int(2); + entry.sum = read_int(2); return entry; } diff --git a/src/book.h b/src/book.h index 014c025..115f5ca 100644 --- a/src/book.h +++ b/src/book.h @@ -8,12 +8,10 @@ namespace sonic { class Book { -public: + public: Book() {} - Book(const std::string& file) { - open(file); - } + Book(const std::string& file) { open(file); } struct Entry { std::uint64_t key; @@ -31,12 +29,12 @@ class Book { // Select a random book move. Move book_move(const Position& pos) const; -private: - int find_key(std::uint64_t key) const; + private: + int find_key(std::uint64_t key) const; Entry read_entry(int pos) const; - FILE* book = NULL; - int book_size = 0; + FILE* book = NULL; + int book_size = 0; }; } // namespace sonic \ No newline at end of file diff --git a/src/chess/attacks.cpp b/src/chess/attacks.cpp index 18d26f2..e37426f 100644 --- a/src/chess/attacks.cpp +++ b/src/chess/attacks.cpp @@ -5,88 +5,90 @@ namespace sonic { -Bitboard rook_rays[Square::SQ_NB]; +Bitboard rook_rays[Square::SQ_NB]; Magic<4096> rook_magics[Square::SQ_NB]; -Bitboard bishop_rays[Square::SQ_NB]; -Magic<512> bishop_magics[Square::SQ_NB]; +Bitboard bishop_rays[Square::SQ_NB]; +Magic<512> bishop_magics[Square::SQ_NB]; void init_rook_attacks() { - for(int file = 0; file < 8; file++) { - for(int rank = 0; rank < 8; rank++) { + for (int file = 0; file < 8; file++) { + for (int rank = 0; rank < 8; rank++) { Bitboard rays_bb(0); // North - for(int new_rank = rank + 1; new_rank < 7; new_rank++) { + for (int new_rank = rank + 1; new_rank < 7; new_rank++) { rays_bb += Square(File(file), Rank(new_rank)); } // South - for(int new_rank = rank - 1; new_rank > 0; new_rank--) { + for (int new_rank = rank - 1; new_rank > 0; new_rank--) { rays_bb += Square(File(file), Rank(new_rank)); } // West - for(int new_file = file - 1; new_file > 0; new_file--) { + for (int new_file = file - 1; new_file > 0; new_file--) { rays_bb += Square(File(new_file), Rank(rank)); } // East - for(int new_file = file + 1; new_file < 7; new_file++) { + for (int new_file = file + 1; new_file < 7; new_file++) { rays_bb += Square(File(new_file), Rank(rank)); } - Square sq = Square(File(file), Rank(rank)); + Square sq = Square(File(file), Rank(rank)); rook_rays[sq.to_int()] = rays_bb; // Iterate over all submask of rays to fill magic table. - for(std::uint64_t blockers = rays_bb.to_int(); ; blockers = (blockers - 1) & rays_bb.to_int()) { + for (std::uint64_t blockers = rays_bb.to_int();; + blockers = (blockers - 1) & rays_bb.to_int()) { const Bitboard& blockers_bb(blockers); - Bitboard attacks_bb = 0; + Bitboard attacks_bb = 0; // North - for(int new_rank = rank + 1; Square::is_valid(new_rank, file); new_rank++) { + for (int new_rank = rank + 1; Square::is_valid(new_rank, file); new_rank++) { Square cur = Square(File(file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // South - for(int new_rank = rank - 1; Square::is_valid(new_rank, file); new_rank--) { + for (int new_rank = rank - 1; Square::is_valid(new_rank, file); new_rank--) { Square cur = Square(File(file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // West - for(int new_file = file - 1; Square::is_valid(rank, new_file); new_file--) { + for (int new_file = file - 1; Square::is_valid(rank, new_file); new_file--) { Square cur = Square(File(new_file), Rank(rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // East - for(int new_file = file + 1; Square::is_valid(rank, new_file); new_file++) { + for (int new_file = file + 1; Square::is_valid(rank, new_file); new_file++) { Square cur = Square(File(new_file), Rank(rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // Update magic table. - std::uint64_t key = (blockers * rook_multiplies[sq.to_int()]) >> rook_shifts[sq.to_int()]; - rook_magics[sq.to_int()].ray_mask = rays_bb; - rook_magics[sq.to_int()].magic = rook_multiplies[sq.to_int()]; - rook_magics[sq.to_int()].shift = rook_shifts[sq.to_int()]; + std::uint64_t key = + (blockers * rook_multiplies[sq.to_int()]) >> rook_shifts[sq.to_int()]; + rook_magics[sq.to_int()].ray_mask = rays_bb; + rook_magics[sq.to_int()].magic = rook_multiplies[sq.to_int()]; + rook_magics[sq.to_int()].shift = rook_shifts[sq.to_int()]; rook_magics[sq.to_int()].attacks[key] = attacks_bb; - if(blockers == 0) { + if (blockers == 0) { break; } } @@ -95,86 +97,96 @@ void init_rook_attacks() { } void init_bishop_attacks() { - for(int file = 0; file < 8; file++) { - for(int rank = 0; rank < 8; rank++) { + for (int file = 0; file < 8; file++) { + for (int rank = 0; rank < 8; rank++) { Bitboard rays_bb(0); // North West - for(int new_file = file - 1, new_rank = rank + 1; new_file > 0 && new_rank < 7; new_file--, new_rank++) { + for (int new_file = file - 1, new_rank = rank + 1; new_file > 0 && new_rank < 7; + new_file--, new_rank++) { Square cur = Square(File(new_file), Rank(new_rank)); rays_bb += cur; } // North East - for(int new_file = file + 1, new_rank = rank + 1; new_file < 7 && new_rank < 7; new_file++, new_rank++) { + for (int new_file = file + 1, new_rank = rank + 1; new_file < 7 && new_rank < 7; + new_file++, new_rank++) { Square cur = Square(File(new_file), Rank(new_rank)); rays_bb += cur; } // South West - for(int new_file = file - 1, new_rank = rank - 1; new_file > 0 && new_rank > 0; new_file--, new_rank--) { + for (int new_file = file - 1, new_rank = rank - 1; new_file > 0 && new_rank > 0; + new_file--, new_rank--) { Square cur = Square(File(new_file), Rank(new_rank)); rays_bb += cur; } // South East - for(int new_file = file + 1, new_rank = rank - 1; new_file < 7 && new_rank > 0; new_file++, new_rank--) { + for (int new_file = file + 1, new_rank = rank - 1; new_file < 7 && new_rank > 0; + new_file++, new_rank--) { Square cur = Square(File(new_file), Rank(new_rank)); rays_bb += cur; } - Square sq = Square(File(file), Rank(rank)); + Square sq = Square(File(file), Rank(rank)); bishop_rays[sq.to_int()] = rays_bb; // Iterate over all submask of rays to fill magic table. - for(std::uint64_t blockers = rays_bb.to_int(); ; blockers = (blockers - 1) & rays_bb.to_int()) { + for (std::uint64_t blockers = rays_bb.to_int();; + blockers = (blockers - 1) & rays_bb.to_int()) { const Bitboard& blockers_bb(blockers); - Bitboard attacks_bb = 0; + Bitboard attacks_bb = 0; // North West - for(int new_file = file - 1, new_rank = rank + 1; Square::is_valid(new_rank, new_file); new_file--, new_rank++) { + for (int new_file = file - 1, new_rank = rank + 1; + Square::is_valid(new_rank, new_file); new_file--, new_rank++) { Square cur = Square(File(new_file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // North East - for(int new_file = file + 1, new_rank = rank + 1; Square::is_valid(new_rank, new_file); new_file++, new_rank++) { + for (int new_file = file + 1, new_rank = rank + 1; + Square::is_valid(new_rank, new_file); new_file++, new_rank++) { Square cur = Square(File(new_file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // South West - for(int new_file = file - 1, new_rank = rank - 1; Square::is_valid(new_rank, new_file); new_file--, new_rank--) { + for (int new_file = file - 1, new_rank = rank - 1; + Square::is_valid(new_rank, new_file); new_file--, new_rank--) { Square cur = Square(File(new_file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // South East - for(int new_file = file + 1, new_rank = rank - 1; Square::is_valid(new_rank, new_file); new_file++, new_rank--) { + for (int new_file = file + 1, new_rank = rank - 1; + Square::is_valid(new_rank, new_file); new_file++, new_rank--) { Square cur = Square(File(new_file), Rank(new_rank)); attacks_bb += cur; - if(blockers_bb.get(cur)) { + if (blockers_bb.get(cur)) { break; } } // Update magic table. - std::uint64_t key = (blockers * bishop_multiplies[sq.to_int()]) >> bishop_shifts[sq.to_int()]; - bishop_magics[sq.to_int()].ray_mask = rays_bb; - bishop_magics[sq.to_int()].magic = bishop_multiplies[sq.to_int()]; - bishop_magics[sq.to_int()].shift = bishop_shifts[sq.to_int()]; + std::uint64_t key = + (blockers * bishop_multiplies[sq.to_int()]) >> bishop_shifts[sq.to_int()]; + bishop_magics[sq.to_int()].ray_mask = rays_bb; + bishop_magics[sq.to_int()].magic = bishop_multiplies[sq.to_int()]; + bishop_magics[sq.to_int()].shift = bishop_shifts[sq.to_int()]; bishop_magics[sq.to_int()].attacks[key] = attacks_bb; - if(blockers == 0) { + if (blockers == 0) { break; } } diff --git a/src/chess/attacks.h b/src/chess/attacks.h index b5e593d..e073cef 100644 --- a/src/chess/attacks.h +++ b/src/chess/attacks.h @@ -10,9 +10,9 @@ namespace sonic { template struct Magic { - Bitboard ray_mask; - std::uint64_t magic; - std::uint64_t shift; + Bitboard ray_mask; + std::uint64_t magic; + std::uint64_t shift; std::array attacks; Bitboard operator()(Bitboard occupied) const { @@ -22,13 +22,14 @@ struct Magic { } }; -extern Bitboard rook_rays[Square::SQ_NB]; +extern Bitboard rook_rays[Square::SQ_NB]; extern Magic<4096> rook_magics[Square::SQ_NB]; -extern Bitboard bishop_rays[Square::SQ_NB]; -extern Magic<512> bishop_magics[Square::SQ_NB]; +extern Bitboard bishop_rays[Square::SQ_NB]; +extern Magic<512> bishop_magics[Square::SQ_NB]; void init_attacks(); +// clang-format off // Magic numbers for rook. constexpr std::uint64_t rook_multiplies[Square::SQ_NB] = { 0xa8002c000108020ULL, 0x4440200140003000ULL, 0x8080200010011880ULL, @@ -169,5 +170,6 @@ constexpr Bitboard king_attacks[Square::SQ_NB] = { 0xC040C00000000000, 0x0203000000000000, 0x0507000000000000, 0x0A0E000000000000, 0x141C000000000000, 0x2838000000000000, 0x5070000000000000, 0xA0E0000000000000, 0x40C0000000000000 }; +// clang-format on } // namespace sonic \ No newline at end of file diff --git a/src/chess/bitboard.h b/src/chess/bitboard.h index a2a11d2..f1a1377 100644 --- a/src/chess/bitboard.h +++ b/src/chess/bitboard.h @@ -10,20 +10,34 @@ namespace sonic { enum File : std::uint8_t { - FILE_A = 0, FILE_B = 1, FILE_C = 2, FILE_D = 3, - FILE_E = 4, FILE_F = 5, FILE_G = 6, FILE_H = 7 + FILE_A = 0, + FILE_B = 1, + FILE_C = 2, + FILE_D = 3, + FILE_E = 4, + FILE_F = 5, + FILE_G = 6, + FILE_H = 7 }; enum Rank : std::uint8_t { - RANK_1 = 0, RANK_2 = 1, RANK_3 = 2, RANK_4 = 3, - RANK_5 = 4, RANK_6 = 5, RANK_7 = 6, RANK_8 = 7 + RANK_1 = 0, + RANK_2 = 1, + RANK_3 = 2, + RANK_4 = 3, + RANK_5 = 4, + RANK_6 = 5, + RANK_7 = 6, + RANK_8 = 7 }; +// clang-format off #define ENABLE_INCR_DECR_OPERATORS(T) \ constexpr T& operator++(T& d) { return d = T(std::uint8_t(d) + 1); } \ constexpr T& operator--(T& d) { return d = T(std::uint8_t(d) - 1); } \ constexpr T operator++(T& d, int) { T tmp = d; ++d; return tmp; } \ constexpr T operator--(T& d, int) { T tmp = d; --d; return tmp; } \ +// clang-format off ENABLE_INCR_DECR_OPERATORS(File) ENABLE_INCR_DECR_OPERATORS(Rank) @@ -31,197 +45,186 @@ ENABLE_INCR_DECR_OPERATORS(Rank) #undef ENABLE_INCR_DECR_OPERATORS class Square { -public: - constexpr Square() {} - constexpr Square(std::uint8_t num) : square(num) {} - constexpr Square(int row, int col) : square(row * 8 + col) {} - constexpr Square(Rank r, File f) : Square(f, r) {} - constexpr Square(File f, Rank r) : square(static_cast(r) * 8 + static_cast(f)) {} - - static constexpr int SQ_NB = 64; - - constexpr std::uint8_t to_int() const { return square; } - constexpr std::uint64_t to_bb() const { return std::uint64_t(1) << square; } - - std::string to_string() const { - // SQ_NONE - if(square == 255) { - return std::string("(none)"); - } - return std::string(1, 'a' + col()) + std::string(1, '1' + row()); - } - - constexpr int row() const { return square / 8; } - constexpr int col() const { return square % 8; } - - constexpr Rank rank() const { return Rank(row()); } - constexpr File file() const { return File(col()); } - - static bool is_valid(int row, int col) { - return row >= 0 && row < 8 && col >= 0 && col < 8; - } - - static bool is_valid(Square sq) { - return is_valid(sq.row(), sq.col()); - } - - constexpr Square& operator+=(const Direction& d) { - square += int(d); - return *this; - } - - friend constexpr Square operator+(Square sq, const Direction& d) { - return sq += d; - } - - constexpr bool operator==(const Square& other) const { - return square == other.square; - } - - constexpr bool operator!=(const Square& other) const { - return square != other.square; - } - -private: - std::uint8_t square = 0; + public: + constexpr Square() {} + constexpr Square(std::uint8_t num) : + square(num) {} + constexpr Square(int row, int col) : + square(row * 8 + col) {} + constexpr Square(Rank r, File f) : + Square(f, r) {} + constexpr Square(File f, Rank r) : + square(static_cast(r) * 8 + static_cast(f)) {} + + static constexpr int SQ_NB = 64; + + constexpr std::uint8_t to_int() const { return square; } + constexpr std::uint64_t to_bb() const { return std::uint64_t(1) << square; } + + std::string to_string() const { + // SQ_NONE + if (square == 255) { + return std::string("(none)"); + } + return std::string(1, 'a' + col()) + std::string(1, '1' + row()); + } + + constexpr int row() const { return square / 8; } + constexpr int col() const { return square % 8; } + + constexpr Rank rank() const { return Rank(row()); } + constexpr File file() const { return File(col()); } + + static bool is_valid(int row, int col) { return row >= 0 && row < 8 && col >= 0 && col < 8; } + + static bool is_valid(Square sq) { return is_valid(sq.row(), sq.col()); } + + constexpr Square& operator+=(const Direction& d) { + square += int(d); + return *this; + } + + friend constexpr Square operator+(Square sq, const Direction& d) { return sq += d; } + + constexpr bool operator==(const Square& other) const { return square == other.square; } + + constexpr bool operator!=(const Square& other) const { return square != other.square; } + + private: + std::uint8_t square = 0; }; class Bitboard { -public: - constexpr Bitboard() {} - constexpr Bitboard(std::uint64_t bb) : board(bb) {} - - constexpr std::uint64_t to_int() const { return board; } - - constexpr int count() const { return popcount(board); } - - // Set the given square to 1. - void set(Square sq) { set(sq.to_int()); } - void set(std::uint8_t pos) { board |= std::uint64_t(1) << pos; } - void set(int row, int col) { set(Square(row, col)); } - - // Set the given square to 0. - void reset(Square sq) { reset(sq.to_int()); } - void reset(std::uint8_t pos) { board &= ~(std::uint64_t(1) << pos); } - void reset(int row, int col) { reset(Square(row, col)); } - - // Get the value of a square. - bool get(Square sq) const { return get(sq.to_int()); } - bool get(std::uint8_t pos) const { return (board >> pos) & 1; } - bool get(int row, int col) const { return get(Square(row, col)); } - - constexpr bool empty() const { return board == 0; } - constexpr bool any() const { return board != 0; } - - std::string to_string() const { - std::ostringstream os; - for(int row = 7; row >= 0; row--) { - for(int col = 0; col < 8; col++) { - os << ".X"[get(row, col)]; - } - os << "\n"; - } - return os.str(); - } - - struct iterator { - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = Square; - using pointer = Square*; - using reference = Square&; - - iterator(std::uint64_t bb) : bitboard(bb), sq(lsb(bb)) {} - - iterator& operator++() { - bitboard &= (bitboard - 1); - sq = Square(lsb(bitboard)); - return *this; - } - - iterator operator++(int) { - iterator tmp(*this); - ++(*this); - return tmp; - } - - reference operator*() { - return sq; - } - - pointer operator->() { - return &sq; - } - - bool operator==(const iterator& other) const { return bitboard == other.bitboard; } - bool operator!=(const iterator& other) const { return bitboard != other.bitboard; } - - std::uint64_t bitboard; - Square sq; - }; - - iterator begin() const { return iterator(board); } - iterator end() const { return iterator(0); } - - constexpr bool operator==(const Bitboard& other) const { - return board == other.board; - } - - constexpr bool operator!=(const Bitboard& other) const { - return board != other.board; - } - - constexpr Bitboard& operator&=(const Bitboard& bb) { - board &= bb.board; - return *this; - } - - friend constexpr Bitboard operator&(const Bitboard& a, const Bitboard& b) { - return Bitboard(a.board & b.board); - } - - friend constexpr Bitboard operator|(const Bitboard& a, const Bitboard& b) { - return Bitboard(a.board | b.board); - } - - friend constexpr Bitboard operator+(const Bitboard& a, const Square& b) { - return Bitboard(a.board | b.to_bb()); - } - - friend constexpr Bitboard operator-(const Bitboard& a, const Square& b) { - return Bitboard(a.board & ~b.to_bb()); - } - - constexpr Bitboard& operator+=(const Bitboard& b) { - board |= b.board; - return *this; - } - - constexpr Bitboard& operator+=(const Square& b) { - board |= std::uint64_t(1) << b.to_int(); - return *this; - } - - constexpr Bitboard& operator-=(const Bitboard& b) { - board &= ~b.board; - return *this; - } - - constexpr Bitboard& operator-=(const Square& b) { - board &= ~(std::uint64_t(1) << b.to_int()); - return *this; - } - - friend constexpr Bitboard operator+(const Bitboard& a, const Bitboard& b) { - return Bitboard(a.board | b.board); - } - - friend constexpr Bitboard operator-(const Bitboard& a, const Bitboard& b) { - return Bitboard(a.board & ~b.board); - } - -private: - std::uint64_t board = 0; + public: + constexpr Bitboard() {} + constexpr Bitboard(std::uint64_t bb) : + board(bb) {} + + constexpr std::uint64_t to_int() const { return board; } + + constexpr int count() const { return popcount(board); } + + // Set the given square to 1. + void set(Square sq) { set(sq.to_int()); } + void set(std::uint8_t pos) { board |= std::uint64_t(1) << pos; } + void set(int row, int col) { set(Square(row, col)); } + + // Set the given square to 0. + void reset(Square sq) { reset(sq.to_int()); } + void reset(std::uint8_t pos) { board &= ~(std::uint64_t(1) << pos); } + void reset(int row, int col) { reset(Square(row, col)); } + + // Get the value of a square. + bool get(Square sq) const { return get(sq.to_int()); } + bool get(std::uint8_t pos) const { return (board >> pos) & 1; } + bool get(int row, int col) const { return get(Square(row, col)); } + + constexpr bool empty() const { return board == 0; } + constexpr bool any() const { return board != 0; } + + std::string to_string() const { + std::ostringstream os; + for (int row = 7; row >= 0; row--) { + for (int col = 0; col < 8; col++) { + os << ".X"[get(row, col)]; + } + os << "\n"; + } + return os.str(); + } + + struct iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = Square; + using pointer = Square*; + using reference = Square&; + + iterator(std::uint64_t bb) : + bitboard(bb), + sq(lsb(bb)) {} + + iterator& operator++() { + bitboard &= (bitboard - 1); + sq = Square(lsb(bitboard)); + return *this; + } + + iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + + reference operator*() { return sq; } + + pointer operator->() { return &sq; } + + bool operator==(const iterator& other) const { return bitboard == other.bitboard; } + bool operator!=(const iterator& other) const { return bitboard != other.bitboard; } + + std::uint64_t bitboard; + Square sq; + }; + + iterator begin() const { return iterator(board); } + iterator end() const { return iterator(0); } + + constexpr bool operator==(const Bitboard& other) const { return board == other.board; } + + constexpr bool operator!=(const Bitboard& other) const { return board != other.board; } + + constexpr Bitboard& operator&=(const Bitboard& bb) { + board &= bb.board; + return *this; + } + + friend constexpr Bitboard operator&(const Bitboard& a, const Bitboard& b) { + return Bitboard(a.board & b.board); + } + + friend constexpr Bitboard operator|(const Bitboard& a, const Bitboard& b) { + return Bitboard(a.board | b.board); + } + + friend constexpr Bitboard operator+(const Bitboard& a, const Square& b) { + return Bitboard(a.board | b.to_bb()); + } + + friend constexpr Bitboard operator-(const Bitboard& a, const Square& b) { + return Bitboard(a.board & ~b.to_bb()); + } + + constexpr Bitboard& operator+=(const Bitboard& b) { + board |= b.board; + return *this; + } + + constexpr Bitboard& operator+=(const Square& b) { + board |= std::uint64_t(1) << b.to_int(); + return *this; + } + + constexpr Bitboard& operator-=(const Bitboard& b) { + board &= ~b.board; + return *this; + } + + constexpr Bitboard& operator-=(const Square& b) { + board &= ~(std::uint64_t(1) << b.to_int()); + return *this; + } + + friend constexpr Bitboard operator+(const Bitboard& a, const Bitboard& b) { + return Bitboard(a.board | b.board); + } + + friend constexpr Bitboard operator-(const Bitboard& a, const Bitboard& b) { + return Bitboard(a.board & ~b.board); + } + + private: + std::uint64_t board = 0; }; } // namespace sonic \ No newline at end of file diff --git a/src/chess/castling.h b/src/chess/castling.h index 6eaeaed..0037b66 100644 --- a/src/chess/castling.h +++ b/src/chess/castling.h @@ -10,78 +10,78 @@ namespace sonic { class Castling { -public: - static constexpr Bitboard WHITE_00_PATH_BB = Bitboard() + SQ_E1 + SQ_F1 + SQ_G1; - static constexpr Bitboard WHITE_000_PATH_BB = Bitboard() + SQ_C1 + SQ_D1 + SQ_E1; - static constexpr Bitboard BLACK_00_PATH_BB = Bitboard() + SQ_E8 + SQ_F8 + SQ_G8; - static constexpr Bitboard BLACK_000_PATH_BB = Bitboard() + SQ_C8 + SQ_D8 + SQ_E8; - static constexpr Square WHITE_000_EXTRA_SQ = SQ_B1; - static constexpr Square BLACK_000_EXTRA_SQ = SQ_B8; + public: + static constexpr Bitboard WHITE_00_PATH_BB = Bitboard() + SQ_E1 + SQ_F1 + SQ_G1; + static constexpr Bitboard WHITE_000_PATH_BB = Bitboard() + SQ_C1 + SQ_D1 + SQ_E1; + static constexpr Bitboard BLACK_00_PATH_BB = Bitboard() + SQ_E8 + SQ_F8 + SQ_G8; + static constexpr Bitboard BLACK_000_PATH_BB = Bitboard() + SQ_C8 + SQ_D8 + SQ_E8; + static constexpr Square WHITE_000_EXTRA_SQ = SQ_B1; + static constexpr Square BLACK_000_EXTRA_SQ = SQ_B8; - static constexpr Move WHITE_00_MOVE = Move(SQ_E1, SQ_G1); - static constexpr Move WHITE_000_MOVE = Move(SQ_E1, SQ_C1); - static constexpr Move BLACK_00_MOVE = Move(SQ_E8, SQ_G8); - static constexpr Move BLACK_000_MOVE = Move(SQ_E8, SQ_C8); - - static constexpr Move WHITE_00_ROOK_MOVE = Move(SQ_H1, SQ_F1); - static constexpr Move WHITE_000_ROOK_MOVE = Move(SQ_A1, SQ_D1); - static constexpr Move BLACK_00_ROOK_MOVE = Move(SQ_H8, SQ_F8); - static constexpr Move BLACK_000_ROOK_MOVE = Move(SQ_A8, SQ_D8); + static constexpr Move WHITE_00_MOVE = Move(SQ_E1, SQ_G1); + static constexpr Move WHITE_000_MOVE = Move(SQ_E1, SQ_C1); + static constexpr Move BLACK_00_MOVE = Move(SQ_E8, SQ_G8); + static constexpr Move BLACK_000_MOVE = Move(SQ_E8, SQ_C8); - Castling() = default; + static constexpr Move WHITE_00_ROOK_MOVE = Move(SQ_H1, SQ_F1); + static constexpr Move WHITE_000_ROOK_MOVE = Move(SQ_A1, SQ_D1); + static constexpr Move BLACK_00_ROOK_MOVE = Move(SQ_H8, SQ_F8); + static constexpr Move BLACK_000_ROOK_MOVE = Move(SQ_A8, SQ_D8); - constexpr void set_00(Color c) { data |= (c == Color::WHITE ? 1 : 4); } - constexpr void set_000(Color c) { data |= (c == Color::WHITE ? 2 : 8); } - constexpr void set_white_00() { set_00(Color::WHITE); } - constexpr void set_white_000() { set_000(Color::WHITE); } - constexpr void set_black_00() { set_00(Color::BLACK); } - constexpr void set_black_000() { set_000(Color::BLACK); } - constexpr void set_all() { data = 15; } + Castling() = default; - constexpr void reset_00(Color c) { data &= ~(c == Color::WHITE ? 1 : 4); } - constexpr void reset_000(Color c) { data &= ~(c == Color::WHITE ? 2 : 8); } - constexpr void reset_white_00() { reset_00(Color::WHITE); } - constexpr void reset_white_000() { reset_000(Color::WHITE); } - constexpr void reset_black_00() { reset_00(Color::BLACK); } - constexpr void reset_black_000() { reset_000(Color::BLACK); } - constexpr void reset_all() { data = 0; } + constexpr void set_00(Color c) { data |= (c == Color::WHITE ? 1 : 4); } + constexpr void set_000(Color c) { data |= (c == Color::WHITE ? 2 : 8); } + constexpr void set_white_00() { set_00(Color::WHITE); } + constexpr void set_white_000() { set_000(Color::WHITE); } + constexpr void set_black_00() { set_00(Color::BLACK); } + constexpr void set_black_000() { set_000(Color::BLACK); } + constexpr void set_all() { data = 15; } - constexpr bool can_00(Color c) const { return (data >> (c == Color::WHITE ? 0 : 2)) & 1; } - constexpr bool can_000(Color c) const { return (data >> (c == Color::WHITE ? 1 : 3)) & 1; } - constexpr bool white_can_00() const { return can_00(Color::WHITE); } - constexpr bool white_can_000() const { return can_000(Color::WHITE); } - constexpr bool black_can_00() const { return can_00(Color::BLACK); } - constexpr bool black_can_000() const { return can_000(Color::BLACK); } + constexpr void reset_00(Color c) { data &= ~(c == Color::WHITE ? 1 : 4); } + constexpr void reset_000(Color c) { data &= ~(c == Color::WHITE ? 2 : 8); } + constexpr void reset_white_00() { reset_00(Color::WHITE); } + constexpr void reset_white_000() { reset_000(Color::WHITE); } + constexpr void reset_black_00() { reset_00(Color::BLACK); } + constexpr void reset_black_000() { reset_000(Color::BLACK); } + constexpr void reset_all() { data = 0; } - constexpr bool any() const { return data != 0; } - constexpr bool any(Color c) const { return (data & (c == Color::WHITE ? 3 : 12)) != 0; } + constexpr bool can_00(Color c) const { return (data >> (c == Color::WHITE ? 0 : 2)) & 1; } + constexpr bool can_000(Color c) const { return (data >> (c == Color::WHITE ? 1 : 3)) & 1; } + constexpr bool white_can_00() const { return can_00(Color::WHITE); } + constexpr bool white_can_000() const { return can_000(Color::WHITE); } + constexpr bool black_can_00() const { return can_00(Color::BLACK); } + constexpr bool black_can_000() const { return can_000(Color::BLACK); } + + constexpr bool any() const { return data != 0; } + constexpr bool any(Color c) const { return (data & (c == Color::WHITE ? 3 : 12)) != 0; } std::string to_string() const { - if(!any()) { + if (!any()) { return "-"; } std::string res; - if(white_can_00()) { + if (white_can_00()) { res += "K"; } - if(white_can_000()) { + if (white_can_000()) { res += "Q"; } - if(black_can_00()) { + if (black_can_00()) { res += "k"; } - if(black_can_000()) { + if (black_can_000()) { res += "q"; } return res; } -private: - // Bit 0: White 00 - // Bit 1: White 000 - // Bit 2: Black 00 - // Bit 3: Black 000 - std::uint8_t data = 0; + private: + // Bit 0: White 00 + // Bit 1: White 000 + // Bit 2: Black 00 + // Bit 3: Black 000 + std::uint8_t data = 0; }; } // namespace sonic \ No newline at end of file diff --git a/src/chess/color.h b/src/chess/color.h index e2af513..cbad3e7 100644 --- a/src/chess/color.h +++ b/src/chess/color.h @@ -3,14 +3,12 @@ namespace sonic { enum Color { - WHITE = 0, - BLACK = 1, - COLOR_NB = 2, - COLOR_NONE = 3 + WHITE = 0, + BLACK = 1, + COLOR_NB = 2, + COLOR_NONE = 3 }; -constexpr Color other_color(Color c) { - return c == Color::WHITE ? Color::BLACK : Color::WHITE; -} +constexpr Color other_color(Color c) { return c == Color::WHITE ? Color::BLACK : Color::WHITE; } } // namespace sonic diff --git a/src/chess/move.h b/src/chess/move.h index 171ec0e..0a86dfa 100644 --- a/src/chess/move.h +++ b/src/chess/move.h @@ -10,56 +10,72 @@ namespace sonic { class Move { -public: - enum class Promotion : std::uint8_t { None, Queen, Rook, Bishop, Knight }; + public: + enum class Promotion : std::uint8_t { + None, + Queen, + Rook, + Bishop, + Knight + }; - constexpr Move() = default; - constexpr explicit Move(std::uint16_t num) : data(num) {} - constexpr Move(Square from, Square to) : data(from.to_int() | (to.to_int() << 6)) {} - constexpr Move(Square from, Square to, Promotion promotion) : data(from.to_int() | (to.to_int() << 6) | (static_cast(promotion) << 12)) {} + constexpr Move() = default; + constexpr explicit Move(std::uint16_t num) : + data(num) {} + constexpr Move(Square from, Square to) : + data(from.to_int() | (to.to_int() << 6)) {} + constexpr Move(Square from, Square to, Promotion promotion) : + data(from.to_int() | (to.to_int() << 6) | (static_cast(promotion) << 12)) {} - Square from() const { return Square(data & kFromMask); } - Square to() const { return Square((data & kToMask) >> 6); } - Promotion promotion() const { return Promotion((data & kPromotionMask) >> 12); } + Square from() const { return Square(data & kFromMask); } + Square to() const { return Square((data & kToMask) >> 6); } + Promotion promotion() const { return Promotion((data & kPromotionMask) >> 12); } - void set_from(Square from) { data = (data & ~kFromMask) | from.to_int(); } - void set_to(Square to) { data = (data & ~kToMask) | (to.to_int() << 6); } - void set_promotion(Promotion promotion) { data = (data & ~kPromotionMask) | (static_cast(promotion) << 12); } + void set_from(Square from) { data = (data & ~kFromMask) | from.to_int(); } + void set_to(Square to) { data = (data & ~kToMask) | (to.to_int() << 6); } + void set_promotion(Promotion promotion) { + data = (data & ~kPromotionMask) | (static_cast(promotion) << 12); + } - std::uint16_t to_int() const { return data; } + std::uint16_t to_int() const { return data; } - // Returns the move in UCI format. - std::string to_string() const { - // MOVE_NONE - if(data == 0) { - return "(none)"; - } - std::string res = from().to_string() + to().to_string(); - switch(promotion()) { - case Promotion::None: return res; - case Promotion::Queen: return res + 'q'; - case Promotion::Rook: return res + 'r'; - case Promotion::Bishop: return res + 'b'; - case Promotion::Knight: return res + 'n'; - } - assert(false); - } + // Returns the move in UCI format. + std::string to_string() const { + // MOVE_NONE + if (data == 0) { + return "(none)"; + } + std::string res = from().to_string() + to().to_string(); + switch (promotion()) { + case Promotion::None : + return res; + case Promotion::Queen : + return res + 'q'; + case Promotion::Rook : + return res + 'r'; + case Promotion::Bishop : + return res + 'b'; + case Promotion::Knight : + return res + 'n'; + } + assert(false); + } - constexpr bool operator==(const Move& other) const { return data == other.data; } - constexpr bool operator!=(const Move& other) const { return data != other.data; } + constexpr bool operator==(const Move& other) const { return data == other.data; } + constexpr bool operator!=(const Move& other) const { return data != other.data; } -private: - // bits 0~5 -> from - // bits 6~11 -> to - // bits 12~14 -> promotion - // Null move if all bits are set to 1. - std::uint16_t data = 0; + private: + // bits 0~5 -> from + // bits 6~11 -> to + // bits 12~14 -> promotion + // Null move if all bits are set to 1. + std::uint16_t data = 0; - enum Masks : std::uint16_t { - kFromMask = 0b0000000000111111, - kToMask = 0b0000111111000000, - kPromotionMask = 0b0111000000000000, - }; + enum Masks : std::uint16_t { + kFromMask = 0b0000000000111111, + kToMask = 0b0000111111000000, + kPromotionMask = 0b0111000000000000, + }; }; using MoveList = SmallVector; diff --git a/src/chess/movegen.cpp b/src/chess/movegen.cpp index 8814a4f..9213027 100644 --- a/src/chess/movegen.cpp +++ b/src/chess/movegen.cpp @@ -14,48 +14,51 @@ namespace sonic { template void generate_pawn_moves(const Position& pos, MoveList& movelist) { - const Color& us = pos.side_to_move(); - const Bitboard& other_pieces = pos.pieces(other_color(us)); - const Rank& initial_rank = (us == Color::WHITE ? Rank::RANK_2 : Rank::RANK_7); - const Rank& promotion_rank = (us == Color::WHITE ? Rank::RANK_7 : Rank::RANK_2); + const Color& us = pos.side_to_move(); + const Bitboard& other_pieces = pos.pieces(other_color(us)); + const Rank& initial_rank = (us == Color::WHITE ? Rank::RANK_2 : Rank::RANK_7); + const Rank& promotion_rank = (us == Color::WHITE ? Rank::RANK_7 : Rank::RANK_2); const Direction& pawn_direction = (us == Color::WHITE ? Direction::NORTH : Direction::SOUTH); - Bitboard pawns = pos.pieces(us, PieceType::PAWN); - for(Square pawn : pawns) { - if(pawn.rank() != promotion_rank) { - if constexpr(Type != GenType::CAPTURE) { + Bitboard pawns = pos.pieces(us, PieceType::PAWN); + for (Square pawn : pawns) { + if (pawn.rank() != promotion_rank) { + if constexpr (Type != GenType::CAPTURE) { Square one_step = pawn + pawn_direction; - if(pos.piece_on(one_step) == Piece::NO_PIECE) { + if (pos.piece_on(one_step) == Piece::NO_PIECE) { movelist.emplace_back(pawn, one_step); // Check two steps - if(pawn.rank() == initial_rank) { + if (pawn.rank() == initial_rank) { Square two_step = one_step + pawn_direction; - if(pos.piece_on(two_step) == Piece::NO_PIECE) { + if (pos.piece_on(two_step) == Piece::NO_PIECE) { movelist.emplace_back(pawn, two_step); } } } } - if constexpr(Type != GenType::NON_CAPTURE) { - for(Square to : pawn_attacks[us][pawn.to_int()]) { - if(other_pieces.get(to) || to == pos.en_passant()) { + if constexpr (Type != GenType::NON_CAPTURE) { + for (Square to : pawn_attacks[us][pawn.to_int()]) { + if (other_pieces.get(to) || to == pos.en_passant()) { movelist.emplace_back(pawn, to); } } } } else { // Check promotion - if constexpr(Type != GenType::CAPTURE) { + if constexpr (Type != GenType::CAPTURE) { Square one_step = pawn + pawn_direction; - if(pos.piece_on(one_step) == Piece::NO_PIECE) { - for(Move::Promotion promo : {Move::Promotion::Queen, Move::Promotion::Knight, Move::Promotion::Rook, Move::Promotion::Bishop}) { + if (pos.piece_on(one_step) == Piece::NO_PIECE) { + for (Move::Promotion promo : {Move::Promotion::Queen, Move::Promotion::Knight, + Move::Promotion::Rook, Move::Promotion::Bishop}) { movelist.emplace_back(pawn, one_step, promo); } } } - if constexpr(Type != GenType::NON_CAPTURE) { - for(Square to : pawn_attacks[us][pawn.to_int()]) { - if(other_pieces.get(to)) { - for(Move::Promotion promo : {Move::Promotion::Queen, Move::Promotion::Knight, Move::Promotion::Rook, Move::Promotion::Bishop}) { + if constexpr (Type != GenType::NON_CAPTURE) { + for (Square to : pawn_attacks[us][pawn.to_int()]) { + if (other_pieces.get(to)) { + for (Move::Promotion promo : + {Move::Promotion::Queen, Move::Promotion::Knight, + Move::Promotion::Rook, Move::Promotion::Bishop}) { movelist.emplace_back(pawn, to, promo); } } @@ -63,25 +66,24 @@ void generate_pawn_moves(const Position& pos, MoveList& movelist) { } } } - } template void generate_knight_moves(const Position& pos, MoveList& movelist) { - const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); + const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); const Bitboard& other_pieces = pos.pieces(other_color(pos.side_to_move())); - Bitboard knights = pos.pieces(pos.side_to_move(), PieceType::KNIGHT); - for(Square knight : knights) { + Bitboard knights = pos.pieces(pos.side_to_move(), PieceType::KNIGHT); + for (Square knight : knights) { Bitboard attacks = knight_attacks[knight.to_int()] - my_pieces; - if constexpr(Type != GenType::ALL) { - if constexpr(Type == GenType::CAPTURE) { + if constexpr (Type != GenType::ALL) { + if constexpr (Type == GenType::CAPTURE) { attacks &= other_pieces; } - if constexpr(Type == GenType::NON_CAPTURE) { + if constexpr (Type == GenType::NON_CAPTURE) { attacks -= other_pieces; } } - for(Square to : attacks) { + for (Square to : attacks) { movelist.emplace_back(knight, to); } } @@ -89,22 +91,22 @@ void generate_knight_moves(const Position& pos, MoveList& movelist) { template void generate_bishop_moves(const Position& pos, MoveList& movelist) { - const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); + const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); const Bitboard& other_pieces = pos.pieces(other_color(pos.side_to_move())); - const Bitboard& all_pieces = my_pieces | other_pieces; - Bitboard bishops = pos.pieces(pos.side_to_move(), PieceType::BISHOP); - for(Square bishop : bishops) { + const Bitboard& all_pieces = my_pieces | other_pieces; + Bitboard bishops = pos.pieces(pos.side_to_move(), PieceType::BISHOP); + for (Square bishop : bishops) { Bitboard attacks = bishop_magics[bishop.to_int()](all_pieces); attacks -= my_pieces; - if constexpr(Type != GenType::ALL) { - if constexpr(Type == GenType::CAPTURE) { + if constexpr (Type != GenType::ALL) { + if constexpr (Type == GenType::CAPTURE) { attacks &= other_pieces; } - if constexpr(Type == GenType::NON_CAPTURE) { + if constexpr (Type == GenType::NON_CAPTURE) { attacks -= other_pieces; } } - for(Square to : attacks) { + for (Square to : attacks) { movelist.emplace_back(bishop, to); } } @@ -112,22 +114,22 @@ void generate_bishop_moves(const Position& pos, MoveList& movelist) { template void generate_rook_moves(const Position& pos, MoveList& movelist) { - const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); + const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); const Bitboard& other_pieces = pos.pieces(other_color(pos.side_to_move())); - const Bitboard& all_pieces = my_pieces | other_pieces; - Bitboard rooks = pos.pieces(pos.side_to_move(), PieceType::ROOK); - for(Square rook : rooks) { + const Bitboard& all_pieces = my_pieces | other_pieces; + Bitboard rooks = pos.pieces(pos.side_to_move(), PieceType::ROOK); + for (Square rook : rooks) { Bitboard attacks = rook_magics[rook.to_int()](all_pieces); attacks -= my_pieces; - if constexpr(Type != GenType::ALL) { - if constexpr(Type == GenType::CAPTURE) { + if constexpr (Type != GenType::ALL) { + if constexpr (Type == GenType::CAPTURE) { attacks &= other_pieces; } - if constexpr(Type == GenType::NON_CAPTURE) { + if constexpr (Type == GenType::NON_CAPTURE) { attacks -= other_pieces; } } - for(Square to : attacks) { + for (Square to : attacks) { movelist.emplace_back(rook, to); } } @@ -135,22 +137,23 @@ void generate_rook_moves(const Position& pos, MoveList& movelist) { template void generate_queen_moves(const Position& pos, MoveList& movelist) { - const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); + const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); const Bitboard& other_pieces = pos.pieces(other_color(pos.side_to_move())); - const Bitboard& all_pieces = my_pieces | other_pieces; - Bitboard queens = pos.pieces(pos.side_to_move(), PieceType::QUEEN); - for(Square queen : queens) { - Bitboard attacks = (rook_magics[queen.to_int()](all_pieces) | bishop_magics[queen.to_int()](all_pieces)); + const Bitboard& all_pieces = my_pieces | other_pieces; + Bitboard queens = pos.pieces(pos.side_to_move(), PieceType::QUEEN); + for (Square queen : queens) { + Bitboard attacks = + (rook_magics[queen.to_int()](all_pieces) | bishop_magics[queen.to_int()](all_pieces)); attacks -= my_pieces; - if constexpr(Type != GenType::ALL) { - if constexpr(Type == GenType::CAPTURE) { + if constexpr (Type != GenType::ALL) { + if constexpr (Type == GenType::CAPTURE) { attacks &= other_pieces; } - if constexpr(Type == GenType::NON_CAPTURE) { + if constexpr (Type == GenType::NON_CAPTURE) { attacks -= other_pieces; } } - for(Square to : attacks) { + for (Square to : attacks) { movelist.emplace_back(queen, to); } } @@ -158,95 +161,95 @@ void generate_queen_moves(const Position& pos, MoveList& movelist) { template void generate_king_moves(const Position& pos, MoveList& movelist) { - const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); + const Bitboard& my_pieces = pos.pieces(pos.side_to_move()); const Bitboard& other_pieces = pos.pieces(other_color(pos.side_to_move())); - Square king = pos.king_square(pos.side_to_move()); - Bitboard attacks = king_attacks[king.to_int()] - my_pieces; - if constexpr(Type != GenType::ALL) { - if constexpr(Type == GenType::CAPTURE) { + Square king = pos.king_square(pos.side_to_move()); + Bitboard attacks = king_attacks[king.to_int()] - my_pieces; + if constexpr (Type != GenType::ALL) { + if constexpr (Type == GenType::CAPTURE) { attacks &= other_pieces; } - if constexpr(Type == GenType::NON_CAPTURE) { + if constexpr (Type == GenType::NON_CAPTURE) { attacks -= other_pieces; } } - for(Square to : attacks) { + for (Square to : attacks) { movelist.emplace_back(king, to); } // Check castlings - if constexpr(Type == GenType::CAPTURE) { + if constexpr (Type == GenType::CAPTURE) { return; } - if(pos.side_to_move() == Color::WHITE) { + if (pos.side_to_move() == Color::WHITE) { // White short castle - if(pos.castling_rights().white_can_00()) { + if (pos.castling_rights().white_can_00()) { bool invalid = false; - for(Square sq : Castling::WHITE_00_PATH_BB) { - if(pos.attacks_by(sq, Color::BLACK)) { + for (Square sq : Castling::WHITE_00_PATH_BB) { + if (pos.attacks_by(sq, Color::BLACK)) { invalid = true; break; } - if(sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { + if (sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { invalid = true; break; } } - if(!invalid) { + if (!invalid) { movelist.push_back(Castling::WHITE_00_MOVE); } } // White long castle - if(pos.castling_rights().white_can_000()) { + if (pos.castling_rights().white_can_000()) { bool invalid = (pos.piece_on(Castling::WHITE_000_EXTRA_SQ) != Piece::NO_PIECE); - for(Square sq : Castling::WHITE_000_PATH_BB) { - if(pos.attacks_by(sq, Color::BLACK)) { + for (Square sq : Castling::WHITE_000_PATH_BB) { + if (pos.attacks_by(sq, Color::BLACK)) { invalid = true; break; } - if(sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { + if (sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { invalid = true; break; } } - if(!invalid) { + if (!invalid) { movelist.push_back(Castling::WHITE_000_MOVE); } } } else { // Black short castle - if(pos.castling_rights().black_can_00()) { + if (pos.castling_rights().black_can_00()) { bool invalid = false; - for(Square sq : Castling::BLACK_00_PATH_BB) { - if(pos.attacks_by(sq, Color::WHITE)) { + for (Square sq : Castling::BLACK_00_PATH_BB) { + if (pos.attacks_by(sq, Color::WHITE)) { invalid = true; break; } - if(sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { + if (sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { invalid = true; break; } } - if(!invalid) { + if (!invalid) { movelist.push_back(Castling::BLACK_00_MOVE); } } // Black long castle - if(pos.castling_rights().black_can_000()) { + if (pos.castling_rights().black_can_000()) { bool invalid = (pos.piece_on(Castling::BLACK_000_EXTRA_SQ) != Piece::NO_PIECE); - for(Square sq : Castling::BLACK_000_PATH_BB) { - if(pos.attacks_by(sq, Color::WHITE)) { + for (Square sq : Castling::BLACK_000_PATH_BB) { + if (pos.attacks_by(sq, Color::WHITE)) { invalid = true; break; } - if(sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { + if (sq != king && pos.piece_on(sq) != Piece::NO_PIECE) { invalid = true; break; } } - if(!invalid) { + if (!invalid) { movelist.push_back(Castling::BLACK_000_MOVE); } } diff --git a/src/chess/movegen.h b/src/chess/movegen.h index f5fb23e..8b9475d 100644 --- a/src/chess/movegen.h +++ b/src/chess/movegen.h @@ -18,6 +18,7 @@ enum GenType { // template void generate_rook_moves(const Position& pos, MoveList& movelist); // template void generate_queen_moves(const Position& pos, MoveList& movelist); // template void generate_king_moves(const Position& pos, MoveList& movelist); -template void generate_moves(const Position& pos, MoveList& movelist); +template +void generate_moves(const Position& pos, MoveList& movelist); } // namespace sonic \ No newline at end of file diff --git a/src/chess/piece.h b/src/chess/piece.h index 2c30ad8..7881f60 100644 --- a/src/chess/piece.h +++ b/src/chess/piece.h @@ -7,22 +7,30 @@ namespace sonic { enum PieceType { - PAWN = 0, - KNIGHT = 1, - BISHOP = 2, - ROOK = 3, - QUEEN = 4, - KING = 5, - PIECE_NB = 6, + PAWN = 0, + KNIGHT = 1, + BISHOP = 2, + ROOK = 3, + QUEEN = 4, + KING = 5, + PIECE_NB = 6, NO_PIECE_TYPE = 7 }; enum Piece { - W_PAWN = 0, W_KNIGHT = 1, W_BISHOP = 2, - W_ROOK = 3, W_QUEEN = 4, W_KING = 5, + W_PAWN = 0, + W_KNIGHT = 1, + W_BISHOP = 2, + W_ROOK = 3, + W_QUEEN = 4, + W_KING = 5, - B_PAWN = 0 + 8, B_KNIGHT = 1 + 8, B_BISHOP = 2 + 8, - B_ROOK = 3 + 8, B_QUEEN = 4 + 8, B_KING = 5 + 8, + B_PAWN = 0 + 8, + B_KNIGHT = 1 + 8, + B_BISHOP = 2 + 8, + B_ROOK = 3 + 8, + B_QUEEN = 4 + 8, + B_KING = 5 + 8, NO_PIECE = 7 }; @@ -32,28 +40,39 @@ constexpr Color color(Piece p) { return p < 8 ? Color::WHITE : Color::BLACK; } -constexpr PieceType type(Piece p) { - return PieceType(p & 7); -} +constexpr PieceType type(Piece p) { return PieceType(p & 7); } constexpr char to_char(Piece p) { - switch(p) { - case Piece::W_PAWN: return 'P'; - case Piece::W_ROOK: return 'R'; - case Piece::W_KNIGHT: return 'N'; - case Piece::W_BISHOP: return 'B'; - case Piece::W_QUEEN: return 'Q'; - case Piece::W_KING: return 'K'; - - case Piece::B_PAWN: return 'p'; - case Piece::B_ROOK: return 'r'; - case Piece::B_KNIGHT: return 'n'; - case Piece::B_BISHOP: return 'b'; - case Piece::B_QUEEN: return 'q'; - case Piece::B_KING: return 'k'; - - default: return ' '; - } + switch (p) { + case Piece::W_PAWN : + return 'P'; + case Piece::W_ROOK : + return 'R'; + case Piece::W_KNIGHT : + return 'N'; + case Piece::W_BISHOP : + return 'B'; + case Piece::W_QUEEN : + return 'Q'; + case Piece::W_KING : + return 'K'; + + case Piece::B_PAWN : + return 'p'; + case Piece::B_ROOK : + return 'r'; + case Piece::B_KNIGHT : + return 'n'; + case Piece::B_BISHOP : + return 'b'; + case Piece::B_QUEEN : + return 'q'; + case Piece::B_KING : + return 'k'; + + default : + return ' '; + } } } // namespace sonic \ No newline at end of file diff --git a/src/chess/position.cpp b/src/chess/position.cpp index ae40f88..1c83e5e 100644 --- a/src/chess/position.cpp +++ b/src/chess/position.cpp @@ -28,28 +28,52 @@ void Position::set(std::string fen) { // 1. Piece placement clear_board(); Square sq = SQ_A8; - for(char c : tokens[0]) { - if(isdigit(c)) { + for (char c : tokens[0]) { + if (isdigit(c)) { sq += (c - '0') * Direction::EAST; - } else if(c == '/') { + } else if (c == '/') { sq += 8 * Direction::WEST; sq += Direction::SOUTH; } else { Piece p = Piece::NO_PIECE; - switch(c) { - case 'P': p = Piece::W_PAWN; break; - case 'R': p = Piece::W_ROOK; break; - case 'N': p = Piece::W_KNIGHT; break; - case 'B': p = Piece::W_BISHOP; break; - case 'Q': p = Piece::W_QUEEN; break; - case 'K': p = Piece::W_KING; break; - - case 'p': p = Piece::B_PAWN; break; - case 'r': p = Piece::B_ROOK; break; - case 'n': p = Piece::B_KNIGHT; break; - case 'b': p = Piece::B_BISHOP; break; - case 'q': p = Piece::B_QUEEN; break; - case 'k': p = Piece::B_KING; break; + switch (c) { + case 'P' : + p = Piece::W_PAWN; + break; + case 'R' : + p = Piece::W_ROOK; + break; + case 'N' : + p = Piece::W_KNIGHT; + break; + case 'B' : + p = Piece::W_BISHOP; + break; + case 'Q' : + p = Piece::W_QUEEN; + break; + case 'K' : + p = Piece::W_KING; + break; + + case 'p' : + p = Piece::B_PAWN; + break; + case 'r' : + p = Piece::B_ROOK; + break; + case 'n' : + p = Piece::B_KNIGHT; + break; + case 'b' : + p = Piece::B_BISHOP; + break; + case 'q' : + p = Piece::B_QUEEN; + break; + case 'k' : + p = Piece::B_KING; + break; } assert(p != Piece::NO_PIECE); add_piece(sq, p); @@ -63,14 +87,14 @@ void Position::set(std::string fen) { // 3. Castling rights castlings.reset_all(); - for(char c : tokens[2]) { - if(c == 'K') { + for (char c : tokens[2]) { + if (c == 'K') { castlings.set_white_00(); - } else if(c == 'Q') { + } else if (c == 'Q') { castlings.set_white_000(); - } else if(c == 'k') { + } else if (c == 'k') { castlings.set_black_00(); - } else if(c == 'q') { + } else if (c == 'q') { castlings.set_black_000(); } } @@ -81,22 +105,22 @@ void Position::set(std::string fen) { key ^= (has_en_passant_capture() * zobrist_key(enPassant)); // 5-6. ply - rule50 = std::stoi(tokens[4]); + rule50 = std::stoi(tokens[4]); gamePly = std::max(2 * std::stoi(tokens[5]) - 2, 0) + (sideToMove == Color::BLACK); } // Returns the FEN representation of the position as a string. std::string Position::fen() const { std::ostringstream os; - Square sq = SQ_A8; - for(int i = 0; i < 8; i++) { + Square sq = SQ_A8; + for (int i = 0; i < 8; i++) { int empty_count = 0; - for(int j = 0; j < 8; j++) { + for (int j = 0; j < 8; j++) { Piece p = piece_on(sq); - if(p == Piece::NO_PIECE) { + if (p == Piece::NO_PIECE) { empty_count++; } else { - if(empty_count > 0) { + if (empty_count > 0) { os << empty_count; empty_count = 0; } @@ -104,12 +128,12 @@ std::string Position::fen() const { } sq += Direction::EAST; } - if(empty_count > 0) { + if (empty_count > 0) { os << empty_count; } sq += 8 * Direction::WEST; sq += Direction::SOUTH; - if(i + 1 < 8) { + if (i + 1 < 8) { os << "/"; } } @@ -123,31 +147,31 @@ std::string Position::fen() const { // Returns if `sq` is being attacked by `c`. Doesn't consider en passant. bool Position::attacks_by(Square sq, Color c) const { // Check knight attacks - if((knight_attacks[sq.to_int()] & pieces(c, PieceType::KNIGHT)).any()) { + if ((knight_attacks[sq.to_int()] & pieces(c, PieceType::KNIGHT)).any()) { return true; } - const Bitboard& c_pieces = pieces(c); + const Bitboard& c_pieces = pieces(c); const Bitboard& all_pieces = c_pieces | pieces(other_color(c)); // Check rook + queen attacks const Bitboard& c_rook_and_queen = pieces(c, PieceType::ROOK) | pieces(c, PieceType::QUEEN); - const Bitboard& rook_attacks = rook_magics[sq.to_int()](all_pieces); - if((rook_attacks & c_rook_and_queen).any()) { + const Bitboard& rook_attacks = rook_magics[sq.to_int()](all_pieces); + if ((rook_attacks & c_rook_and_queen).any()) { return true; } // Check bishop + queen attacks const Bitboard& c_bishop_and_queen = pieces(c, PieceType::BISHOP) | pieces(c, PieceType::QUEEN); - const Bitboard& bishop_attacks = bishop_magics[sq.to_int()](all_pieces); - if((bishop_attacks & c_bishop_and_queen).any()) { + const Bitboard& bishop_attacks = bishop_magics[sq.to_int()](all_pieces); + if ((bishop_attacks & c_bishop_and_queen).any()) { return true; } // Check pawn attacks const Bitboard& c_pawns = pieces(c, PieceType::PAWN); - if((pawn_attacks[other_color(c)][sq.to_int()] & c_pawns).any()) { + if ((pawn_attacks[other_color(c)][sq.to_int()] & c_pawns).any()) { return true; } // Check king attacks const Bitboard& c_king = pieces(c, PieceType::KING); - if((king_attacks[sq.to_int()] & c_king).any()) { + if ((king_attacks[sq.to_int()] & c_king).any()) { return true; } return false; @@ -155,119 +179,130 @@ bool Position::attacks_by(Square sq, Color c) const { // Apply a move on the board and returns true if the given move is legal. bool Position::make_move(Move m, UndoInfo& info) { - info.last_move = m; - info.rule50 = rule50; - info.history_count = history_count; + info.last_move = m; + info.rule50 = rule50; + info.history_count = history_count; info.castling_state = castlings; - info.en_passant = enPassant; + info.en_passant = enPassant; info.captured_piece = Piece::NO_PIECE; - info.key = key; + info.key = key; history_keys[history_count] = key; history_count++; gamePly++; rule50++; - key ^= zobrist_key(castlings) ^ zobrist_key(sideToMove) ^ (has_en_passant_capture() * zobrist_key(enPassant)); + key ^= zobrist_key(castlings) ^ zobrist_key(sideToMove) + ^ (has_en_passant_capture() * zobrist_key(enPassant)); - Color us = sideToMove; + Color us = sideToMove; Color them = other_color(sideToMove); sideToMove = them; - Square from = m.from(); - Square to = m.to(); - Piece p = piece_on(from); - PieceType pt = type(p); + Square from = m.from(); + Square to = m.to(); + Piece p = piece_on(from); + PieceType pt = type(p); assert(to != king_square(them)); // Reset castlings when rook moves or rook was captured. - if(from == SQ_H1 || to == SQ_H1) { + if (from == SQ_H1 || to == SQ_H1) { castlings.reset_white_00(); } - if(from == SQ_A1 || to == SQ_A1) { + if (from == SQ_A1 || to == SQ_A1) { castlings.reset_white_000(); } - if(from == SQ_H8 || to == SQ_H8) { + if (from == SQ_H8 || to == SQ_H8) { castlings.reset_black_00(); } - if(from == SQ_A8 || to == SQ_A8) { + if (from == SQ_A8 || to == SQ_A8) { castlings.reset_black_000(); } - if(pt == PieceType::KING) { + if (pt == PieceType::KING) { castlings.reset_00(us); castlings.reset_000(us); } - if(piece_on(to) != Piece::NO_PIECE) { + if (piece_on(to) != Piece::NO_PIECE) { // Reset rule50 when captures. info.captured_piece = piece_on(to); - rule50 = 0; - history_count = 0; + rule50 = 0; + history_count = 0; remove_piece(to); } remove_piece(from); add_piece(to, p); - if(pt == PieceType::PAWN) { - rule50 = 0; + if (pt == PieceType::PAWN) { + rule50 = 0; history_count = 0; // Check if the move is an en passant capture. - if(to == enPassant) { + if (to == enPassant) { remove_piece(enPassant + (us == Color::WHITE ? Direction::SOUTH : Direction::NORTH)); } // Update en passant square. enPassant = SQ_NONE; - if(from.rank() == Rank::RANK_2 && to.rank() == Rank::RANK_4) { + if (from.rank() == Rank::RANK_2 && to.rank() == Rank::RANK_4) { enPassant = Square(from.file(), Rank::RANK_3); } - if(from.rank() == Rank::RANK_7 && to.rank() == Rank::RANK_5) { + if (from.rank() == Rank::RANK_7 && to.rank() == Rank::RANK_5) { enPassant = Square(from.file(), Rank::RANK_6); } // Handle promotion. auto promotion = m.promotion(); - if(promotion != Move::Promotion::None) { + if (promotion != Move::Promotion::None) { remove_piece(to); Piece promotion_to = Piece::NO_PIECE; - switch(promotion) { - case Move::Promotion::Queen: promotion_to = (us == Color::WHITE ? Piece::W_QUEEN : Piece::B_QUEEN); break; - case Move::Promotion::Knight: promotion_to = (us == Color::WHITE ? Piece::W_KNIGHT : Piece::B_KNIGHT); break; - case Move::Promotion::Rook: promotion_to = (us == Color::WHITE ? Piece::W_ROOK : Piece::B_ROOK); break; - case Move::Promotion::Bishop: promotion_to = (us == Color::WHITE ? Piece::W_BISHOP : Piece::B_BISHOP); break; - default: break; + switch (promotion) { + case Move::Promotion::Queen : + promotion_to = (us == Color::WHITE ? Piece::W_QUEEN : Piece::B_QUEEN); + break; + case Move::Promotion::Knight : + promotion_to = (us == Color::WHITE ? Piece::W_KNIGHT : Piece::B_KNIGHT); + break; + case Move::Promotion::Rook : + promotion_to = (us == Color::WHITE ? Piece::W_ROOK : Piece::B_ROOK); + break; + case Move::Promotion::Bishop : + promotion_to = (us == Color::WHITE ? Piece::W_BISHOP : Piece::B_BISHOP); + break; + default : + break; } add_piece(to, promotion_to); } } else { enPassant = SQ_NONE; } - - if(pt == PieceType::KING) { + + if (pt == PieceType::KING) { // Check if the move is castling. - if(m == Castling::WHITE_00_MOVE) { + if (m == Castling::WHITE_00_MOVE) { const Move& rook_move = Castling::WHITE_00_ROOK_MOVE; remove_piece(rook_move.from()); add_piece(rook_move.to(), Piece::W_ROOK); - } else if(m == Castling::WHITE_000_MOVE) { + } else if (m == Castling::WHITE_000_MOVE) { const Move& rook_move = Castling::WHITE_000_ROOK_MOVE; remove_piece(rook_move.from()); add_piece(rook_move.to(), Piece::W_ROOK); - } else if(m == Castling::BLACK_00_MOVE) { + } else if (m == Castling::BLACK_00_MOVE) { const Move& rook_move = Castling::BLACK_00_ROOK_MOVE; remove_piece(rook_move.from()); add_piece(rook_move.to(), Piece::B_ROOK); - } else if(m == Castling::BLACK_000_MOVE) { + } else if (m == Castling::BLACK_000_MOVE) { const Move& rook_move = Castling::BLACK_000_ROOK_MOVE; remove_piece(rook_move.from()); add_piece(rook_move.to(), Piece::B_ROOK); } } - key ^= zobrist_key(castlings) ^ zobrist_key(sideToMove) ^ (has_en_passant_capture() * zobrist_key(enPassant)); + key ^= zobrist_key(castlings) ^ zobrist_key(sideToMove) + ^ (has_en_passant_capture() * zobrist_key(enPassant)); return !attacks_by(king_square(us), them); } @@ -277,37 +312,38 @@ void Position::unmake_move(const UndoInfo& info) { remove_piece(info.last_move.to()); // Check promotion. - if(info.last_move.promotion() != Move::Promotion::None) { + if (info.last_move.promotion() != Move::Promotion::None) { moved_piece = (sideToMove == Color::WHITE ? Piece::B_PAWN : Piece::W_PAWN); } add_piece(info.last_move.from(), moved_piece); // Check captures. - if(info.captured_piece != Piece::NO_PIECE) { + if (info.captured_piece != Piece::NO_PIECE) { add_piece(info.last_move.to(), info.captured_piece); } // Check en passant. - if(type(moved_piece) == PieceType::PAWN && info.last_move.to() == info.en_passant) { + if (type(moved_piece) == PieceType::PAWN && info.last_move.to() == info.en_passant) { Direction d = (sideToMove == Color::WHITE ? Direction::NORTH : Direction::SOUTH); - add_piece(info.last_move.to() + d, sideToMove == Color::WHITE ? Piece::W_PAWN : Piece::B_PAWN); + add_piece(info.last_move.to() + d, + sideToMove == Color::WHITE ? Piece::W_PAWN : Piece::B_PAWN); } // Check castling. - if(type(moved_piece) == PieceType::KING) { - if(info.last_move == Castling::WHITE_00_MOVE) { + if (type(moved_piece) == PieceType::KING) { + if (info.last_move == Castling::WHITE_00_MOVE) { const Move& rook_move = Castling::WHITE_00_ROOK_MOVE; remove_piece(rook_move.to()); add_piece(rook_move.from(), Piece::W_ROOK); - } else if(info.last_move == Castling::WHITE_000_MOVE) { + } else if (info.last_move == Castling::WHITE_000_MOVE) { const Move& rook_move = Castling::WHITE_000_ROOK_MOVE; remove_piece(rook_move.to()); add_piece(rook_move.from(), Piece::W_ROOK); - } else if(info.last_move == Castling::BLACK_00_MOVE) { + } else if (info.last_move == Castling::BLACK_00_MOVE) { const Move& rook_move = Castling::BLACK_00_ROOK_MOVE; remove_piece(rook_move.to()); add_piece(rook_move.from(), Piece::B_ROOK); - } else if(info.last_move == Castling::BLACK_000_MOVE) { + } else if (info.last_move == Castling::BLACK_000_MOVE) { const Move& rook_move = Castling::BLACK_000_ROOK_MOVE; remove_piece(rook_move.to()); add_piece(rook_move.from(), Piece::B_ROOK); @@ -315,23 +351,23 @@ void Position::unmake_move(const UndoInfo& info) { } // Restore states. - castlings = info.castling_state; - enPassant = info.en_passant; - rule50 = info.rule50; + castlings = info.castling_state; + enPassant = info.en_passant; + rule50 = info.rule50; history_count = info.history_count; - key = info.key; + key = info.key; gamePly--; sideToMove = other_color(sideToMove); } void Position::make_null_move(UndoInfo& info) { - info.last_move = MOVE_NONE; - info.rule50 = rule50; - info.history_count = history_count; - info.castling_state = castlings; - info.en_passant = enPassant; - info.captured_piece = Piece::NO_PIECE; - info.key = key; + info.last_move = MOVE_NONE; + info.rule50 = rule50; + info.history_count = history_count; + info.castling_state = castlings; + info.en_passant = enPassant; + info.captured_piece = Piece::NO_PIECE; + info.key = key; history_keys[history_count] = key; history_count++; rule50++; @@ -347,11 +383,11 @@ void Position::make_null_move(UndoInfo& info) { } void Position::unmake_null_move(const UndoInfo& info) { - rule50 = info.rule50; + rule50 = info.rule50; history_count = info.history_count; - castlings = info.castling_state; - enPassant = info.en_passant; - key = info.key; + castlings = info.castling_state; + enPassant = info.en_passant; + key = info.key; gamePly--; sideToMove = other_color(sideToMove); } @@ -361,8 +397,8 @@ std::string Position::to_string() const { std::ostringstream os; os << "\n +---+---+---+---+---+---+---+---+\n"; Square sq = SQ_A8; - for(int i = 0; i < 8; i++) { - for(int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { os << " | " << to_char(piece_on(sq)); sq += Direction::EAST; } diff --git a/src/chess/position.h b/src/chess/position.h index 514bbfb..a3bd559 100644 --- a/src/chess/position.h +++ b/src/chess/position.h @@ -15,21 +15,22 @@ namespace sonic { struct UndoInfo { - Move last_move; - Castling castling_state; - Square en_passant; - Piece captured_piece; - int rule50; - int history_count; + Move last_move; + Castling castling_state; + Square en_passant; + Piece captured_piece; + int rule50; + int history_count; std::uint64_t key; }; class Position { -public: - Position() : Position(INITIAL_FEN) {} - Position(const std::string& fen) { set(fen); } + public: + Position() : + Position(INITIAL_FEN) {} + Position(const std::string& fen) { set(fen); } - void set(std::string fen); + void set(std::string fen); // Returns the FEN representation of the position as a string. std::string fen() const; @@ -37,10 +38,10 @@ class Position { // Returns the zobrist hash key of the current position. constexpr std::uint64_t hashkey() const { return key; } - constexpr Color side_to_move() const { return sideToMove; } - constexpr Square en_passant() const { return enPassant; } - constexpr int game_ply() const { return gamePly; } - constexpr int rule50_ply() const { return rule50; } + constexpr Color side_to_move() const { return sideToMove; } + constexpr Square en_passant() const { return enPassant; } + constexpr int game_ply() const { return gamePly; } + constexpr int rule50_ply() const { return rule50; } constexpr Castling castling_rights() const { return castlings; } // Returns the square that the king in at. @@ -49,29 +50,25 @@ class Position { return Square(lsb(raw)); } - bool in_check() const { - return attacks_by(king_square(sideToMove), other_color(sideToMove)); - } + bool in_check() const { return attacks_by(king_square(sideToMove), other_color(sideToMove)); } bool is_capture(Move m) const { const Square& to = m.to(); return piece_on(to) != Piece::NO_PIECE || to == enPassant; } - bool is_quiet(Move m) const { - return !is_capture(m) && m.promotion() == Move::Promotion::None; - } + bool is_quiet(Move m) const { return !is_capture(m) && m.promotion() == Move::Promotion::None; } bool has_en_passant_capture() const { - if(enPassant == SQ_NONE) { + if (enPassant == SQ_NONE) { return false; } Piece my_pawn = (sideToMove == Color::WHITE ? Piece::W_PAWN : Piece::B_PAWN); - bool result = false; - if(enPassant.file() != File::FILE_A) { + bool result = false; + if (enPassant.file() != File::FILE_A) { result = result || piece_on(enPassant + Direction::WEST) == my_pawn; } - if(enPassant.file() != File::FILE_H) { + if (enPassant.file() != File::FILE_H) { result = result || piece_on(enPassant + Direction::EAST) == my_pawn; } return result; @@ -79,16 +76,14 @@ class Position { constexpr Bitboard pieces(Color c) const { return pieceBB[c][PieceType::PAWN] | pieceBB[c][PieceType::KNIGHT] - | pieceBB[c][PieceType::BISHOP] | pieceBB[c][PieceType::ROOK] - | pieceBB[c][PieceType::QUEEN] | pieceBB[c][PieceType::KING]; + | pieceBB[c][PieceType::BISHOP] | pieceBB[c][PieceType::ROOK] + | pieceBB[c][PieceType::QUEEN] | pieceBB[c][PieceType::KING]; } constexpr Bitboard pieces(Color c, PieceType pt) const { return pieceBB[c][pt]; } // Returns the piece on `sq`. - constexpr Piece piece_on(Square sq) const { - return board[sq.to_int()]; - } + constexpr Piece piece_on(Square sq) const { return board[sq.to_int()]; } // Returns if `sq` is being attacked by `c`. Doesn't consider en passant. bool attacks_by(Square sq, Color c) const; @@ -107,8 +102,8 @@ class Position { // Check if the current position occurs before. bool is_repetition() const { - for(int i = 2; i < std::min(history_count, rule50); i += 2) { - if(history_keys[history_count - i] == key) { + for (int i = 2; i < std::min(history_count, rule50); i += 2) { + if (history_keys[history_count - i] == key) { return true; } } @@ -117,35 +112,35 @@ class Position { // Check if insufficient mating material. constexpr bool insufficient_material() const { - if(pieceBB[Color::WHITE][PieceType::PAWN].any() || pieceBB[Color::WHITE][PieceType::KNIGHT].count() > 1 || - pieceBB[Color::WHITE][PieceType::BISHOP].count() > 1 || pieceBB[Color::WHITE][PieceType::ROOK].any() || - pieceBB[Color::WHITE][PieceType::QUEEN].any() - ) { + if (pieceBB[Color::WHITE][PieceType::PAWN].any() + || pieceBB[Color::WHITE][PieceType::KNIGHT].count() > 1 + || pieceBB[Color::WHITE][PieceType::BISHOP].count() > 1 + || pieceBB[Color::WHITE][PieceType::ROOK].any() + || pieceBB[Color::WHITE][PieceType::QUEEN].any()) { return false; } - if(pieceBB[Color::BLACK][PieceType::PAWN].any() || pieceBB[Color::BLACK][PieceType::KNIGHT].count() > 1 || - pieceBB[Color::BLACK][PieceType::BISHOP].count() > 1 || pieceBB[Color::BLACK][PieceType::ROOK].any() || - pieceBB[Color::BLACK][PieceType::QUEEN].any() - ) { + if (pieceBB[Color::BLACK][PieceType::PAWN].any() + || pieceBB[Color::BLACK][PieceType::KNIGHT].count() > 1 + || pieceBB[Color::BLACK][PieceType::BISHOP].count() > 1 + || pieceBB[Color::BLACK][PieceType::ROOK].any() + || pieceBB[Color::BLACK][PieceType::QUEEN].any()) { return false; } return true; } - bool is_draw() const { - return rule50 >= 100 || is_repetition() || insufficient_material(); - } + bool is_draw() const { return rule50 >= 100 || is_repetition() || insufficient_material(); } // Visualize the current position. std::string to_string() const; -private: + private: void clear_board() { - for(int i = 0; i < Square::SQ_NB; i++) { + for (int i = 0; i < Square::SQ_NB; i++) { board[i] = Piece::NO_PIECE; } - for(int i = 0; i < Color::COLOR_NB; i++) { - for(int j = 0; j < PieceType::PIECE_NB; j++) { + for (int i = 0; i < Color::COLOR_NB; i++) { + for (int j = 0; j < PieceType::PIECE_NB; j++) { pieceBB[i][j] = Bitboard(0); } } @@ -159,23 +154,23 @@ class Position { void remove_piece(Square sq) { Piece p = board[sq.to_int()]; - if(p != Piece::NO_PIECE) { + if (p != Piece::NO_PIECE) { board[sq.to_int()] = Piece::NO_PIECE; pieceBB[color(p)][type(p)] -= sq; key ^= zobrist_key(sq, p); } } - Color sideToMove; - Piece board[Square::SQ_NB]; - Bitboard pieceBB[Color::COLOR_NB][PieceType::PIECE_NB]; - int gamePly; - int rule50; - Castling castlings; - Square enPassant; - std::uint64_t key; + Color sideToMove; + Piece board[Square::SQ_NB]; + Bitboard pieceBB[Color::COLOR_NB][PieceType::PIECE_NB]; + int gamePly; + int rule50; + Castling castlings; + Square enPassant; + std::uint64_t key; std::array history_keys = {}; - int history_count; + int history_count; }; } // namespace sonic \ No newline at end of file diff --git a/src/chess/zobrist.h b/src/chess/zobrist.h index 44ec1b4..9cae220 100644 --- a/src/chess/zobrist.h +++ b/src/chess/zobrist.h @@ -211,30 +211,29 @@ constexpr std::uint64_t ZobristKeys[781] = { 0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL, 0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL, 0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL, 0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL, - 0xF8D626AAAF278509ULL -}; - + 0xF8D626AAAF278509ULL}; + constexpr std::uint64_t zobrist_key(Square sq, Piece p) { - if(p == Piece::NO_PIECE) { + if (p == Piece::NO_PIECE) { return 0LL; } - int piece_id = (color(p) ^ 1) + type(p) * 2; + int piece_id = (color(p) ^ 1) + type(p) * 2; int sq_offset = 8 * static_cast(sq.rank()) + static_cast(sq.file()); return ZobristKeys[64 * piece_id + sq_offset]; } constexpr std::uint64_t zobrist_key(Castling c) { std::uint64_t key = 0; - if(c.white_can_00()) { + if (c.white_can_00()) { key ^= ZobristKeys[768]; } - if(c.white_can_000()) { + if (c.white_can_000()) { key ^= ZobristKeys[769]; } - if(c.black_can_00()) { + if (c.black_can_00()) { key ^= ZobristKeys[770]; } - if(c.black_can_000()) { + if (c.black_can_000()) { key ^= ZobristKeys[771]; } return key; @@ -244,8 +243,6 @@ constexpr std::uint64_t zobrist_key(Square sq) { return sq == SQ_NONE ? 0ULL : ZobristKeys[772 + static_cast(sq.file())]; } -constexpr std::uint64_t zobrist_key(Color c) { - return c == Color::WHITE ? ZobristKeys[780] : 0ULL; -} +constexpr std::uint64_t zobrist_key(Color c) { return c == Color::WHITE ? ZobristKeys[780] : 0ULL; } } // namespace sonic \ No newline at end of file diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 298f879..3664d55 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -6,6 +6,7 @@ namespace sonic { +// clang-format off constexpr std::pair PieceSquareTable[PieceType::PIECE_NB][Square::SQ_NB] = { { // Pawn {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, @@ -58,22 +59,24 @@ constexpr std::pair PieceSquareTable[PieceType::PIECE_NB][Square:: {2560, 2499}, {2560, 2520}, {2560, 2530}, {2560, 2540}, {2560, 2540}, {2560, 2530}, {2560, 2520}, {2560, 2499}, }, { // King - {302, 16}, {328, 78}, {276, 108}, {225, 139}, {225, 139}, {276, 108}, {328, 78}, {302, 16}, - {276, 78}, {302, 139}, {251, 170}, {200, 200}, {200, 200}, {251, 170}, {302, 139}, {276, 78}, + {302, 16}, {328, 78}, {276, 108}, {225, 139}, {225, 139}, {276, 108}, {328, 78}, {302, 16}, + {276, 78}, {302, 139}, {251, 170}, {200, 200}, {200, 200}, {251, 170}, {302, 139}, {276, 78}, {225, 108}, {251, 170}, {200, 200}, {149, 230}, {149, 230}, {200, 200}, {251, 170}, {225, 108}, {200, 139}, {225, 200}, {175, 230}, {124, 261}, {124, 261}, {175, 230}, {225, 200}, {200, 139}, - {175, 139}, {200, 200}, {149, 230}, {98, 261}, {98, 261}, {149, 230}, {200, 200}, {175, 139}, - {149, 108}, {175, 170}, {124, 200}, {72, 230}, {72, 230}, {124, 200}, {175, 170}, {149, 108}, - {124, 78}, {149, 139}, {98, 170}, {47, 200}, {47, 200}, {98, 170}, {149, 139}, {124, 78}, - {98, 16}, {124, 78}, {72, 108}, {21, 139}, {21, 139}, {72, 108}, {124, 78}, {98, 16}, + {175, 139}, {200, 200}, {149, 230}, { 98, 261}, { 98, 261}, {149, 230}, {200, 200}, {175, 139}, + {149, 108}, {175, 170}, {124, 200}, { 72, 230}, { 72, 230}, {124, 200}, {175, 170}, {149, 108}, + {124, 78}, {149, 139}, { 98, 170}, { 47, 200}, { 47, 200}, { 98, 170}, {149, 139}, {124, 78}, + { 98, 16}, {124, 78}, { 72, 108}, { 21, 139}, { 21, 139}, { 72, 108}, {124, 78}, { 98, 16}, }, }; +// clang-format off constexpr std::pair KnightMobilityMult = {6, 6}; constexpr std::pair BishopMobilityMult = {2, 3}; constexpr std::pair RookMobilityMult = {3, 6}; constexpr std::pair QueenMobilityMult = {2, 7}; +// clang-format off constexpr Bitboard PassedPawnMask[Color::COLOR_NB][Square::SQ_NB] = { // White { @@ -98,49 +101,51 @@ constexpr Bitboard PassedPawnMask[Color::COLOR_NB][Square::SQ_NB] = { 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, } }; +// clang-format on Value evaluate(const Position& pos) { static constexpr int PieceTypeValues[] = {1, 3, 3, 5, 9}; - Color us = pos.side_to_move(); - Bitboard white_pieces = pos.pieces(Color::WHITE); - Bitboard black_pieces = pos.pieces(Color::BLACK); - Value mid_game_score = 0; - Value end_game_score = 0; - int phase = 0; - int coeff = 1; - for(Color c : {Color::WHITE, Color::BLACK}) { - for(Square sq : pos.pieces(c)) { + Color us = pos.side_to_move(); + Bitboard white_pieces = pos.pieces(Color::WHITE); + Bitboard black_pieces = pos.pieces(Color::BLACK); + Value mid_game_score = 0; + Value end_game_score = 0; + int phase = 0; + int coeff = 1; + for (Color c : {Color::WHITE, Color::BLACK}) { + for (Square sq : pos.pieces(c)) { PieceType pt = type(pos.piece_on(sq)); mid_game_score += coeff * PieceSquareTable[pt][sq.to_int()].first; end_game_score += coeff * PieceSquareTable[pt][sq.to_int()].second; - if(pt != PieceType::KING) { + if (pt != PieceType::KING) { phase += PieceTypeValues[pt]; } // Piece Mobility Bonus - if(pt == PieceType::KNIGHT) { - Bitboard to = knight_attacks[sq.to_int()] - (us == Color::WHITE ? white_pieces : black_pieces); + if (pt == PieceType::KNIGHT) { + Bitboard to = knight_attacks[sq.to_int()] + - (us == Color::WHITE ? white_pieces : black_pieces); int counts = to.count(); mid_game_score += coeff * KnightMobilityMult.first * counts; end_game_score += coeff * KnightMobilityMult.second * counts; } - if(pt == PieceType::BISHOP) { + if (pt == PieceType::BISHOP) { Bitboard bishop_attacks = bishop_magics[sq.to_int()](white_pieces | black_pieces); bishop_attacks -= (us == Color::WHITE ? white_pieces : black_pieces); int counts = bishop_attacks.count(); mid_game_score += coeff * BishopMobilityMult.first * counts; end_game_score += coeff * BishopMobilityMult.second * counts; } - if(pt == PieceType::ROOK) { + if (pt == PieceType::ROOK) { Bitboard rook_attacks = rook_magics[sq.to_int()](white_pieces | black_pieces); rook_attacks -= (us == Color::WHITE ? white_pieces : black_pieces); int counts = rook_attacks.count(); mid_game_score += coeff * RookMobilityMult.first * counts; end_game_score += coeff * RookMobilityMult.second * counts; } - if(pt == PieceType::QUEEN) { - Bitboard rook_attacks = rook_magics[sq.to_int()](white_pieces | black_pieces); + if (pt == PieceType::QUEEN) { + Bitboard rook_attacks = rook_magics[sq.to_int()](white_pieces | black_pieces); Bitboard bishop_attacks = bishop_magics[sq.to_int()](white_pieces | black_pieces); - Bitboard queen_attacks = rook_attacks | bishop_attacks; + Bitboard queen_attacks = rook_attacks | bishop_attacks; queen_attacks -= (us == Color::WHITE ? white_pieces : black_pieces); int counts = queen_attacks.count(); mid_game_score += coeff * QueenMobilityMult.first * counts; @@ -149,9 +154,9 @@ Value evaluate(const Position& pos) { } // Passed pawn bonus. const Bitboard& opponent_pawns = pos.pieces(other_color(c), PieceType::PAWN); - for(Square sq : pos.pieces(c, PieceType::PAWN)) { + for (Square sq : pos.pieces(c, PieceType::PAWN)) { Bitboard visible_pawns = PassedPawnMask[c][sq.to_int()] & opponent_pawns; - if(visible_pawns.empty()) { + if (visible_pawns.empty()) { int promotion_rank = (c == Color::WHITE ? 8 : 1); int bonus = 200 - 25 * std::abs(static_cast(sq.rank()) - promotion_rank); mid_game_score += coeff * bonus; diff --git a/src/main.cpp b/src/main.cpp index dda6969..ad50fa9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,13 +14,13 @@ #include "search.h" int main(int argc, char* argv[]) { - using namespace std; - using namespace sonic; - init_attacks(); - if(argc > 1 && std::string(argv[1]) == "bench") { - run_bench(); - return 0; - } - uci_loop(); - return 0; + using namespace std; + using namespace sonic; + init_attacks(); + if (argc > 1 && std::string(argv[1]) == "bench") { + run_bench(); + return 0; + } + uci_loop(); + return 0; } diff --git a/src/movesort.cpp b/src/movesort.cpp index e2639ea..70e3b85 100644 --- a/src/movesort.cpp +++ b/src/movesort.cpp @@ -8,35 +8,35 @@ namespace sonic { void sort_moves(const Position& pos, MoveList& movelist, Move tt_move) { auto move_score = [&](Move m) -> int { // 1. TT move - if(m == tt_move) { + if (m == tt_move) { return 1000000; } // 2. Promotions - if(m.promotion() == Move::Promotion::Queen) { + if (m.promotion() == Move::Promotion::Queen) { return 100001; } - if(m.promotion() == Move::Promotion::Knight) { + if (m.promotion() == Move::Promotion::Knight) { return 100000; } // 3. MVV-LVA // Pawn, Knight, Bishop, Rook, Queen, King static constexpr int AttackValues[6] = {50, 30, 30, 20, 10, 0}; - Piece from = pos.piece_on(m.from()); - Piece to = pos.piece_on(m.to()); - if(pos.is_capture(m)) { + Piece from = pos.piece_on(m.from()); + Piece to = pos.piece_on(m.to()); + if (pos.is_capture(m)) { return AttackValues[type(from)] - AttackValues[type(to)] + 500; } // 4. Others return -AttackValues[type(from)]; }; static int scores[218]; - for(size_t i = 0; i < movelist.size(); i++) { + for (size_t i = 0; i < movelist.size(); i++) { scores[i] = move_score(movelist[i]); } // Selection sort - for(size_t i = 1; i < movelist.size(); i++) { + for (size_t i = 1; i < movelist.size(); i++) { int j = i; - while(j - 1 >= 0 && scores[j] > scores[j - 1]) { + while (j - 1 >= 0 && scores[j] > scores[j - 1]) { std::swap(scores[j], scores[j - 1]); std::swap(movelist[j], movelist[j - 1]); j--; diff --git a/src/search.cpp b/src/search.cpp index 0b60be7..685793b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -21,38 +21,38 @@ namespace sonic { Value qsearch(Position& pos, SearchInfo& search_info, Value alpha, Value beta) { int ply = search_info.depth; search_info.nodes++; - search_info.seldepth = std::max(search_info.seldepth, ply); + search_info.seldepth = std::max(search_info.seldepth, ply); search_info.pv_length[ply] = 0; - if(pos.is_draw()) { + if (pos.is_draw()) { return VALUE_DRAW; } - if(search_info.time_out()) { + if (search_info.time_out()) { return VALUE_NONE; } // Check for transposition. - Move tt_move = MOVE_NONE; + Move tt_move = MOVE_NONE; Value tt_score = TT.probe(pos, ply, 0, alpha, beta, tt_move); - bool tt_hit = (tt_score != VALUE_NONE); - if(ply > 0 && tt_hit) { + bool tt_hit = (tt_score != VALUE_NONE); + if (ply > 0 && tt_hit) { return tt_score; } Value eval = (tt_hit ? tt_score : evaluate(pos)); - if(ply > MAX_DEPTH - 1) { + if (ply > MAX_DEPTH - 1) { return eval; } bool in_check = pos.in_check(); - if(!in_check) { - if(eval >= beta) { + if (!in_check) { + if (eval >= beta) { return eval; } alpha = std::max(alpha, eval); } // Delta pruning. - if(eval + DELTA_MARGIN < alpha) { + if (eval + DELTA_MARGIN < alpha) { return alpha; } @@ -60,12 +60,12 @@ Value qsearch(Position& pos, SearchInfo& search_info, Value alpha, Value beta) { generate_moves(pos, captures); sort_moves(pos, captures, MOVE_NONE); - Move best_move = MOVE_NONE; - TTFlag flag = TTFlag::TT_ALPHA; - for(Move m : captures) { + Move best_move = MOVE_NONE; + TTFlag flag = TTFlag::TT_ALPHA; + for (Move m : captures) { UndoInfo info; search_info.depth++; - if(!pos.make_move(m, info)) { + if (!pos.make_move(m, info)) { pos.unmake_move(info); search_info.depth--; continue; @@ -74,11 +74,11 @@ Value qsearch(Position& pos, SearchInfo& search_info, Value alpha, Value beta) { Value score = -qsearch(pos, search_info, -beta, -alpha); pos.unmake_move(info); search_info.depth--; - if(score > alpha) { - alpha = score; + if (score > alpha) { + alpha = score; best_move = m; - flag = TTFlag::TT_EXACT; - if(alpha >= beta) { + flag = TTFlag::TT_EXACT; + if (alpha >= beta) { flag = TTFlag::TT_BETA; break; } @@ -90,71 +90,73 @@ Value qsearch(Position& pos, SearchInfo& search_info, Value alpha, Value beta) { } // Negamax search with alpha-beta pruning. -Value negamax(Position& pos, SearchInfo& search_info, Value alpha, Value beta, int depth, bool do_null) { - int ply = search_info.depth; +Value negamax( + Position& pos, SearchInfo& search_info, Value alpha, Value beta, int depth, bool do_null) { + int ply = search_info.depth; bool root_node = (ply == 0); search_info.nodes++; - search_info.seldepth = std::max(search_info.seldepth, ply); + search_info.seldepth = std::max(search_info.seldepth, ply); search_info.pv_length[ply] = 0; - if(!root_node && pos.is_draw()) { + if (!root_node && pos.is_draw()) { return VALUE_DRAW; } - if(search_info.time_out()) { + if (search_info.time_out()) { return VALUE_NONE; } - if(ply > MAX_DEPTH - 1) { + if (ply > MAX_DEPTH - 1) { return evaluate(pos); } // Mate distance pruning. - if(!root_node) { + if (!root_node) { alpha = std::max(alpha, mated_in(ply)); - beta = std::min(beta, mate_in(ply + 1)); - if(alpha >= beta) { + beta = std::min(beta, mate_in(ply + 1)); + if (alpha >= beta) { return alpha; } } bool pv_node = (beta - alpha > 1); // Check for transposition. - Move tt_move = MOVE_NONE; + Move tt_move = MOVE_NONE; Value tt_score = TT.probe(pos, ply, depth, alpha, beta, tt_move); - bool tt_hit = (tt_score != VALUE_NONE); - if(!root_node && tt_hit && !pv_node) { + bool tt_hit = (tt_score != VALUE_NONE); + if (!root_node && tt_hit && !pv_node) { return tt_score; } // Check extension. bool in_check = pos.in_check(); - if(in_check) { + if (in_check) { depth++; } - if(depth <= 0) { + if (depth <= 0) { return qsearch(pos, search_info, alpha, beta); } Value eval = VALUE_INF; - if(!in_check) { + if (!in_check) { // Use evaluation stored in TT. eval = (tt_hit ? tt_score : evaluate(pos)); // Reverse futility pruning. - if(depth <= 3 && eval - (RFP_BASE + RFP_MULTIPLIER * depth * depth) >= beta) { + if (depth <= 3 && eval - (RFP_BASE + RFP_MULTIPLIER * depth * depth) >= beta) { return (eval + beta) / 2; } } // Null move pruning. Color us = pos.side_to_move(); - bool has_big_piece = (pos.pieces(us) - pos.pieces(us, PieceType::KING) - pos.pieces(us, PieceType::PAWN)).any(); - if(do_null && !in_check && has_big_piece && search_info.depth > 0 && depth >= 3) { + bool has_big_piece = + (pos.pieces(us) - pos.pieces(us, PieceType::KING) - pos.pieces(us, PieceType::PAWN)).any(); + if (do_null && !in_check && has_big_piece && search_info.depth > 0 && depth >= 3) { UndoInfo info; search_info.depth++; pos.make_null_move(info); Value null_score = -negamax(pos, search_info, -beta, -beta + 1, depth - 1 - 2, false); pos.unmake_null_move(info); search_info.depth--; - if(null_score >= beta) { + if (null_score >= beta) { return beta; } } @@ -163,25 +165,26 @@ Value negamax(Position& pos, SearchInfo& search_info, Value alpha, Value beta, i generate_moves(pos, movelist); sort_moves(pos, movelist, tt_move); - Value best_score = -VALUE_INF; - Move best_move = MOVE_NONE; - TTFlag flag = TTFlag::TT_ALPHA; - int moves_searched = 0; - for(Move m : movelist) { - bool is_quiet = pos.is_quiet(m); + Value best_score = -VALUE_INF; + Move best_move = MOVE_NONE; + TTFlag flag = TTFlag::TT_ALPHA; + int moves_searched = 0; + for (Move m : movelist) { + bool is_quiet = pos.is_quiet(m); UndoInfo info; search_info.depth++; - if(!pos.make_move(m, info)) { + if (!pos.make_move(m, info)) { pos.unmake_move(info); search_info.depth--; continue; } moves_searched++; bool gives_check = pos.in_check(); - if(!root_node) { + if (!root_node) { // Futility pruning. Value futility_margin = FP_BASE + FP_MULTIPLIER * depth; - if(!in_check && depth <= 2 && is_quiet && !gives_check && eval + futility_margin < alpha) { + if (!in_check && depth <= 2 && is_quiet && !gives_check + && eval + futility_margin < alpha) { pos.unmake_move(info); search_info.depth--; continue; @@ -189,28 +192,28 @@ Value negamax(Position& pos, SearchInfo& search_info, Value alpha, Value beta, i } prefetch(TT.entry_address(pos.hashkey())); Value score = VALUE_NONE; - if(moves_searched >= 5 && depth >= 3 && !in_check) { + if (moves_searched >= 5 && depth >= 3 && !in_check) { score = -negamax(pos, search_info, -alpha - 1, -alpha, depth - 2, true); } else { // Do search on full-depth. score = VALUE_INF; } - if(score > alpha) { + if (score > alpha) { // PV search. score = -negamax(pos, search_info, -alpha - 1, -alpha, depth - 1, true); - if(alpha < score && score < beta) { + if (alpha < score && score < beta) { score = -negamax(pos, search_info, -beta, -alpha, depth - 1, true); } } pos.unmake_move(info); search_info.depth--; - if(score > best_score) { + if (score > best_score) { best_score = score; - best_move = m; - if(score > alpha) { + best_move = m; + if (score > alpha) { alpha = score; - flag = TTFlag::TT_EXACT; - if(alpha >= beta) { + flag = TTFlag::TT_EXACT; + if (alpha >= beta) { flag = TTFlag::TT_BETA; break; } @@ -218,7 +221,7 @@ Value negamax(Position& pos, SearchInfo& search_info, Value alpha, Value beta, i } } } - if(moves_searched == 0) { + if (moves_searched == 0) { // Checkmate or Stalemate. return in_check ? mated_in(ply) : VALUE_DRAW; } @@ -233,7 +236,7 @@ void search(Position& pos, SearchInfo& search_info) { // Search for book move. Book book(options["Book"]); Move best_move = book.book_move(pos); - if(best_move != MOVE_NONE) { + if (best_move != MOVE_NONE) { std::cout << "info book move" << std::endl; std::cout << "bestmove " << best_move.to_string() << std::endl; return; @@ -241,20 +244,20 @@ void search(Position& pos, SearchInfo& search_info) { // Aspiration window. Value alpha = -VALUE_INF, beta = VALUE_INF; // Iterative deepening. - for(int depth = 1; depth <= search_info.max_depth; depth++) { + for (int depth = 1; depth <= search_info.max_depth; depth++) { search_info.follow_pv = true; - Value score = negamax(pos, search_info, alpha, beta, depth, true); - if(search_info.time_out()) { + Value score = negamax(pos, search_info, alpha, beta, depth, true); + if (search_info.time_out()) { break; } - if(score <= alpha || score >= beta) { + if (score <= alpha || score >= beta) { // Research with full window. alpha = -VALUE_INF; - beta = VALUE_INF; + beta = VALUE_INF; depth--; continue; } - best_move = search_info.pv[0][0]; + best_move = search_info.pv[0][0]; std::uint64_t ms = time_elapsed(search_info.start_time); std::cout << "info depth " << depth << " seldepth " << search_info.seldepth; std::cout << " score " << value_to_string(score); @@ -264,7 +267,7 @@ void search(Position& pos, SearchInfo& search_info) { std::cout << " time " << ms; std::cout << " pv " << search_info.pv_to_string() << std::endl; alpha = std::max(score - 20, -VALUE_INF); - beta = std::min(score + 20, VALUE_INF); + beta = std::min(score + 20, VALUE_INF); } std::cout << "bestmove " << best_move.to_string() << std::endl; } diff --git a/src/search.h b/src/search.h index e329fc8..95d61a3 100644 --- a/src/search.h +++ b/src/search.h @@ -18,16 +18,16 @@ namespace sonic { struct SearchInfo { // Total nodes searched. - std::uint64_t nodes = 0; + std::uint64_t nodes = 0; std::uint64_t max_nodes = std::numeric_limits::max() / 2; // Start time of the search. - TimePoint start_time; + TimePoint start_time; std::uint64_t max_time = std::numeric_limits::max() / 2; // Current search depth. - int depth = 0; - int seldepth = 0; + int depth = 0; + int seldepth = 0; int max_depth = MAX_DEPTH; bool stop = false; @@ -35,21 +35,22 @@ struct SearchInfo { std::array history_keys; - std::array, MAX_DEPTH> pv = {}; - std::array pv_length = {}; - bool follow_pv = false; + std::array, MAX_DEPTH> pv = {}; + std::array pv_length = {}; + bool follow_pv = false; void insert_pv(int ply, Move move) { pv[ply][0] = move; - std::copy(pv[ply + 1].begin(), pv[ply + 1].begin() + pv_length[ply + 1], pv[ply].begin() + 1); + std::copy(pv[ply + 1].begin(), pv[ply + 1].begin() + pv_length[ply + 1], + pv[ply].begin() + 1); pv_length[ply] = pv_length[ply + 1] + 1; } std::string pv_to_string() const { std::ostringstream os; - for(int i = 0; i < pv_length[0]; i++) { + for (int i = 0; i < pv_length[0]; i++) { os << pv[0][i].to_string(); - if(i != pv_length[0] - 1) { + if (i != pv_length[0] - 1) { os << " "; } } diff --git a/src/tt.cpp b/src/tt.cpp index bc89a1d..06877ac 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -10,13 +10,13 @@ namespace sonic { TranspositionTable TT(16); void TranspositionTable::resize(std::size_t mbSize) { - constexpr int MB = 1024 * 1024; - std::size_t new_size = 1; + constexpr int MB = 1024 * 1024; + std::size_t new_size = 1; // Size must be power of 2. - while(new_size * 2 * sizeof(TTEntry) <= mbSize * MB) { + while (new_size * 2 * sizeof(TTEntry) <= mbSize * MB) { new_size *= 2; } - if(new_size != size) { + if (new_size != size) { size = new_size; entries.resize(size); clear(); @@ -28,50 +28,53 @@ void TranspositionTable::clear() { entries_count = 0; } -Value TranspositionTable::probe(const Position& pos, int ply, int depth, Value alpha, Value beta, Move& m) const { +Value TranspositionTable::probe( + const Position& pos, int ply, int depth, Value alpha, Value beta, Move& m) const { const TTEntry& entry = entries[pos.hashkey() & (size - 1)]; - if(entry.key != pos.hashkey()) { + if (entry.key != pos.hashkey()) { return VALUE_NONE; } m = entry.move; - if(entry.depth >= depth) { + if (entry.depth >= depth) { Value score = entry.score; - if(is_mate_value(score)) { - if(score < 0) { + if (is_mate_value(score)) { + if (score < 0) { score += ply; } else { score -= ply; } } - if(entry.flag == TTFlag::TT_EXACT) { + if (entry.flag == TTFlag::TT_EXACT) { return score; } - if(entry.flag == TTFlag::TT_ALPHA && score <= alpha) { + if (entry.flag == TTFlag::TT_ALPHA && score <= alpha) { return alpha; } - if(entry.flag == TTFlag::TT_BETA && score >= beta) { + if (entry.flag == TTFlag::TT_BETA && score >= beta) { return beta; } } return VALUE_NONE; } -void TranspositionTable::store(const Position& pos, int depth, Value score, Move move, TTFlag flag) { +void TranspositionTable::store( + const Position& pos, int depth, Value score, Move move, TTFlag flag) { size_t index = pos.hashkey() & (size - 1); assert(index < size); TTEntry& entry = entries[index]; - bool replace = entry.key != pos.hashkey() || entry.depth < depth + 2 || flag == TTFlag::TT_EXACT; - if(!replace) { + bool replace = + entry.key != pos.hashkey() || entry.depth < depth + 2 || flag == TTFlag::TT_EXACT; + if (!replace) { return; } - if(entry.key == 0) { + if (entry.key == 0) { entries_count++; } - entry.key = pos.hashkey(); + entry.key = pos.hashkey(); entry.depth = depth; entry.score = score; - entry.move = move; - entry.flag = flag; + entry.move = move; + entry.flag = flag; } const TTEntry* TranspositionTable::entry_address(std::uint64_t key) const { diff --git a/src/tt.h b/src/tt.h index 167d775..f034f94 100644 --- a/src/tt.h +++ b/src/tt.h @@ -8,23 +8,26 @@ namespace sonic { -enum TTFlag : std::uint8_t { TT_NONE, TT_ALPHA, TT_BETA, TT_EXACT }; +enum TTFlag : std::uint8_t { + TT_NONE, + TT_ALPHA, + TT_BETA, + TT_EXACT +}; struct TTEntry { - std::uint64_t key = 0; - Value score = VALUE_NONE; - Move move = MOVE_NONE; - std::uint8_t depth = 0; - TTFlag flag = TTFlag::TT_NONE; + std::uint64_t key = 0; + Value score = VALUE_NONE; + Move move = MOVE_NONE; + std::uint8_t depth = 0; + TTFlag flag = TTFlag::TT_NONE; }; class TranspositionTable { -public: + public: TranspositionTable() = default; - TranspositionTable(std::size_t mbSize) { - resize(mbSize); - } + TranspositionTable(std::size_t mbSize) { resize(mbSize); } void resize(std::size_t mbSize); void clear(); @@ -32,13 +35,13 @@ class TranspositionTable { const TTEntry* entry_address(std::uint64_t key) const; Value probe(const Position& pos, int ply, int depth, Value alpha, Value beta, Move& m) const; - void store(const Position& pos, int depth, Value score, Move move, TTFlag flag); + void store(const Position& pos, int depth, Value score, Move move, TTFlag flag); constexpr int hashfull() const { return entries_count * 1000 / size; } -private: - std::size_t size = 0; - std::size_t entries_count = 0; + private: + std::size_t size = 0; + std::size_t entries_count = 0; std::vector entries; }; diff --git a/src/tune.h b/src/tune.h index d5a56d5..eb385e2 100644 --- a/src/tune.h +++ b/src/tune.h @@ -11,13 +11,17 @@ extern OptionsMap options; struct TunableParam { TunableParam() {} - TunableParam(std::string name_, int value_, int min_, int max_) : name(name_), value(value_), min(min_), max(max_) { + TunableParam(std::string name_, int value_, int min_, int max_) : + name(name_), + value(value_), + min(min_), + max(max_) { options.add_tune_option(name, &value, min, max); } std::string name; - int value; - int min, max; + int value; + int min, max; operator int() const { return value; } }; diff --git a/src/types.h b/src/types.h index 543388f..107095a 100644 --- a/src/types.h +++ b/src/types.h @@ -14,31 +14,32 @@ using Value = int; constexpr Value VALUE_ZERO = 0; constexpr Value VALUE_DRAW = 0; constexpr Value VALUE_NONE = 32002; -constexpr Value VALUE_INF = 32001; +constexpr Value VALUE_INF = 32001; constexpr Value VALUE_MATE = 32000; -constexpr bool is_mate_value(Value score) { return VALUE_MATE - std::abs(score) <= MAX_DEPTH; } +constexpr bool is_mate_value(Value score) { return VALUE_MATE - std::abs(score) <= MAX_DEPTH; } constexpr Value mate_in(int ply) { return VALUE_MATE - ply; } constexpr Value mated_in(int ply) { return -VALUE_MATE + ply; } inline std::string value_to_string(Value score) { - assert(std::abs(score) <= VALUE_MATE); - if(is_mate_value(score)) { - return std::string("mate ") + std::to_string(score > 0 ? (VALUE_MATE - score + 1) / 2 : (-score - VALUE_MATE) / 2); - } - return std::string("cp ") + std::to_string(score); + assert(std::abs(score) <= VALUE_MATE); + if (is_mate_value(score)) { + return std::string("mate ") + + std::to_string(score > 0 ? (VALUE_MATE - score + 1) / 2 : (-score - VALUE_MATE) / 2); + } + return std::string("cp ") + std::to_string(score); } enum Direction : int { - NORTH = 8, - EAST = 1, - SOUTH = -NORTH, - WEST = -EAST, - - NORTH_EAST = NORTH + EAST, - SOUTH_EAST = SOUTH + EAST, - NORTH_WEST = NORTH + WEST, - SOUTH_WEST = SOUTH + WEST + NORTH = 8, + EAST = 1, + SOUTH = -NORTH, + WEST = -EAST, + + NORTH_EAST = NORTH + EAST, + SOUTH_EAST = SOUTH + EAST, + NORTH_WEST = NORTH + WEST, + SOUTH_WEST = SOUTH + WEST }; constexpr Direction operator+(Direction a, Direction b) { return Direction(int(a) + int(b)); } diff --git a/src/uci.cpp b/src/uci.cpp index ac02ae0..3552db8 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -28,9 +28,9 @@ OptionsMap init_options_map() { options.add_option("Book", "string", ""); options.add_option("Hash", "spin", 16, 1, 1024); options.add_option("Threads", "spin", 1, 1, 1); // Multi-threading currently unsupported. - options.add_option("ClearHash", "button", [&]() -> void { + options.add_option("ClearHash", "button", [&]() -> void { std::lock_guard lock(mtx); // Thread safety - TT.clear(); + TT.clear(); }); return options; } @@ -38,9 +38,10 @@ OptionsMap init_options_map() { OptionsMap options = init_options_map(); void uci_loop() { - std::cout << "Sonic Chess Engine " << version_to_string() << " by Ting-Hsuan Huang" << std::endl; - Position pos; - SearchInfo search_info; + std::cout << "Sonic Chess Engine " << version_to_string() << " by Ting-Hsuan Huang" + << std::endl; + Position pos; + SearchInfo search_info; std::string cmd; std::thread th; @@ -106,12 +107,16 @@ void uci_loop() { options.print_tune_params(); } else { std::cout << "Unknown Command: " << cmd << std::endl; - std::cout << "Available commands: setoption, quit, uci, isready, ucinewgame, bench, perft, position, go, stop, d, tune." << std::endl; + std::cout + << "Available commands: setoption, quit, uci, isready, ucinewgame, bench, perft, position, go, stop, d, tune." + << std::endl; } } } -void parse_position(Position& pos, SearchInfo& search_info, const std::vector& tokens) { +void parse_position(Position& pos, + SearchInfo& search_info, + const std::vector& tokens) { int moves_start = -1; if (tokens[1] == "fen") { std::string fen; @@ -135,19 +140,28 @@ void parse_position(Position& pos, SearchInfo& search_info, const std::vector& params) { const Color& us = pos.side_to_move(); - search_info = SearchInfo(); + search_info = SearchInfo(); int time = -1, increment = 0; for (size_t i = 1; i < params.size(); i++) { if (params[i] == "movetime") { @@ -185,10 +199,10 @@ void parse_go(Position& pos, SearchInfo& search_info, const std::vector::max() / 2; } - search_info.nodes = 0; + search_info.nodes = 0; search_info.start_time = current_time(); - search_info.max_time = time / 15 + increment / 2; - search_info.stop = false; + search_info.max_time = time / 15 + increment / 2; + search_info.stop = false; } } // namespace sonic diff --git a/src/ucioption.h b/src/ucioption.h index bea9a1e..10c440c 100644 --- a/src/ucioption.h +++ b/src/ucioption.h @@ -12,18 +12,33 @@ namespace sonic { struct Option { - std::string name, type; - std::string default_value; - std::string string_value; - int value; - int min, max; + std::string name, type; + std::string default_value; + std::string string_value; + int value; + int min, max; std::function button; Option() {} - Option(std::string name_, std::string type_) : name(name_), type(type_) {} - Option(std::string name_, std::string type_, std::function button_) : name(name_), type(type_), button(button_) {} - Option(std::string name_, std::string type_, std::string default_val) : name(name_), type(type_), default_value(default_val), string_value(default_val) {} - Option(std::string name_, std::string type_, int default_val, int min_, int max_) : name(name_), type(type_), default_value(std::to_string(default_val)), value(default_val), min(min_), max(max_) {} + Option(std::string name_, std::string type_) : + name(name_), + type(type_) {} + Option(std::string name_, std::string type_, std::function button_) : + name(name_), + type(type_), + button(button_) {} + Option(std::string name_, std::string type_, std::string default_val) : + name(name_), + type(type_), + default_value(default_val), + string_value(default_val) {} + Option(std::string name_, std::string type_, int default_val, int min_, int max_) : + name(name_), + type(type_), + default_value(std::to_string(default_val)), + value(default_val), + min(min_), + max(max_) {} operator int() const { return value; } operator double() const { return value; } @@ -31,10 +46,11 @@ struct Option { std::string to_string() const { std::string result = std::string("option name ") + name + " type " + type; - if(type != "button") { + if (type != "button") { result += std::string(" default ") + default_value; - if(type == "spin") { - result += std::string(" min ") + std::to_string(min) + " max " + std::to_string(max); + if (type == "spin") { + result += + std::string(" min ") + std::to_string(min) + " max " + std::to_string(max); } } return result; @@ -48,21 +64,27 @@ struct Option { class OptionsMap { using ParamData = std::tuple; -public: + public: void add_option(std::string name, std::string type) { options[name] = Option(name, type); } - void add_option(std::string name, std::string type, std::function button) { options[name] = Option(name, type, button); } - void add_option(std::string name, std::string type, std::string default_value) { options[name] = Option(name, type, default_value); } - void add_option(std::string name, std::string type, int default_value, int min, int max) { options[name] = Option(name, type, default_value, min, max); } + void add_option(std::string name, std::string type, std::function button) { + options[name] = Option(name, type, button); + } + void add_option(std::string name, std::string type, std::string default_value) { + options[name] = Option(name, type, default_value); + } + void add_option(std::string name, std::string type, int default_value, int min, int max) { + options[name] = Option(name, type, default_value, min, max); + } void add_tune_option(std::string name, int* val, int min, int max) { tune_params.push_back(std::make_tuple(name, val, min, max)); } void print_tune_params() { - for(auto data : tune_params) { + for (auto data : tune_params) { std::string name; - int* value_ptr; - int min, max; + int* value_ptr; + int min, max; std::tie(name, value_ptr, min, max) = data; std::cout << name << ", int, " << *value_ptr << ", " << min << ", " << max << ", "; std::cout << std::max((max - min) / 20.0, 0.5) << ", 0.002" << std::endl; @@ -70,7 +92,7 @@ class OptionsMap { } void button(const std::string& name) { - if(options.find(name) == options.end()) { + if (options.find(name) == options.end()) { std::cout << "Unknown option: \"" << name << "\"." << std::endl; return; } @@ -79,15 +101,15 @@ class OptionsMap { } void set(const std::string& name, const std::string& value) { - if(options.find(name) == options.end()) { + if (options.find(name) == options.end()) { // Search if the option is a tunable param. set_tune_param(name, stoi(value)); return; } Option& option = options[name]; - if(option.type == "spin") { + if (option.type == "spin") { int value_int = stoi(value); - if(option.min <= value_int && value_int <= option.max) { + if (option.min <= value_int && value_int <= option.max) { option.value = stoi(value); } return; @@ -96,8 +118,8 @@ class OptionsMap { } void set_tune_param(const std::string& name, int value) { - for(auto data : tune_params) { - if(std::get<0>(data) == name) { + for (auto data : tune_params) { + if (std::get<0>(data) == name) { *std::get<1>(data) = value; return; } @@ -107,7 +129,7 @@ class OptionsMap { std::string to_string() const { std::string result; - for(auto p : options) { + for (auto p : options) { result += p.second.to_string(); result += "\n"; } @@ -119,13 +141,11 @@ class OptionsMap { return out << o.to_string(); } - const Option& operator[](const std::string& name) { - return options[name]; - } + const Option& operator[](const std::string& name) { return options[name]; } -private: - std::vector tune_params; + private: + std::vector tune_params; std::unordered_map options; }; - + } // namespace sonic \ No newline at end of file diff --git a/src/utils/bits.h b/src/utils/bits.h index 23a98e6..498ebc9 100644 --- a/src/utils/bits.h +++ b/src/utils/bits.h @@ -20,8 +20,6 @@ constexpr int popcount(std::uint64_t num) { #endif } -constexpr int lsb(std::uint64_t num) { - return __builtin_ctzll(num); -} +constexpr int lsb(std::uint64_t num) { return __builtin_ctzll(num); } } // namespace sonic diff --git a/src/utils/misc.cpp b/src/utils/misc.cpp index 9cbb43b..f899a6f 100644 --- a/src/utils/misc.cpp +++ b/src/utils/misc.cpp @@ -9,11 +9,11 @@ void prefetch(const void*) {} #else void prefetch(const void* addr) { -#ifdef _MSC_VER + #ifdef _MSC_VER _mm_prefetch((const char*) addr, _MM_HINT_T0); -#else + #else __builtin_prefetch(addr); -#endif + #endif } #endif diff --git a/src/utils/random.h b/src/utils/random.h index c344444..c8bff53 100644 --- a/src/utils/random.h +++ b/src/utils/random.h @@ -6,10 +6,10 @@ namespace sonic { inline std::uint64_t rng() { - static std::uint64_t SEED = std::chrono::steady_clock::now().time_since_epoch().count(); - SEED ^= SEED << 7; - SEED ^= SEED >> 9; - return SEED; + static std::uint64_t SEED = std::chrono::steady_clock::now().time_since_epoch().count(); + SEED ^= SEED << 7; + SEED ^= SEED >> 9; + return SEED; } } // namespace sonic diff --git a/src/utils/small_vector.h b/src/utils/small_vector.h index b36908f..293382f 100644 --- a/src/utils/small_vector.h +++ b/src/utils/small_vector.h @@ -9,12 +9,13 @@ namespace sonic { template class SmallVector { -public: + public: using iterator = typename std::array::iterator; SmallVector() = default; - SmallVector(std::size_t n) : sz(n) { + SmallVector(std::size_t n) : + sz(n) { assert(n <= N); } @@ -36,17 +37,15 @@ class SmallVector { sz--; } - void resize(std::size_t i) { - sz = i; - } + void resize(std::size_t i) { sz = i; } bool contains(const T& x) const { return std::find(data.begin(), data.begin() + sz, x) != data.begin() + sz; } - constexpr void clear() { sz = 0; } + constexpr void clear() { sz = 0; } constexpr std::size_t size() const { return sz; } - constexpr bool empty() const { return sz == 0; } + constexpr bool empty() const { return sz == 0; } T& operator[](std::size_t i) { assert(i < sz); @@ -62,10 +61,10 @@ class SmallVector { auto end() { return data.begin() + static_cast(sz); } auto begin() const { return data.begin(); } auto end() const { return data.begin() + static_cast(sz); } - -private: + + private: std::array data = {}; - std::size_t sz = 0; + std::size_t sz = 0; }; } // namespace sonic \ No newline at end of file diff --git a/src/utils/strings.cpp b/src/utils/strings.cpp index 8b0a7ac..150b993 100644 --- a/src/utils/strings.cpp +++ b/src/utils/strings.cpp @@ -8,10 +8,10 @@ namespace sonic { std::vector split_string(const std::string& s, char delim) { - std::istringstream in(s); + std::istringstream in(s); std::vector tokens; - std::string token; - while(std::getline(in, token, delim)) { + std::string token; + while (std::getline(in, token, delim)) { tokens.push_back(token); } return tokens; diff --git a/src/utils/timer.h b/src/utils/timer.h index b626986..edf6592 100644 --- a/src/utils/timer.h +++ b/src/utils/timer.h @@ -7,9 +7,7 @@ namespace sonic { using TimePoint = std::chrono::high_resolution_clock::time_point; -inline TimePoint current_time() { - return std::chrono::high_resolution_clock::now(); -} +inline TimePoint current_time() { return std::chrono::high_resolution_clock::now(); } inline std::uint64_t time_elapsed(TimePoint start) { TimePoint now = current_time();