prepare netcode for claiming threefold repetition

Sun, 07 Jun 2026 14:55:20 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 07 Jun 2026 14:55:20 +0200
changeset 131
c33567d61ba7
parent 130
3fc6b1d6cbe9
child 132
5762f2b5f87a

prepare netcode for claiming threefold repetition

relates to #843

src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/network.h file | annotate | diff | comparison | revisions
--- 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;
+}
--- 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 */
 
--- 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,
--- 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 */

mercurial