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,