diff -r 8bda076d0a16 -r 04c65336777f src/chess/rules.c --- a/src/chess/rules.c Sat Aug 22 15:15:52 2026 +0200 +++ b/src/chess/rules.c Sat Aug 22 16:22:05 2026 +0200 @@ -106,94 +106,6 @@ return (gamestate->movecount % 2 == 0) ? WHITE : BLACK; } -/* MUST be called BETWEEN validating AND applying a move to work correctly */ -static void format_move(const GameState *gamestate, Move *move) { - char *string = &(move->string[0]); - - /* at least 8 characters should be available, wipe them out */ - memset(string, 0, 8); - - unsigned int idx; - if (piece_type(move->piece) == KING && - abs(move->tofile-move->fromfile) == 2) { - /* special formats for castling */ - if (move->tofile==fileidx('c')) { - memcpy(string, "O-O-O", 5); - idx = 5; - } else { - memcpy(string, "O-O", 3); - idx = 3; - } - } else { - /* start by notating the piece character */ - string[0] = getpiecechr(move->piece); - idx = string[0] ? 1 : 0; - - /* find out how many source information we do need */ - if (piece_type(move->piece) == PAWN) { - if (move->capture) { - string[idx++] = filechr(move->fromfile); - } - } else if (piece_type(move->piece) != KING) { - /* resolve ambiguities, if any */ - Move candidates[16]; - size_t ccount; - if (get_real_candidates(gamestate, move->torow, move->tofile, - piece_color(move->piece), candidates, &ccount)) { - unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; - for (size_t i = 0 ; i < ccount ; i++) { - if (candidates[i].piece == move->piece) { - ambpiece++; - if (candidates[i].fromrow == move->fromrow) { - ambrows++; - } - if (candidates[i].fromfile == move->fromfile) { - ambfiles++; - } - } - } - /* neither file, nor row are ambiguous, name file */ - if (ambpiece > 1 && ambrows == 1 && ambfiles == 1) { - /* this is most likely the case with Knights - * in diagonal opposition */ - string[idx++] = filechr(move->fromfile); - } else { - /* ambiguous row, name file */ - if (ambrows > 1) { - string[idx++] = filechr(move->fromfile); - } - /* ambiguous file, name row */ - if (ambfiles > 1) { - string[idx++] = rowchr(move->fromrow); - } - } - } - } - - /* capturing? */ - if (move->capture) { - string[idx++] = 'x'; - } - - /* destination */ - string[idx++] = filechr(move->tofile); - string[idx++] = rowchr(move->torow); - - /* promotion? */ - if (move->promotion) { - string[idx++] = '='; - string[idx++] = getpiecechr(move->promotion); - } - } - - /* check? */ - if (move->checkmate) { - string[idx++] = '#'; - } else if (move->check) { - string[idx++] = '+'; - } -} - static void calc_movetime(GameState *gamestate, Move *move) { /* only if move has no time info, compute it */ if (move->movetime > 0) return; @@ -622,6 +534,106 @@ return canescape ? 1 : 2; } + +static void format_move_impl(const GameState *gamestate, Move *move) { + char *string = &(move->string[0]); + + /* at least 8 characters should be available, wipe them out */ + memset(string, 0, 8); + + unsigned int idx; + if (piece_type(move->piece) == KING && + abs(move->tofile-move->fromfile) == 2) { + /* special formats for castling */ + if (move->tofile==fileidx('c')) { + memcpy(string, "O-O-O", 5); + idx = 5; + } else { + memcpy(string, "O-O", 3); + idx = 3; + } + } else { + /* start by notating the piece character */ + string[0] = getpiecechr(move->piece); + idx = string[0] ? 1 : 0; + + /* find out how many source information we do need */ + if (piece_type(move->piece) == PAWN) { + if (move->capture) { + string[idx++] = filechr(move->fromfile); + } + } else if (piece_type(move->piece) != KING) { + /* resolve ambiguities, if any */ + Move candidates[16]; + size_t ccount; + if (get_real_candidates(gamestate, move->torow, move->tofile, + piece_color(move->piece), candidates, &ccount)) { + unsigned int ambrows = 0, ambfiles = 0, ambpiece = 0; + for (size_t i = 0 ; i < ccount ; i++) { + if (candidates[i].piece == move->piece) { + ambpiece++; + if (candidates[i].fromrow == move->fromrow) { + ambrows++; + } + if (candidates[i].fromfile == move->fromfile) { + ambfiles++; + } + } + } + /* neither file, nor row are ambiguous, name file */ + if (ambpiece > 1 && ambrows == 1 && ambfiles == 1) { + /* this is most likely the case with Knights + * in diagonal opposition */ + string[idx++] = filechr(move->fromfile); + } else { + /* ambiguous row, name file */ + if (ambrows > 1) { + string[idx++] = filechr(move->fromfile); + } + /* ambiguous file, name row */ + if (ambfiles > 1) { + string[idx++] = rowchr(move->fromrow); + } + } + } + } + + /* capturing? */ + if (move->capture) { + string[idx++] = 'x'; + } + + /* destination */ + string[idx++] = filechr(move->tofile); + string[idx++] = rowchr(move->torow); + + /* promotion? */ + if (move->promotion) { + string[idx++] = '='; + string[idx++] = getpiecechr(move->promotion); + } + } + + /* check? */ + if (move->checkmate) { + string[idx++] = '#'; + } else if (move->check) { + string[idx++] = '+'; + } +} + +void format_move(const GameState *gamestate, Move *move) { + /* correct check/checkmate flags */ + move->check = move->checkmate = false; + switch (determine_check_or_checkmate(gamestate, move)) { + case 2: move->checkmate = true; + case 1: move->check = true; + } + + /* format the move string */ + format_move_impl(gamestate, move); +} + static int validate_move_rules(const GameState *gamestate, const Move *move) { assert((move->piece & ~(PIECE_MASK|COLOR_MASK)) == 0); @@ -1162,18 +1174,18 @@ } /* format the move string */ - format_move(gamestate, move); + format_move_impl(gamestate, move); } } return result; } -int eval_move_lazy(const GameState *gamestate, +int eval_move(const GameState *gamestate, const char *mstr, Color color, Move *move) { return eval_move2(gamestate, mstr, color, move, true); } -int eval_move(const GameState *gamestate, +int eval_move_strict(const GameState *gamestate, const char *mstr, Color color, Move *move) { return eval_move2(gamestate, mstr, color, move, false); }