Mon, 24 Aug 2026 13:42:35 +0200
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);