--- a/src/chess/rules.h Tue Jul 28 13:44:10 2026 +0200 +++ b/src/chess/rules.h Wed Jul 29 13:45:51 2026 +0200 @@ -30,6 +30,7 @@ #ifndef RULES_H #define RULES_H +#include <stdlib.h> #include <stdint.h> #include <stdbool.h> @@ -44,21 +45,21 @@ #define KING_MOVES_INTO_CHECK 7 #define RULES_VIOLATED 10 -#define ENPASSANT_THREAT 0x40 +#define ENPASSANT_THREAT 0x40u -#define WHITE 0x10 -#define BLACK 0x20 +#define WHITE 0x10u +#define BLACK 0x20u #define opponent_color(color) ((color)==WHITE?BLACK:WHITE) -#define PIECE_MASK 0x0F -#define COLOR_MASK 0x30 +#define PIECE_MASK 0x0Fu +#define COLOR_MASK 0x30u -#define PAWN 0x01 -#define ROOK 0x02 -#define KNIGHT 0x03 -#define BISHOP 0x04 -#define QUEEN 0x05 -#define KING 0x06 +#define PAWN 0x01u +#define ROOK 0x02u +#define KNIGHT 0x03u +#define BISHOP 0x04u +#define QUEEN 0x05u +#define KING 0x06u #define WPAWN (WHITE|PAWN) #define WROOK (WHITE|ROOK) @@ -74,6 +75,11 @@ #define BKING (BLACK|KING) 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 tv_sec; @@ -81,11 +87,11 @@ }; typedef struct { - uint8_t piece; - uint8_t fromfile; - uint8_t fromrow; - uint8_t tofile; - uint8_t torow; + Piece piece; + File fromfile; + Row fromrow; + File tofile; + Row torow; uint8_t promotion; uint8_t check; uint8_t capture; @@ -140,6 +146,17 @@ bool review; } GameState; +#define piece_type(piece) ((piece)&PIECE_MASK) +#define piece_color(piece) ((piece)&COLOR_MASK) +#define mkpiece(type,color) ((type)|(color)) + +#define enpassant_threat_add(gamestate, row, file) \ + (gamestate->board[row][file] |= ENPASSANT_THREAT) +#define enpassant_threat_remove(gamestate, row, file) \ + (gamestate->board[row][file] &= ~ENPASSANT_THREAT) +#define enpassant_threat_exists(gamestate, row, file) \ + (gamestate->board[row][file] & ENPASSANT_THREAT) + #define is_game_running(gamestate) !((gamestate)->checkmate || \ (gamestate)->wresign || (gamestate)->bresign || (gamestate)->threefold || \ (gamestate)->stalemate || (gamestate)->remis || (gamestate)->review) @@ -148,13 +165,13 @@ ((gamestate)->moves[(gamestate)->movecount-1]) #define POS_UNSPECIFIED UINT8_MAX -#define mdst(b,m) b[(m)->torow][(m)->tofile] -#define msrc(b,m) b[(m)->fromrow][(m)->fromfile] +#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) ((uint8_t)(idx) < 8) +#define isidx(idx) ((BoardIndex)(idx) < 8) /** Checks if the index is unspecified or valid. */ -#define isidxr(idx) ((idx) == POS_UNSPECIFIED || (uint8_t)(idx) < 8) +#define isidxr(idx) ((idx) == POS_UNSPECIFIED || (BoardIndex)(idx) < 8) #define isfile(file) (file >= 'a' && file <= 'h') #define isrow(row) (row >= '1' && row <= '8') @@ -169,7 +186,6 @@ #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED) #define rowidx_s(c) (isrow(c)?rowidx(c):POS_UNSPECIFIED) - /** * Initializes a game state and prepares the chess board. * @param gamestate the game state to initialize @@ -186,21 +202,22 @@ * Maps a character to a piece. * * Does not work for pawns, since they don't have a character. - * + * * @param c one of R,N,B,Q,K - * @return numeric value for the specified piece + * @param color the piece color + * @return the specified piece or zero when the character is invalid */ -uint8_t getpiece(char c); +Piece getpiece(char c, Color color); /** * Maps a piece to a character. * - * Does not work for pawns, scince they don't have a character. + * Does not work for pawns, since they don't have a character. * * @param piece may have color or additional flags * @return character value for the specified piece */ -char getpiecechr(uint8_t piece); +char getpiecechr(Piece piece); /** * Maps a piece to a unicode character sequence. @@ -208,10 +225,10 @@ * The returned unicode is for black pieces. * You may colorize the output by setting the terminal foreground color. * - * @param piece the piece to dispaly + * @param piece the piece to display * @return unicode character sequence for the specified piece */ -char* getpieceunicode(uint8_t piece); +char* getpieceunicode(Piece piece); /** * Returns the color of the player who is next to move. @@ -219,7 +236,38 @@ * @param gamestate the current game state * @return the color of the player who is next to move */ -uint8_t current_color(GameState *gamestate); +Color current_color(GameState *gamestate); + +/** + * Returns the piece at the specified position. + * + * @param gamestate the current game state + * @param row the row + * @param file the file + * @return the piece at the specified position + */ +Piece piece_at(const GameState *gamestate, Row row, File file); + +/** + * Places a piece at the specified position in the current game state. + * + * @param gamestate the current game state + * @param row the row + * @param file the file + * @param piece the piece to place at the specified position + */ +void piece_set(GameState *gamestate, Row row, File file, Piece piece); + +/** + * Removes the piece at the specified position in the current game state. + * + * @param gamestate the current game state + * @param row the row + * @param file the file + */ +static inline void piece_remove(GameState *gamestate, Row row, File file) { + piece_set(gamestate, row, file, 0); +} /** * Checks, if a specified field is covered by a piece of a certain color. @@ -233,13 +281,12 @@ * @param color the color of the piece that should threaten the field * @param threats the array where to store the threats (should be able to hold * the rare maximum of 16 elements) - * @param threatcount a pointer to an uint8_t where the count of threats is - * stored + * @param threatcount a pointer where the count of threats is stored * @return true, if any piece of the specified color threatens the specified * field (i.e. could capture an opponent piece) */ -bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move* threats, uint8_t* threatcount); +bool get_threats(GameState *gamestate, Row row, File file, + Color color, Move* threats, size_t* threatcount); /** * Checks, if a specified field is covered by a piece of a certain color AND @@ -254,13 +301,12 @@ * @param color the color of the piece that should threaten the field * @param threats the array where to store the threats (should be able to hold * the rare maximum of 16 elements) - * @param threatcount a pointer to an uint8_t where the count of threats is - * stored + * @param threatcount a pointer where the count of threats is stored * @return true, if any piece of the specified color threatens the specified * field (i.e. could capture an opponent piece) */ -bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color, Move* threats, uint8_t* threatcount); +bool get_real_threats(GameState *gamestate, Row row, File file, + Color color, Move* threats, size_t* threatcount); /** * Checks, if a specified field is covered by a piece of a certain color. @@ -304,8 +350,7 @@ * @return true, if any piece (excluding the king) of the specified color * threatens the specified field and could capture an opponent piece */ -bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, - uint8_t color); +bool is_protected(GameState *gamestate, Row row, File file, Color color); /** * Checks, if the specified move cannot be performed, because the piece is @@ -339,8 +384,7 @@ * @param color the color of the player to evaluate the move for * @return status code (see macros in this file for the list of codes) */ -int eval_move(GameState *gamestate, const char *mstr, - Move *move, uint8_t color); +int eval_move(GameState *gamestate, const char *mstr, Move *move, Color color); /** * Syntactically checks a move without verifying that a piece exists that is @@ -350,7 +394,7 @@ * @param color the color of the player to evaluate the move for * @return status code (see macros in this file for the list of codes) */ -int check_move(const char *mstr, uint8_t color); +int check_move(const char *mstr, Color color); /** * Validates move by applying chess rules. @@ -399,7 +443,7 @@ * @return the remaining time - if time control is disabled, this function * always returns zero */ -uint16_t remaining_movetime(GameState *gamestate, uint8_t color); +uint16_t remaining_movetime(GameState *gamestate, Color color); /** * Converts clock time to string.