fix regression in network play: we have to transmit capture/check(mate) flags default tip

Mon, 24 Aug 2026 13:42:35 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 24 Aug 2026 13:42:35 +0200
changeset 186
8230904458a7
parent 185
c0acc89d6c01

fix regression in network play: we have to transmit capture/check(mate) flags

PROTOCOL.md file | annotate | diff | comparison | revisions
src/chess/pgn.c file | annotate | diff | comparison | revisions
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
test/run-tests.c file | annotate | diff | comparison | revisions
--- a/PROTOCOL.md	Mon Aug 24 13:20:19 2026 +0200
+++ b/PROTOCOL.md	Mon Aug 24 13:42:35 2026 +0200
@@ -39,6 +39,9 @@
   * a BYTE index for the row the piece was moved from
   * a BYTE index for the file the piece was moved to
   * a BYTE index for the row the piece was moved to
+  * a BYTE set to 1 if this is a capturing move and to zero if it is not
+  * a BYTE set to 1 if this move gives check, 2 if it gives checkmate, and
+    zero otherwise
   * a BYTE describing the selected piece for promotion (otherwise zero)
 
 Note carefully that the byte order used by this protocol is little-endian while
@@ -116,7 +119,17 @@
 
 ## Playing the Game
 
-TODO: describe
+The game is played by exchanging moves.
+We call the player supposed to make the next move the _active_ player.
+The other player we call the _waiting_ player.
+
+### Make a Move
+
+### Resign
+
+### Offer or Claim a Draw
+
+### Propose Resignation
 
 ## Message Code Table
 
--- a/src/chess/pgn.c	Mon Aug 24 13:20:19 2026 +0200
+++ b/src/chess/pgn.c	Mon Aug 24 13:42:35 2026 +0200
@@ -155,6 +155,7 @@
         if (move_validate_result != VALID_MOVE_SEMANTICS) {
             return(pgn_error_move_semantics);
         }
+        format_move(gamestate, &move);
         apply_move(gamestate, &move);
         
         /* skip spaces */
--- a/src/chess/rules.c	Mon Aug 24 13:20:19 2026 +0200
+++ b/src/chess/rules.c	Mon Aug 24 13:42:35 2026 +0200
@@ -535,7 +535,7 @@
 }
 
 
-static void format_move_impl(const GameState *gamestate, Move *move) {
+void format_move(const GameState *gamestate, Move *move) {
     char *string = &(move->string[0]);
 
     /* at least 8 characters should be available, wipe them out */
@@ -622,18 +622,6 @@
     }
 }
 
-void format_move(const GameState *gamestate, Move *move) {
-    /* correct check/checkmate flags */
-    move->check = move->checkmate = false;
-    switch (determine_check_or_checkmate(gamestate, move)) {
-        case 2: move->checkmate = true;
-        case 1: move->check = true;
-    }
-
-    /* format the move string */
-    format_move_impl(gamestate, move);
-}
-
 static int validate_move_rules(const GameState *gamestate, const Move *move) {
     assert((move->piece & ~(PIECE_MASK|COLOR_MASK)) == 0);
 
@@ -1025,6 +1013,7 @@
     }
     char mstr[8];
     strcpy(mstr, pstr);
+    strcpy(move->string, pstr);
     
     /* evaluate check/checkmate flags */
     if (mstr[len-1] == '+' || mstr[len-1] == '#') {
@@ -1155,7 +1144,7 @@
     return VALID_MOVE_SYNTAX;
 }
 
-int eval_move2(const GameState *gamestate,
+static int eval_move2(const GameState *gamestate,
         const char *mstr, Color color, Move *move, bool lazy) {
     int result = eval_move1(mstr, move, color);
     if (result == VALID_MOVE_SYNTAX) {
@@ -1172,9 +1161,6 @@
                     case 1: move->check = true;
                 }
             }
-
-            /* format the move string */
-            format_move_impl(gamestate, move);
         }
     }
     return result;
--- a/src/chess/rules.h	Mon Aug 24 13:20:19 2026 +0200
+++ b/src/chess/rules.h	Mon Aug 24 13:42:35 2026 +0200
@@ -527,9 +527,12 @@
 /**
  * Calculates the move string within the specified move.
  *
- * This corrects any missing check / checkmate flags, first.
+ * The string calculated in short algebraic notation.
+ * The @p gamestate is needed to determine how to disambiguate the move,
+ * if necessary.
  *
- * Do not call this function after eval_move() or eval_move_strict().
+ * Recommended to be called before apply_move() so that a clean
+ * move string is added to the list of recorded moves.
  *
  * @param gamestate the current game state
  * @param move the move data
--- a/src/main.c	Mon Aug 24 13:20:19 2026 +0200
+++ b/src/main.c	Mon Aug 24 13:42:35 2026 +0200
@@ -478,6 +478,7 @@
                 if (result == VALID_MOVE_SYNTAX) {
                     result = validate_move(gamestate, &move);
                     if (result == VALID_MOVE_SEMANTICS) {
+                        format_move(gamestate, &move);
                         apply_move(gamestate, &move);
                         if (is_game_running(gamestate)) {
                             return 0;
@@ -496,13 +497,13 @@
     }
 }
 
-#define NETMOVE_LEN 14
+#define NETMOVE_LEN 16
 #define NETGI_LEN 8
 
 static NetGameInfo hton_gi(GameInfo gi) {
     return (NetGameInfo) {
         .servercolor = gi.servercolor,
-        .timecontrol = gi.timecontrol ? 1 : 0,
+        .timecontrol = gi.timecontrol,
         .time = net_htons(gi.time),
         .addtime = net_htons(gi.addtime),
         .delay = net_htons(gi.delay)
@@ -526,7 +527,9 @@
         .piece = move.piece,
         .fromfile = move.fromfile, .fromrow = move.fromrow,
         .tofile = move.tofile, .torow = move.torow,
-        .promotion = move.promotion
+        .capture = move.capture,
+        .check_or_mate = move.checkmate + move.check,
+        .promotion = move.promotion,
     };
 }
 
@@ -540,8 +543,9 @@
         .fromfile = move.fromfile, .fromrow = move.fromrow,
         .tofile = move.tofile, .torow = move.torow,
         .promotion = move.promotion,
-        /* flags are also calculated before applying the move */
-        0
+        .check = move.check_or_mate,
+        .checkmate = move.check_or_mate >> 1,
+        .capture = move.capture
     };
 }
 
@@ -676,6 +680,7 @@
                             || code == NETCODE_CHECKMATE
                             || code == NETCODE_STALEMATE
                             || code == NETCODE_NOMATERIAL) {
+                        format_move(gamestate, &move);
                         apply_move(gamestate, &move);
                         if (is_game_running(gamestate)) {
                             return 0;
@@ -812,9 +817,9 @@
             NetMove nmove;
             net_recieve_data(opponent, &nmove, NETMOVE_LEN);
             Move move = ntoh_move(nmove);
-            format_move(gamestate, &move);
             code = validate_move(gamestate, &move);
             if (code == VALID_MOVE_SEMANTICS) {
+                format_move(gamestate, &move);
                 apply_move(gamestate, &move);
                 if (gamestate->checkmate) {
                     net_send_code(opponent, NETCODE_CHECKMATE);
--- a/src/network.h	Mon Aug 24 13:20:19 2026 +0200
+++ b/src/network.h	Mon Aug 24 13:42:35 2026 +0200
@@ -86,6 +86,8 @@
     uint8_t fromrow;
     uint8_t tofile;
     uint8_t torow;
+    uint8_t capture;
+    uint8_t check_or_mate;
     uint8_t promotion;
 } NetMove;
 
--- a/test/run-tests.c	Mon Aug 24 13:20:19 2026 +0200
+++ b/test/run-tests.c	Mon Aug 24 13:42:35 2026 +0200
@@ -47,5 +47,5 @@
     }
     printf("\nTotal success: %u | failure: %u\n", success, failure);
 
-    return failure > 0 ? 1 : 0;
+    return failure > 0;
 }

mercurial