--- a/src/chess/rules.h Mon Apr 27 18:06:00 2026 +0200 +++ b/src/chess/rules.h Tue Apr 28 12:25:48 2026 +0200 @@ -63,8 +63,9 @@ #define rowchr(row) (row+'1') #define filechr(file) (file+'a') -#define chkidx(move) (isidx((move)->fromfile) && isidx((move)->fromrow) && \ - isidx((move)->tofile) && isidx((move)->torow)) +#define chkidx_from(move) (isidx((move)->fromfile) && isidx((move)->fromrow)) +#define chkidx_to(move) (isidx((move)->tofile) && isidx((move)->torow)) +#define chkidx(move) (chkidx_from(move) && chkidx_to(move)) /* secure versions - use, if index is not checked with isidx() */ #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED) @@ -206,6 +207,12 @@ /** * Evaluates a move syntactically and stores the move data in the specified * object. + * + * When short algebraic notation is used, the source position is determined by + * the evaluating the allowed moves according to the current game state. + * + * For a purely syntactic check, regardless of whether a piece exists that is + * allowed to move that way, use check_move(). * * @param gamestate the current game state * @param mstr the input string to parse @@ -216,6 +223,16 @@ int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color); /** + * Syntactically checks a move without verifying that a piece exists that is + * allowed to move that way. + * + * @param mstr the input string to parse + * @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(char *mstr, uint8_t color); + +/** * Validates move by applying chess rules. * @param gamestate the current game state * @param move the move to validate