#pragma once /* --- Score16 (centipawns) ---- */ typedef int16_t Score16; enum { SCORE_INF = 9999, SCORE_CHECKMATE = 999, }; /* ----------- Index8 ----------- */ typedef uint8_t Index8; #define MASK_SHIFT_NORTH(b, n) ((b) << ((Index8)(n)*8U)) #define MASK_SHIFT_SOUTH(b, n) ((b) >> ((Index8)(n)*8U)) #define MASK_SHIFT_WEST(b, n) ((b) >> ((Index8)(n)*1U)) #define MASK_SHIFT_EAST(b, n) ((b) << ((Index8)(n)*1U)) #define SQ_SHIFT_NORTH(i, n) ((i) + ((Index8)(n)*8U)) #define SQ_SHIFT_SOUTH(i, n) ((i) - ((Index8)(n)*8U)) #define SQ_SHIFT_WEST(i, n) ((i) - ((Index8)(n)*1U)) #define SQ_SHIFT_EAST(i, n) ((i) + ((Index8)(n)*1U)) #define SQ_FROM_RF(rank, file) ((Index8)(8U*(Index8)(rank) + (Index8)(file))) /* ----------- file_index ----------- */ enum file_index : Index8 { FILE_INDEX_BEGIN, FILE_INDEX_A = FILE_INDEX_BEGIN, FILE_INDEX_B, FILE_INDEX_C, FILE_INDEX_D, FILE_INDEX_E, FILE_INDEX_F, FILE_INDEX_G, FILE_INDEX_H, FILE_INDEX_COUNT, }; char const file_index_char[FILE_INDEX_COUNT] = { [FILE_INDEX_A] = 'A', [FILE_INDEX_B] = 'B', [FILE_INDEX_C] = 'C', [FILE_INDEX_D] = 'D', [FILE_INDEX_E] = 'E', [FILE_INDEX_F] = 'F', [FILE_INDEX_G] = 'G', [FILE_INDEX_H] = 'H', }; /* ----------- rank_index ----------- */ enum rank_index : Index8 { RANK_INDEX_BEGIN, RANK_INDEX_1 = RANK_INDEX_BEGIN, RANK_INDEX_2, RANK_INDEX_3, RANK_INDEX_4, RANK_INDEX_5, RANK_INDEX_6, RANK_INDEX_7, RANK_INDEX_8, RANK_INDEX_COUNT, }; char const rank_index_char[RANK_INDEX_COUNT] = { [RANK_INDEX_1] = '1', [RANK_INDEX_2] = '2', [RANK_INDEX_3] = '3', [RANK_INDEX_4] = '4', [RANK_INDEX_5] = '5', [RANK_INDEX_6] = '6', [RANK_INDEX_7] = '7', [RANK_INDEX_8] = '8', }; /* ----------- Sq8 ----------- */ #define SQMASK_PREFIX SQMASK_ #define SQUARES_LIST_BEGIN \ X(A, 1) #define SQUARES_LIST \ X(A, 1) \ X(A, 2) \ X(A, 3) \ X(A, 4) \ X(A, 5) \ X(A, 6) \ X(A, 7) \ X(A, 8) \ X(B, 1) \ X(B, 2) \ X(B, 3) \ X(B, 4) \ X(B, 5) \ X(B, 6) \ X(B, 7) \ X(B, 8) \ X(C, 1) \ X(C, 2) \ X(C, 3) \ X(C, 4) \ X(C, 5) \ X(C, 6) \ X(C, 7) \ X(C, 8) \ X(D, 1) \ X(D, 2) \ X(D, 3) \ X(D, 4) \ X(D, 5) \ X(D, 6) \ X(D, 7) \ X(D, 8) \ X(E, 1) \ X(E, 2) \ X(E, 3) \ X(E, 4) \ X(E, 5) \ X(E, 6) \ X(E, 7) \ X(E, 8) \ X(F, 1) \ X(F, 2) \ X(F, 3) \ X(F, 4) \ X(F, 5) \ X(F, 6) \ X(F, 7) \ X(F, 8) \ X(G, 1) \ X(G, 2) \ X(G, 3) \ X(G, 4) \ X(G, 5) \ X(G, 6) \ X(G, 7) \ X(G, 8) \ X(H, 1) \ X(H, 2) \ X(H, 3) \ X(H, 4) \ X(H, 5) \ X(H, 6) \ X(H, 7) \ X(H, 8) typedef enum sq8 : uint8_t { #define X(file, rank) SQ_##file##rank = SQ_FROM_RF(RANK_INDEX_##rank, FILE_INDEX_##file), SQUARES_LIST SQ_COUNT, SQ_POISONED, #undef X /* define iterator begin enum */ #define X(file, rank) SQ_BEGIN = SQ_##file##rank, SQUARES_LIST_BEGIN #undef X } Sq8; static char* const sq8_display[SQ_COUNT] = { #define X(file, rank) \ [SQ_##file##rank] = STR(file##rank), SQUARES_LIST #undef X }; static char* const sq8_str[SQ_COUNT] = { #define X(file, rank) \ [SQ_##file##rank] = STR(SQ_##file##rank), SQUARES_LIST #undef X }; static inline enum file_index sq_to_file(Sq8 p) { return p % 8ULL; } static inline enum rank_index sq_to_rank(Sq8 p) { return p / 8ULL; } /* ----------- Side8 ----------- */ typedef enum side : uint8_t { SIDE_WHITE, SIDE_BLACK, SIDE_COUNT, SIDE_BEGIN = SIDE_WHITE, } Side8; static inline Side8 other_side(Side8 p) { return (p == SIDE_WHITE ? SIDE_BLACK : SIDE_WHITE); } static char const* side_str[SIDE_COUNT] = { [SIDE_WHITE] = "SIDE_WHITE", [SIDE_BLACK] = "SIDE_BLACK", }; /* ----------- Piece8 ----------- */ /* https://en.wikipedia.org/wiki/X_macro */ /* enum value white char white unicode black char black unicode */ #define PIECES \ X(PIECE_EMPTY, 0, ' ', ' ', ' ', ' ') \ X(PIECE_PAWN, 100, 'P', 0x2659, 'p', 0x265F) \ X(PIECE_KNIGHT, 301, 'N', 0x2658, 'n', 0x265E) \ X(PIECE_BISHOP, 302, 'B', 0x2657, 'b', 0x265D) \ X(PIECE_ROOK, 500, 'R', 0x2656, 'r', 0x265C) \ X(PIECE_QUEEN, 900, 'Q', 0x2655, 'q', 0x265B) \ X(PIECE_KING, 1600, 'K', 0x2654, 'k', 0x265A) \ /**/ typedef enum piece : uint8_t { #define X(e, v, wc, wu, bc, bu) e, PIECES PIECE_COUNT, PIECE_BEGIN = PIECE_PAWN, PIECE_POISONED, /* used as undefined value in debug builds */ #undef X } Piece8; static Score16 piece_value[PIECE_COUNT] = { #define X(e, v, wc, wu, bc, bu) [e] = v, PIECES #undef X }; static char const* piece_str[PIECE_COUNT] = { #define X(e, v, wc, wu, bc, bu) [e] = STR(e), PIECES #undef X }; struct piece_side {Piece8 piece; Side8 side;} const piece_and_side_from_char[256] = { #define X(e, v, wc, wu, bc, bu) \ [(uint8_t)bc] = {.piece = e, .side = SIDE_BLACK}, \ [(uint8_t)wc] = {.piece = e, .side = SIDE_WHITE}, PIECES #undef X }; static char const piece_char[SIDE_COUNT][PIECE_COUNT] = { [SIDE_WHITE] = { #define X(e, v, wc, wu, bc, bu) [e] = wc, PIECES #undef X }, [SIDE_BLACK] = { #define X(e, v, wc, wu, bc, bu) [e] = bc, PIECES #undef X } }; static int const piece_unicode[SIDE_COUNT][PIECE_COUNT] = { [SIDE_WHITE] = { #define X(e, v, wc, wu, bc, bu) [e] = wu, PIECES #undef X }, [SIDE_BLACK] = { #define X(e, v, wc, wu, bc, bu) [e] = bu, PIECES #undef X } }; /* ----------- moves ----------- */ enum { MATTR_PROMOTE = 1<<0, MATTR_POISONED = 1<<1, }; struct move { Sq8 from; Sq8 to; uint8_t attr; #define APPEAL_MAX UINT8_MAX uint8_t appeal; }; /* * Move32 layout: * f (from piece): 3 bits * F (from square): 6 bits * t (to piece): 3 bits * T (to square): 6 bits * p (promotion): ? bits (likely 3) * [x,x,x,x,x,x,x,x,x,x,x,p,p,p,T,T,T,T,T,T,t,t,t,F,F,F,F,F,F,f,f,f] * */ typedef uint32_t Move32; #define MOVE_FROM_PIECE(m) (m & 0b000000000000000000111) #define MOVE_FROM_SQUARE(m) (m & 0b000000000000111111000) #define MOVE_TO_PIECE(m) (m & 0b000000000111000000000) #define MOVE_TO_SQUARE(m) (m & 0b000111111000000000000) #define MOVE_PROMOTION(m) (m & 0b111000000000000000000) _Static_assert(sizeof(struct move) == 4, "this static assuming is here to check when sizeof(move) changes"); #define MOVE_NULL (struct move){0} #define MOVE_POISONED (struct move) {.from = SQ_POISONED, .to = SQ_POISONED, .attr = MATTR_POISONED } #define IS_MOVE_NULL(m) ((m).from == (m).to) /* ----------- castle_direction ----------- */ enum castle_direction { CASTLE_BEGIN, CASTLE_KINGSIDE = CASTLE_BEGIN, CASTLE_QUEENSIDE, CASTLE_COUNT, }; /* -------------- stop flag --------------- */ /* occupy an entire cache line to avoid invalidation from neighboring writes */ struct searching_flag { alignas(CACHE_LINE_SIZE) atomic_uint_fast8_t v; uint8_t pad[CACHE_LINE_SIZE - sizeof(atomic_uint_fast8_t)]; }; static inline void searching_init(struct searching_flag* restrict sf) { atomic_init(&sf->v, 0); } static inline bool searching_still(struct searching_flag const* restrict sf) { return atomic_load_explicit(&sf->v, memory_order_relaxed); } static inline void searching_start(struct searching_flag* restrict sf) { atomic_store_explicit(&sf->v, 1, memory_order_relaxed); } static inline void searching_stop(struct searching_flag* restrict sf) { atomic_store_explicit(&sf->v, 0, memory_order_relaxed); }