--- a/src/chess/rules.c Tue May 19 17:59:24 2026 +0200 +++ b/src/chess/rules.c Tue May 19 18:03:06 2026 +0200 @@ -144,6 +144,32 @@ } } +static void calc_movetime(GameState *gamestate, Move *move) { + struct timeval curtimestamp; + gettimeofday(&curtimestamp, NULL); + move->timestamp.tv_sec = curtimestamp.tv_sec; + move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; + + if (gamestate->movecount > 1) { + struct movetimeval lasttstamp = last_move(gamestate).timestamp; + uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; + suseconds_t micros; + if (curtimestamp.tv_usec < lasttstamp.tv_usec) { + micros = 1000000-(lasttstamp.tv_usec - curtimestamp.tv_usec); + sec--; + } else { + micros = curtimestamp.tv_usec - lasttstamp.tv_usec; + } + + move->movetime.tv_sec = sec; + move->movetime.tv_usec = (int32_t) micros; + } else { + /* no move time for the first move of both white and black */ + move->movetime.tv_usec = 0; + move->movetime.tv_sec = 0; + } +} + static void addmove(GameState* gamestate, Move *data) { if (gamestate->movecount == gamestate->movecapacity) { gamestate->movecapacity += 64; /* 32 more full moves */ @@ -154,29 +180,12 @@ Move *move = &gamestate->moves[gamestate->movecount]; *move = *data; - struct timeval curtimestamp; - gettimeofday(&curtimestamp, NULL); - move->timestamp.tv_sec = curtimestamp.tv_sec; - move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; - - if (gamestate->movecount > 1) { - struct movetimeval lasttstamp = last_move(gamestate).timestamp; - uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; - suseconds_t micros; - if (curtimestamp.tv_usec < lasttstamp.tv_usec) { - micros = 1000000-(lasttstamp.tv_usec - curtimestamp.tv_usec); - sec--; - } else { - micros = curtimestamp.tv_usec - lasttstamp.tv_usec; - } - - move->movetime.tv_sec = sec; - move->movetime.tv_usec = (int32_t) micros; - } else { - /* no move time for the first move of both white and black */ - move->movetime.tv_usec = 0; - move->movetime.tv_sec = 0; + /* only if move has no time info, compute it */ + if (move->movetime.tv_sec == 0 && move->movetime.tv_usec == 0) { + calc_movetime(gamestate, move); } + + /* important: only "add" the move after calculating the time! */ gamestate->movecount++; } @@ -280,7 +289,19 @@ } void apply_move(GameState *gamestate, Move *move) { - apply_move_impl(gamestate, move, 0); + apply_move_impl(gamestate, move, false); +} + +void gamestate_at_move(GameState *gamestate, + unsigned move_number, GameState *replay) { + gamestate_init(replay); + replay->review = true; + if (move_number > gamestate->movecount) { + move_number = gamestate->movecount; + } + for (unsigned i = 0 ; i < move_number ; i++) { + apply_move_impl(replay, &(gamestate->moves[i]), true); + } } static int validate_move_rules(GameState *gamestate, Move *move) { @@ -357,7 +378,7 @@ /* simulate move for check validation */ GameState simulation = gamestate_copy_sim(gamestate); Move simmove = *move; - apply_move_impl(&simulation, &simmove, 1); + apply_move_impl(&simulation, &simmove, true); /* find kings for check validation */ uint8_t piececolor = (move->piece & COLOR_MASK);