# HG changeset patch # User Mike Becker # Date 1776360551 -7200 # Node ID 231a79d93c0c6dc95e637e77948426bfd488cd67 # Parent 9cb41383540fb44ab4302cafb1c9c0ccf2fb089f add API for calculating the clock for a specific move + fixes wrong handling of move time and increment in move 1 relates to #815 diff -r 9cb41383540f -r 231a79d93c0c src/chess/rules.c --- a/src/chess/rules.c Sat Apr 04 13:25:47 2026 +0200 +++ b/src/chess/rules.c Thu Apr 16 19:29:11 2026 +0200 @@ -158,7 +158,7 @@ move->timestamp.tv_sec = curtimestamp.tv_sec; move->timestamp.tv_usec = (int32_t) curtimestamp.tv_usec; - if (gamestate->movecount > 0) { + if (gamestate->movecount > 1) { struct movetimeval lasttstamp = last_move(gamestate).timestamp; uint64_t sec = curtimestamp.tv_sec - lasttstamp.tv_sec; suseconds_t micros; @@ -172,6 +172,7 @@ 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; } @@ -769,51 +770,49 @@ uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, uint8_t color) { + unsigned move_number = gamestate->movecount; + if (color == BLACK) { + move_number |= 1; + } else { + move_number = (move_number + 1) & ~1; + } + return remaining_movetime2(gameinfo, gamestate, move_number); +} + +uint16_t remaining_movetime2(GameInfo *gameinfo, GameState *gamestate, + unsigned move_number) { if (!gameinfo->timecontrol) { return 0; } - - if (gamestate->movecount > 0) { - uint16_t time = gameinfo->time; - suseconds_t micros = 0; + + unsigned total_time = gameinfo->time; + unsigned used_time = 0; + suseconds_t micros = 0; + + /* go through all already played moves */ + unsigned first_move = move_number % 2; + unsigned next_move = move_number; + if (next_move > gamestate->movecount) next_move = gamestate->movecount; + for (unsigned i = first_move ; i < next_move ; i += 2) { + used_time += gamestate->moves[i].movetime.tv_sec; + micros += gamestate->moves[i].movetime.tv_usec; + /* add increments starting with move 2 */ + if (i > 1) total_time += gameinfo->addtime; + } - for (unsigned i = color == WHITE ? 0 : 1 - ; i < gamestate->movecount ; i += 2) { - time += gameinfo->addtime; - - if (gamestate->moves[i].movetime.tv_sec >= time) { - return 0; - } - - time -= gamestate->moves[i].movetime.tv_sec; - micros += gamestate->moves[i].movetime.tv_usec; - } - - time_t sec; - Move *lastmove = &last_move(gamestate); - if ((lastmove->piece & COLOR_MASK) != color) { - struct movetimeval lastmovetstamp = lastmove->timestamp; - struct timeval currenttstamp; - gettimeofday(¤ttstamp, NULL); - micros += currenttstamp.tv_usec - lastmovetstamp.tv_usec; - sec = currenttstamp.tv_sec - lastmovetstamp.tv_sec; - if (sec >= time) { - return 0; - } - - time -= sec; - } - - sec = micros / 1000000; - - if (sec >= time) { - return 0; - } + /* when the player is currently playing, count down the clock */ + if (is_game_running(gamestate) && move_number > 1 && + move_number == gamestate->movecount) { + struct movetimeval lastmovetstamp = + gamestate->moves[move_number - 1].timestamp; + struct timeval currenttstamp; + gettimeofday(¤ttstamp, NULL); + used_time += currenttstamp.tv_sec - lastmovetstamp.tv_sec; + micros += currenttstamp.tv_usec - lastmovetstamp.tv_usec; + } - time -= sec; - - return time; - } else { - return gameinfo->time; - } + /* apply the microseconds */ + used_time += micros / 1000000; + + return used_time >= total_time ? 0 : total_time - used_time; } diff -r 9cb41383540f -r 231a79d93c0c src/chess/rules.h --- a/src/chess/rules.h Sat Apr 04 13:25:47 2026 +0200 +++ b/src/chess/rules.h Thu Apr 16 19:29:11 2026 +0200 @@ -231,6 +231,18 @@ */ void apply_move(GameState *gamestate, Move *move); +/** + * Returns the remaining time on the clock for the specified + * half-move number. + * + * @param gameinfo the information about the game + * @param gamestate the current game state + * @param move_number the half-move that is now going to be played + * @return the remaining time - if time control is disabled, this function + * always returns zero + */ +uint16_t remaining_movetime2(GameInfo *gameinfo, GameState *gamestate, + unsigned move_number); /** * Returns the remaining time on the clock for the specified player.