Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,18 @@ jobs:
- name: Configure CMake
shell: bash
run: |
if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
if "${{ matrix.cpp_compiler }}" == "clang++" ]]; then
SANITIZERS="memory,undefined"
else
SANITIZERS="address,undefined"
fi
fi
cmake -B "${{ steps.vars.outputs.dir }}" \
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }} \
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DSANITIZERS="address,undefined" \
-DSANITIZERS=${SANITIZERS} \
-DDART_TESTING_TIMEOUT=0 \
-S "${{ github.workspace }}"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/try_compile.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Compilation

on:
pull_request:
push:

jobs:
build:
Expand Down
41 changes: 35 additions & 6 deletions movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,39 @@
namespace chess {

namespace _chess {
#if defined(__AVX512BW__)

#if defined(USE_AVX512ICL)

// clang-format off
const __m512i AllSquares = _mm512_set_epi8(
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41,
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
// clang-format on

template <Direction offset> inline Move *splat_pawn_moves(Move *moveList, Bitboard to_bb) {
assert(popcount(to_bb) <= 8); // <= 8 pawns per side

const __m128i toSquares = _mm_cvtepi8_epi16(_mm512_castsi512_si128(_mm512_maskz_compress_epi8(to_bb, AllSquares)));
const __m128i fromSquares = _mm_subs_epi16(toSquares, _mm_set1_epi16(offset));
const __m128i moves = _mm_or_si128(_mm_slli_epi16(fromSquares, 6), _mm_slli_epi16(toSquares, 0));

_mm_storeu_si128(reinterpret_cast<__m128i *>(moveList), moves);
return moveList + popcount(to_bb);
}

inline Move *splat_moves(Move *moveList, Square from, Bitboard to_bb) {
assert(popcount(to_bb) <= 32); // Q can attack up to 27 squares

const __m512i fromVec = _mm512_set1_epi16(Move(from, SQUARE_ZERO).raw());
const __m512i toSquares = _mm512_cvtepi8_epi16(_mm512_castsi512_si256(_mm512_maskz_compress_epi8(to_bb, AllSquares)));
const __m512i moves = _mm512_or_si512(fromVec, _mm512_slli_epi16(toSquares, Move::ToSqShift));

_mm512_storeu_si512(moveList, moves);
return moveList + popcount(to_bb);
}

#elif defined(__AVX512BW__)
template <int Offset = 0> struct alignas(64) SplatTable {
std::array<uint16_t, 64> data;
constexpr int clamp64(int x) { return (x < 0) ? 0 : (x > 63 ? 63 : x); }
Expand Down Expand Up @@ -213,7 +245,7 @@ void movegen::genPawnSingleMoves(
}
template <typename T, Color c, bool capturesOnly>
void movegen::genKnightMoves(const _Position<T, void> &pos, Movelist &list, Bitboard _pin_mask, Bitboard _check_mask) {
Bitboard knights = pos.template pieces<KNIGHT, c>() & ~_pin_mask; // yes, unconditionally.
Bitboard knights = pos.template pieces<KNIGHT, c>() & ~_pin_mask;
while (knights) {
Square x = static_cast<Square>(pop_lsb(knights));
Bitboard moves = attacks::knight(x) & ~pos.occ(c);
Expand Down Expand Up @@ -253,7 +285,6 @@ void movegen::genKingMoves(const _Position<T, void> &pos, Movelist &out, Bitboar
// Enemy king (adjacent control squares)
enemyAttacks |= attacks::king(pos.kingSq(them));

// Candidate king moves = legal squares not attacked by enemy
Bitboard moves = attacks::king(kingSq) & ~myOcc & ~enemyAttacks;
if constexpr (capturesOnly)
moves &= pos.occ(~c);
Expand Down Expand Up @@ -289,8 +320,7 @@ void movegen::genSlidingMoves(
static_assert(pt == BISHOP || pt == ROOK || pt == QUEEN, "Sliding pieces only.");
Bitboard sliders = pos.template pieces<pt, c>();
Bitboard occ_all = pos.occ();
// Square king_sq = current_state.kings[c];
Bitboard rook_pinners = _rook_pin; // bitboard of enemy rooks/queens pinning
Bitboard rook_pinners = _rook_pin;
Bitboard bishop_pinners = _bishop_pin;
if constexpr (pt == BISHOP)
sliders &= ~rook_pinners;
Expand All @@ -305,7 +335,6 @@ void movegen::genSlidingMoves(
Bitboard bishop_hit = bishop_pinners & from_bb;
Bitboard pin_mask = rook_hit ? rook_pinners : bishop_hit ? bishop_pinners : ~0ULL;

// Bitboard blockers = occ() ^ from_bb; // remove piece temporarily
auto func = attacks::queen;
if constexpr (pt == BISHOP)
func = attacks::bishop;
Expand Down
8 changes: 6 additions & 2 deletions non_core_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -893,9 +893,13 @@ TEST_SUITE("SAN Parser") {
}

TEST_SUITE("misc tests") {
TEST_CASE("FEN reconstruction") {
TEST_CASE("FEN reconstruction (Chess960)") {
Position pos(Position::START_CHESS960_FEN, true);
REQUIRE(pos.fen() == Position::START_CHESS960_FEN);
REQUIRE(pos.fen(false) == Position::START_CHESS960_FEN);
REQUIRE(pos.fen() == Position::START_FEN);
pos.setFEN(Position::START_CHESS960_FEN, true, chess::MODE_SMK);
REQUIRE(pos.fen(false) == Position::START_CHESS960_FEN);
REQUIRE(pos.fen() == Position::START_FEN);
}
}
int main(int argc, char **argv) {
Expand Down
33 changes: 25 additions & 8 deletions position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ template <typename PieceC, typename T> template <bool Strict> void _Position<Pie
}
}

template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const std::string &str, bool chess960) {
template <typename PieceC, typename T>
void _Position<PieceC, T>::setFEN(const std::string &str, bool chess960, FENParsingMode mode) {
current_state = HistoryEntry<PieceC>();
history.clear();
_chess960 = chess960;
Expand Down Expand Up @@ -329,6 +330,8 @@ template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const s
}
return SQ_NONE;
};
bool allow_xfen = (mode == MODE_XFEN || mode == MODE_AUTO);
bool allow_smk = (mode == MODE_SMK || mode == MODE_AUTO);
auto apply = [&](char c) {
Square king_sq = findKing();
if (king_sq == SQ_NONE)
Expand Down Expand Up @@ -368,24 +371,28 @@ template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const s
};

if (c == 'K' && color == WHITE) {
INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser");
if (rook_ks == SQ_NONE)
return;
if (rank_of(king_sq) != rank_of(rook_ks))
return;
setKS(rook_ks);
} else if (c == 'Q' && color == WHITE) {
INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser");
if (rook_qs == SQ_NONE)
return;
if (rank_of(king_sq) != rank_of(rook_qs))
return;
setQS(rook_qs);
} else if (c == 'k' && color == BLACK) {
INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser");
if (rook_ks == SQ_NONE)
return;
if (rank_of(king_sq) != rank_of(rook_ks))
return;
setKS(rook_ks);
} else if (c == 'q' && color == BLACK) {
INVALID_ARG_IF(chess960 && !allow_xfen, "shredder fen into xfen parser");
if (rook_qs == SQ_NONE)
return;
if (rank_of(king_sq) != rank_of(rook_qs))
Expand All @@ -394,6 +401,7 @@ template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const s
}

else if (c >= 'A' && c <= 'H' && color == WHITE) {
INVALID_ARG_IF(chess960 && !allow_smk, "xfen into shredder fen parser");
File f = static_cast<File>(c - 'A');
Square rook_sq = make_sq(RANK_1, f);

Expand All @@ -403,6 +411,7 @@ template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const s

(f > file_of(king_sq)) ? setKS(rook_sq) : setQS(rook_sq);
} else if (c >= 'a' && c <= 'h' && color == BLACK) {
INVALID_ARG_IF(chess960 && !allow_smk, "xfen into shredder fen parser");
File f = static_cast<File>(c - 'a');
Square rook_sq = make_sq(RANK_8, f);

Expand Down Expand Up @@ -474,7 +483,7 @@ template <typename PieceC, typename T> void _Position<PieceC, T>::setFEN(const s
current_state.repetition = current_state.pliesFromNull = 0;
}

template <typename PieceC, typename T> std::string _Position<PieceC, T>::fen() const {
template <typename PieceC, typename T> std::string _Position<PieceC, T>::fen(bool xfen) const {
std::ostringstream ss;

// 1) Piece placement
Expand Down Expand Up @@ -508,13 +517,21 @@ template <typename PieceC, typename T> std::string _Position<PieceC, T>::fen() c
std::string castlingStr;
if (chess960()) {
if (castlingRights() & WHITE_OO)
castlingStr += static_cast<char>('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks));
castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_ks == SQ_H1)
? 'K'
: static_cast<char>('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_ks));
if (castlingRights() & WHITE_OOO)
castlingStr += static_cast<char>('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs));
castlingStr += (xfen && current_state.castlingMetadata[WHITE].rook_start_qs == SQ_A1)
? 'Q'
: static_cast<char>('A' + file_of(current_state.castlingMetadata[WHITE].rook_start_qs));
if (castlingRights() & BLACK_OO)
castlingStr += static_cast<char>('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_ks));
castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_ks == SQ_H8)
? 'k'
: static_cast<char>('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_ks));
if (castlingRights() & BLACK_OOO)
castlingStr += static_cast<char>('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs));
castlingStr += (xfen && current_state.castlingMetadata[BLACK].rook_start_qs == SQ_A8)
? 'q'
: static_cast<char>('a' + file_of(current_state.castlingMetadata[BLACK].rook_start_qs));
} else {
if (castlingRights() & WHITE_OO)
castlingStr += 'K';
Expand Down Expand Up @@ -858,8 +875,8 @@ template <typename PieceC, typename T> CastlingRights _Position<PieceC, T>::clea
}
// clang-format off
#define INSTANTIATE(PieceC) \
template void _Position<PieceC, void>::setFEN(const std::string &, bool); \
template std::string _Position<PieceC, void>::fen() const; \
template void _Position<PieceC, void>::setFEN(const std::string &, bool, FENParsingMode); \
template std::string _Position<PieceC, void>::fen(bool) const; \
template void _Position<PieceC, void>::doMove<false>(const Move &move); \
template void _Position<PieceC, void>::doMove<true>(const Move &move); \
template void _Position<PieceC, void>::refresh_attacks(); \
Expand Down
19 changes: 13 additions & 6 deletions position.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ template <typename Piece> struct alignas(64) HistoryEntry {
};

enum class CheckType { NO_CHECK, DIRECT_CHECK, DISCOVERY_CHECK };

enum FENParsingMode { MODE_XFEN, MODE_SMK, MODE_AUTO };

enum class MoveGenType : uint16_t {
NONE = 0,

Expand Down Expand Up @@ -396,16 +399,16 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
[[nodiscard]] inline Square kingSq(Color c) const { return current_state.kings[c]; }
[[nodiscard]] inline Bitboard checkers() const { return _checkers; }
[[nodiscard]] inline Bitboard pin_mask() const { return _pin_mask; }
inline _Position(std::string fen = START_FEN, bool chess960 = false) {
inline _Position(std::string fen = START_FEN, bool chess960 = false, FENParsingMode xfen = MODE_AUTO) {
history.reserve(6144);
setFEN(fen, chess960);
setFEN(fen, chess960, xfen);
}
[[nodiscard]] inline bool isCapture(Move mv) const {
return mv.type_of() == EN_PASSANT || (mv.type_of() != CASTLING && piece_on(mv.to_sq()) != PieceC::NO_PIECE);
}
[[nodiscard]] inline bool is_capture(Move mv) const { return isCapture(mv); }
[[nodiscard]] inline bool is_zeroing(Move mv) const { return isCapture(mv) || at<PieceType>(mv.from_sq()) == PAWN; }
[[nodiscard]] std::string fen() const;
[[nodiscard]] std::string fen(bool xfen = true) const;
[[nodiscard]] inline uint8_t halfmoveClock() const { return current_state.halfMoveClock; }
[[nodiscard]] inline uint16_t fullmoveNumber() const { return current_state.fullMoveNumber; }
[[nodiscard]] inline uint8_t rule50_count() const { return current_state.halfMoveClock; }
Expand All @@ -428,9 +431,13 @@ template <typename PieceC = EnginePiece, typename = std::enable_if_t<is_piece_en
}
inline Square enpassantSq() const { return ep_square(); }
CastlingRights clean_castling_rights() const;
void setFEN(const std::string &str, bool chess960 = false);
inline void set_fen(const std::string &str, bool chess960 = false) { setFEN(str, chess960); }
inline void setFen(const std::string &str, bool chess960 = false) { setFEN(str, chess960); }
void setFEN(const std::string &str, bool chess960 = false, FENParsingMode xfen = MODE_AUTO);
inline void set_fen(const std::string &str, bool chess960 = false, FENParsingMode xfen = MODE_AUTO) {
setFEN(str, chess960, xfen);
}
inline void setFen(const std::string &str, bool chess960 = false, FENParsingMode xfen = MODE_AUTO) {
setFEN(str, chess960, xfen);
}
Move parse_uci(std::string) const;
Move push_uci(std::string);
Square _valid_ep_square() const;
Expand Down
Loading