diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index ce9c419..88b50d7 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -1,14 +1,19 @@ name: clang-format on: - pull_request: - branches: [ "main" ] - + workflow_run: + workflows: ["CMake on multiple platforms"] + types: + - completed + jobs: format: + if: > + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' runs-on: ubuntu-latest permissions: - contents: write # required to push back into PR + contents: write steps: - uses: actions/checkout@v4 diff --git a/attacks.h b/attacks.h index 32b5e94..081b281 100644 --- a/attacks.h +++ b/attacks.h @@ -1,4 +1,5 @@ #pragma once +#include "fwd_decl.h" #include "bitboard.h" #include "types.h" #include @@ -288,4 +289,6 @@ template [[nodiscard]] constexpr Bitboard slider(Square sq, Bitbo return queen(sq, occupied); } -} // namespace chess::attacks \ No newline at end of file + +} // namespace chess::attacks + diff --git a/movegen.cpp b/movegen.cpp index 29a77de..d242da9 100644 --- a/movegen.cpp +++ b/movegen.cpp @@ -267,33 +267,32 @@ template void movegen::genKingMoves(con if (pos.checkers()) return; - // Precompute all castling masks - constexpr Bitboard WHITE_OO_EMPTY = (1ULL << SQ_F1) | (1ULL << SQ_G1); - constexpr Bitboard WHITE_OO_SAFE = (1ULL << SQ_F1) | (1ULL << SQ_G1); - constexpr Bitboard WHITE_OOO_EMPTY = (1ULL << SQ_B1) | (1ULL << SQ_C1) | (1ULL << SQ_D1); - constexpr Bitboard WHITE_OOO_SAFE = (1ULL << SQ_C1) | (1ULL << SQ_D1); - - constexpr Bitboard BLACK_OO_EMPTY = (1ULL << SQ_F8) | (1ULL << SQ_G8); - constexpr Bitboard BLACK_OO_SAFE = (1ULL << SQ_F8) | (1ULL << SQ_G8); - constexpr Bitboard BLACK_OOO_EMPTY = (1ULL << SQ_B8) | (1ULL << SQ_C8) | (1ULL << SQ_D8); - constexpr Bitboard BLACK_OOO_SAFE = (1ULL << SQ_C8) | (1ULL << SQ_D8); - Bitboard occupancy = pos.occ(); Bitboard enemy_attacks = enemyAttacks; if constexpr (c == WHITE) { + Bitboard WHITE_OO_EMPTY = pos.getCastlingPath(WHITE, true); + Bitboard WHITE_OO_SAFE = between(kingSq, castling_king_square(WHITE, true)); + Bitboard WHITE_OOO_EMPTY = pos.getCastlingPath(WHITE, false); + Bitboard WHITE_OOO_SAFE = between(kingSq, castling_king_square(WHITE, false)); + if ((pos.castlingRights() & WHITE_OO) && !(occupancy & WHITE_OO_EMPTY) && !(enemy_attacks & WHITE_OO_SAFE)) { - out.push_back(Move::make(SQ_E1, SQ_H1)); + out.push_back(Move::make(kingSq, SQ_H1)); } if ((pos.castlingRights() & WHITE_OOO) && !(occupancy & WHITE_OOO_EMPTY) && !(enemy_attacks & WHITE_OOO_SAFE)) { - out.push_back(Move::make(SQ_E1, SQ_A1)); + out.push_back(Move::make(kingSq, SQ_A1)); } } else { + Bitboard BLACK_OO_EMPTY = pos.getCastlingPath(BLACK, true); + Bitboard BLACK_OO_SAFE = between(kingSq, castling_king_square(BLACK, true)); + Bitboard BLACK_OOO_EMPTY = pos.getCastlingPath(BLACK, false); + Bitboard BLACK_OOO_SAFE = between(kingSq, castling_king_square(BLACK, false)); + if ((pos.castlingRights() & BLACK_OO) && !(occupancy & BLACK_OO_EMPTY) && !(enemy_attacks & BLACK_OO_SAFE)) { - out.push_back(Move::make(SQ_E8, SQ_H8)); + out.push_back(Move::make(kingSq, SQ_H8)); } if ((pos.castlingRights() & BLACK_OOO) && !(occupancy & BLACK_OOO_EMPTY) && !(enemy_attacks & BLACK_OOO_SAFE)) { - out.push_back(Move::make(SQ_E8, SQ_A8)); + out.push_back(Move::make(kingSq, SQ_A8)); } } } diff --git a/position.cpp b/position.cpp index 7f8a48d..e87977b 100644 --- a/position.cpp +++ b/position.cpp @@ -101,8 +101,8 @@ template template void _Position(rook_dest, us); placePiece(king_dest, us); current_state.incr_sqs[0] = from_sq; @@ -629,7 +629,6 @@ template void _Position::refresh_attack } template uint64_t _Position::zobrist() const { uint64_t hash = 0; -#pragma unroll(64) for (int sq = 0; sq < 64; ++sq) { auto p = piece_on((Square)sq); hash ^= (p == PieceC::NO_PIECE) ? 0 : zobrist::RandomPiece[enum_idx()][(int)p][sq]; @@ -674,6 +673,7 @@ template Square _Position::_valid_ep_sq Bitboard mask = 1ULL << ep_square(); Bitboard pawn_mask = mask << 8; Bitboard org_pawn_mask = mask >> 8; + if (sideToMove() == BLACK) std::swap(pawn_mask, org_pawn_mask); // rank 3 or rank 6, depending on color if (rank_of(ep_square()) != ep_rank) return SQ_NONE; @@ -787,3 +787,5 @@ INSTANTIATE(EnginePiece) INSTANTIATE(ContiguousMappingPiece) #undef INSTANTIATE } // namespace chess + + diff --git a/position.h b/position.h index 28f89f3..6aa9376 100644 --- a/position.h +++ b/position.h @@ -19,13 +19,11 @@ template struct alignas(64) HistoryEntry { Color turn; // true if white to move Move mv; Key hash; - struct { - uint8_t halfMoveClock; // Half-move clock for 50/75-move rule - uint16_t fullMoveNumber; // Full-move number (starts at 1) - bool epIncluded; - int8_t repetition = 0; - uint8_t pliesFromNull = 0; - }; + uint8_t halfMoveClock; // Half-move clock for 50/75-move rule + uint16_t fullMoveNumber; // Full-move number (starts at 1) + bool epIncluded; + int8_t repetition = 0; + uint8_t pliesFromNull = 0; Square enPassant = SQ_NONE; // En passant target square Square kings[COLOR_NB] = { SQ_NONE }; CastlingRights castlingRights; // Castling rights bitmask @@ -160,9 +158,7 @@ template , 6144> - history; // ahh, but i hope it fulfils before I manages to find the absolute limit of a game - // Move generation functions, but INTERNAL. (they're kind of long so i put them into a source - // file) Pawns (fully extensively tested) + history; Bitboard _rook_pin; Bitboard _bishop_pin; Bitboard _checkers; @@ -181,6 +177,12 @@ template , 2> castling_path = + {{ + {{ 0xe, 0x60 }}, + {{ 0xe00000000000000ULL, 0x6000000000000000ULL }} + }}; public: // Legal move generation functions @@ -393,7 +395,7 @@ template __FORCEINLINE void placePiece(Square sq, Color c) { if constexpr (pt != NO_PIECE_TYPE) { Bitboard v = 1ULL << sq; @@ -448,6 +450,7 @@ template &state() const { return current_state; } uint64_t zobrist() const; __FORCEINLINE PieceC piece_at(Square sq) const { return piece_on(sq); } - __FORCEINLINE PieceC at(Square sq) const { return piece_at(sq); } + template + __FORCEINLINE PieceC at(Square sq) const { + assert(chess::is_valid(sq)); + if constexpr (std::is_same_v) return piece_of(piece_at(sq)); + else return piece_at(sq); + } __FORCEINLINE Square enpassantSq() const { return ep_square(); } CastlingRights clean_castling_rights() const; void setFEN(const std::string &str); @@ -524,6 +531,8 @@ template bool is_valid() const; CheckType givesCheck(Move move) const; - + /** + * @brief Checks if the current position is a draw by 50 move rule. + * Keep in mind that by the rules of chess, if the position has 50 half + * moves it's not necessarily a draw, since checkmate has higher priority, + * call getHalfMoveDrawType, + * to determine whether the position is a draw or checkmate. + * @return + */ + [[nodiscard]] __FORCEINLINE bool isHalfMoveDraw() const noexcept { return halfmoveClock() >= 100; } + [[nodiscard]] __FORCEINLINE Bitboard getCastlingPath(Color c, bool isKingSide) const { return castling_path[c][isKingSide]; } private: template [[nodiscard]] __FORCEINLINE Bitboard pinMask(Color c, Square sq) const { static_assert(pt == BISHOP || pt == ROOK, "Only bishop or rook allowed!"); @@ -684,5 +712,23 @@ template ; // for some fun because I HATE HARDCODING +namespace attacks{ +/** + * @brief Returns the attacks for a given piece on a given square + * @param board + * @param color + * @param square + * @return + */ +template ::value>> +[[nodiscard]] __FORCEINLINE Bitboard attackers(const _Position &board, Color color, Square square) noexcept { + return board.attackers(color, square); +} +} +// Aliases +using Position = _Position; +using Board = _Position; }; // namespace chess + + + diff --git a/types.h b/types.h index 554d67b..9ff1230 100644 --- a/types.h +++ b/types.h @@ -123,13 +123,14 @@ enum Direction : int8_t { }; // clang-format on inline constexpr Square relative_square(Color c, Square s) { return Square(s ^ (c * 56)); } +inline constexpr Square castling_rook_square(Color c, bool is_king_side) { return relative_square(c, is_king_side ? SQ_F1 : Square::SQ_D1); } +inline constexpr Square castling_king_square(Color c, bool is_king_side) { return relative_square(c, is_king_side ? SQ_G1 : Square::SQ_C1); } inline constexpr Rank relative_rank(Color c, Rank r) { return Rank(r ^ (c * 7)); } inline constexpr Rank relative_rank(Color c, Square s) { return relative_rank(c, rank_of(s)); } inline constexpr Direction relative_direction(Color c, Direction d) { return static_cast(c == WHITE ? d : -d); } - inline constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; } #define ENABLE_INCR_OPERATORS_ON(T) \ @@ -437,3 +438,5 @@ constexpr PieceType parse_pt(unsigned char c) { } } // namespace chess + +