--- a/src/chess/rules.h Mon Aug 24 16:13:51 2026 +0200 +++ b/src/chess/rules.h Tue Aug 25 18:35:18 2026 +0200 @@ -49,11 +49,27 @@ #define INVALID_CHECKMATE 11 #define RULES_VIOLATED 32 +#if __STDC_VERSION__ < 202310L +/* since #warning is also a C23 feature, the only hope is this: */ +#pragma GCC warning "Type safety for enums is only available since C23" +#define enum_uint8_t(name) enum e##name +#define typedef_enum_uint8_t(name) typedef uint8_t name +#else +#define enum_uint8_t(name) enum e##name : uint8_t +#define typedef_enum_uint8_t(name) typedef enum e##name name +#endif + #define ENPASSANT_THREAT 0x40u -#define WHITE 0x10u -#define BLACK 0x20u -#define opponent_color(color) ((color)==WHITE?BLACK:WHITE) +enum_uint8_t(Color) { + WHITE = 0x10u, + BLACK = 0x20u, +}; +typedef_enum_uint8_t(Color); + +static inline Color opponent_color(Color color) { + return color == WHITE ? BLACK : WHITE; +} #define PIECE_MASK 0x0Fu #define COLOR_MASK 0x30u @@ -65,25 +81,36 @@ #define QUEEN 0x05u #define KING 0x06u -#define WPAWN (WHITE|PAWN) -#define WROOK (WHITE|ROOK) -#define WKNIGHT (WHITE|KNIGHT) -#define WBISHOP (WHITE|BISHOP) -#define WQUEEN (WHITE|QUEEN) -#define WKING (WHITE|KING) -#define BPAWN (BLACK|PAWN) -#define BROOK (BLACK|ROOK) -#define BKNIGHT (BLACK|KNIGHT) -#define BBISHOP (BLACK|BISHOP) -#define BQUEEN (BLACK|QUEEN) -#define BKING (BLACK|KING) +enum_uint8_t(Piece) { + WPAWN = WHITE|PAWN, + WROOK = WHITE|ROOK, + WKNIGHT = WHITE|KNIGHT, + WBISHOP = WHITE|BISHOP, + WQUEEN = WHITE|QUEEN, + WKING = WHITE|KING, + BPAWN = BLACK|PAWN, + BROOK = BLACK|ROOK, + BKNIGHT = BLACK|KNIGHT, + BBISHOP = BLACK|BISHOP, + BQUEEN = BLACK|QUEEN, + BKING = BLACK|KING, +}; +typedef_enum_uint8_t(Piece); + +#define POS_UNSPECIFIED 255u +enum_uint8_t(Row) { + RANK_1 = 0, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, + RANK_UNSPECIFIED = POS_UNSPECIFIED +}; +typedef_enum_uint8_t(Row); + +enum_uint8_t(File) { + FILE_A = 0, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, + FILE_UNSPECIFIED = POS_UNSPECIFIED +}; +typedef_enum_uint8_t(File); typedef uint8_t Board[8][8]; -typedef uint8_t BoardIndex; -typedef BoardIndex Row; -typedef BoardIndex File; -typedef uint8_t Piece; -typedef uint8_t Color; struct movetimeval { uint64_t sec; @@ -154,31 +181,26 @@ bool review; } GameState; -#define piece_type(piece) ((piece)&PIECE_MASK) -#define piece_color(piece) ((piece)&COLOR_MASK) -#define mkpiece(type,color) ((type)|(color)) +#define piece_type(piece) ((uint8_t)(piece)&PIECE_MASK) +#define piece_color(piece) ((uint8_t)(piece)&COLOR_MASK) +#define mkpiece(type,color) (Piece)((type)|(color)) -#define POS_UNSPECIFIED UINT8_MAX #define mdst(m) (m)->torow, (m)->tofile #define msrc(m) (m)->fromrow, (m)->fromfile /** Checks if the index is specified and valid. */ -#define isidx(idx) ((BoardIndex)(idx) < 8) +static inline bool isidx(uint8_t idx) {return idx < 8;} /** Checks if the index is unspecified or valid. */ -#define isidxr(idx) ((idx) == POS_UNSPECIFIED || (BoardIndex)(idx) < 8) - -#define isfile(file) (file >= 'a' && file <= 'h') -#define isrow(row) (row >= '1' && row <= '8') +static inline bool isidxr(uint8_t idx) {return idx==POS_UNSPECIFIED || idx<8;} -#define rowidx(row) (row-'1') -#define fileidx(file) (file-'a') +static inline bool isfile(char file) {return file >= 'a' && file <= 'h';} +static inline bool isrow(char row) {return row >= '1' && row <= '8';} -#define rowchr(row) (row+'1') -#define filechr(file) (file+'a') +static inline Row rowidx(char row) {return row-'1';} +static inline File fileidx(char file) {return file-'a';} -/* secure versions - use, if index is not checked with isidx() */ -#define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED) -#define rowidx_s(c) (isrow(c)?rowidx(c):POS_UNSPECIFIED) +static inline char rowchr(Row row) {return (char)row+'1';} +static inline char filechr(File file) {return (char)file+'a';} static inline void enpassant_threat_add(GameState *gamestate,