# HG changeset patch # User Mike Becker # Date 1780836920 -7200 # Node ID c33567d61ba7849520f0a90a30ebea190a0058e0 # Parent 3fc6b1d6cbe9432907ce17810df7856b1f9673b2 prepare netcode for claiming threefold repetition relates to #843 diff -r 3fc6b1d6cbe9 -r c33567d61ba7 src/chess/rules.c --- a/src/chess/rules.c Thu May 28 13:58:24 2026 +0200 +++ b/src/chess/rules.c Sun Jun 07 14:55:20 2026 +0200 @@ -922,3 +922,8 @@ return snprintf(str, 6, "%02u:%02u", minutes, seconds); } } + +bool check_threefold_repetition(GameState *gamestate) { + // TODO: implement threefold repetition detection + return false; +} diff -r 3fc6b1d6cbe9 -r c33567d61ba7 src/chess/rules.h --- a/src/chess/rules.h Thu May 28 13:58:24 2026 +0200 +++ b/src/chess/rules.h Sun Jun 07 14:55:20 2026 +0200 @@ -125,6 +125,7 @@ char premove[8]; bool checkmate; bool stalemate; + bool threefold; bool remis; bool wresign; bool bresign; @@ -134,7 +135,7 @@ } GameState; #define is_game_running(gamestate) !((gamestate)->checkmate || \ - (gamestate)->wresign || (gamestate)->bresign || \ + (gamestate)->wresign || (gamestate)->bresign || (gamestate)->threefold || \ (gamestate)->stalemate || (gamestate)->remis || (gamestate)->review) #define last_move(gamestate) \ @@ -395,5 +396,19 @@ */ int print_clk(uint16_t time, char *str, bool always_hours); +/** + * Checks if the current position already appeared two times before. + * + * This does not set the threefold flag in the game state as this flag is + * intended to be set only when the game ends after actually claiming a draw. + * + * By standard chess rules this is not automatically a draw. + * But implementation may choose to automatically draw the game anyway. + * + * @param gamestate the current game state + * @return true if the game is in a threefold repetition position + */ +bool check_threefold_repetition(GameState *gamestate); + #endif /* RULES_H */ diff -r 3fc6b1d6cbe9 -r c33567d61ba7 src/main.c --- a/src/main.c Thu May 28 13:58:24 2026 +0200 +++ b/src/main.c Sun Jun 07 14:55:20 2026 +0200 @@ -731,6 +731,18 @@ } } break; + case NETCODE_THREEFOLD: + /* validate the claim */ + if (check_threefold_repetition(gamestate)) { + /* auto-accept the claim */ + gamestate->threefold = true; + net_send_code(opponent, NETCODE_ACCEPT); + return 1; + } else { + /* silently decline, do not add message to UI */ + net_send_code(opponent, NETCODE_DECLINE); + } + break; case NETCODE_MOVE: { Move move; net_recieve_data(opponent, &move, sizeof(Move)); @@ -748,7 +760,29 @@ } else { net_send_code(opponent, NETCODE_ACCEPT); } - return 0; + /* check for threefold repetition */ + /* Note: in our implementation it is an auto-draw claimed + * by the player confronted with the position. By standard + * chess rules, also the player who creates the position may + * claim the draw. But since we do it automatically, it makes + * no practical difference. + */ + if (check_threefold_repetition(gamestate)) { + /* send this as a new package (basically as next move) */ + net_send_code(opponent, NETCODE_THREEFOLD); + /* the protocol supports declining the claim */ + uint8_t resp = net_recieve_code(opponent); + if (resp == NETCODE_ACCEPT) { + gamestate->threefold = true; + return 1; + } else { + /* does not happen in our implementation */ + // TODO: somehow add a message to the UI + return 0; + } + } else { + return 0; + } } else { uint32_t reason = htonl(code); net_send_data(opponent, NETCODE_DECLINE, diff -r 3fc6b1d6cbe9 -r c33567d61ba7 src/network.h --- a/src/network.h Thu May 28 13:58:24 2026 +0200 +++ b/src/network.h Sun Jun 07 14:55:20 2026 +0200 @@ -45,6 +45,7 @@ #define NETCODE_CHECK 0x22 #define NETCODE_CHECKMATE 0x24 #define NETCODE_STALEMATE 0x28 +#define NETCODE_THREEFOLD 0x30 #define NETCODE_RESIGN 0x41 #define NETCODE_REMIS 0x42 #define NETCODE_TAUNT 0x43 @@ -53,7 +54,7 @@ #define NETCODE_CONNLOST 0x80 #define NETCODE_ERROR 0xFF -#define NETCODE_VERSION 19 +#define NETCODE_VERSION 20 typedef struct { int fd; /* -1, if we are the client */