341 lines
7.7 KiB
C
341 lines
7.7 KiB
C
#pragma once
|
|
|
|
/* ----------- 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.0f, ' ', ' ', ' ', ' ') \
|
|
X(PIECE_PAWN, 1.0f, 'P', 0x2659, 'p', 0x265F) \
|
|
X(PIECE_KNIGHT, 3.1f, 'N', 0x2658, 'n', 0x265E) \
|
|
X(PIECE_BISHOP, 3.2f, 'B', 0x2657, 'b', 0x265D) \
|
|
X(PIECE_ROOK, 5.0f, 'R', 0x2656, 'r', 0x265C) \
|
|
X(PIECE_QUEEN, 9.0f, 'Q', 0x2655, 'q', 0x265B) \
|
|
X(PIECE_KING, 16.0f, '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 float 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);
|
|
}
|