Mon, 24 Aug 2026 15:48:19 +0200
complete documentation of the network protocol
resolves #938
# terminal-chess Network Protocol The network protocol for terminal-chess is designed in an interoperable manner, allowing for playing chess with other clients that implement the same protocol. This document describes the protocol in detail, including the message formats and the expected behavior of clients and the server. The current protocol version is 24. ## Message Format The terminal-chess network protocol has two different message types: * a code consisting of a single byte * a message composed of a single byte indicating the type plus a payload An example implementation covering both types is the following struct: ```C struct message { unsigned char code; unsigned char message[]; // flexible array member } ``` A table with all message codes can be found [below](#message-code-table). The datatypes used in the message payloads are as follows: * BYTE — a single byte * WORD — two bytes integer (little-endian) * DWORD — four bytes integer (little-endian) * MOVE — a data structure describing a move, consisting of * a DWORD for the elapsed move time in seconds * a DWORD for additional elapsed move time in microseconds * a BYTE describing the moved piece (see below) * a BYTE index for the file the piece was moved from * 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 the standard network byte order would be big-endian. But since the vast majority of processors use little-endian nowadays, this protocol uses little-endian, too. The following table shows the possible values for the BYTEs describing a piece. | Piece | Value (Hex) | |--------------|-------------| | White Pawn | 0x11 | | White Rook | 0x12 | | White Knight | 0x13 | | White Bishop | 0x14 | | White Queen | 0x15 | | White King | 0x16 | | Black Pawn | 0x21 | | Black Rook | 0x22 | | Black Knight | 0x23 | | Black Bishop | 0x24 | | Black Queen | 0x25 | | Black King | 0x26 | ## Handshake Immediately after a connection between a server and a client is established, the server SHALL send one single byte denoting the protocol version to the client. The client SHALL then immediately answer with their protocol version. After both parties have sent their version to the other party, they SHALL both compare their own version with the received version. When the versions do not match, both parties SHALL terminate the connection. The users SHOULD be informed about the protocol mismatch. ## Game Setup After a successful handshake, the server SHALL send the client information about the game they want to play. The server can set up a completely new game or continue an unfinished game. ### Starting a New Game When the server wants to start a new game, they SHALL send a `GAMEINFO` message. The payload of this message is as follows: * one BYTE denoting the color the server wants to play (16 or 0x10 = white, 32 or 0x20 = black) * one BYTE indicating if the game is played with time control (1 = yes, 0 = no) * one WORD for the initial clock time in seconds * one WORD for the number of seconds that are added per move * one WORD for the delay in seconds for each move When the game is played without time control, the last three WORDs MAY be left uninitialized, but they SHALL be sent anyway. ### Continuing a Game When the server wants to continue a game, they SHALL send a `PGNDATA` message. The payload of this message is as follows: * the same two BYTEs and three WORDs as in `GAMEINFO`, followed by * one WORD for the number `n` of moves that will follow * the `n` MOVEs that have been played already The server SHOULD NOT send a game that cannot be continued because it already has reached a checkmate, stalemate, or forced draw position. ### Clock Setup For clock synchronization, the following rules SHALL be applied: * the clock of each player starts after their first move * the _increment_ is added _after_ a move, except… * … when the initial clock is zero, then the clock starts with the increment * when the used time for a move is less than the delay, the move costs no time * the delay is always subtracted from the actual move time ## Playing the Game 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 If the active player wants to make a move, they SHALL send a `MOVE` message with one MOVE payload to the waiting player. The active player SHALL then wait for an `ACCEPT_MOVE` or `DECLINE_MOVE` message. When the waiting player receives a `MOVE` message, they SHOULD validate the move. When validation fails, they SHALL send a `DECLINE_MOVE` message with one byte indicating the reason why the move is declined. Otherwise, they SHALL send an `ACCEPT_MOVE` message. When the move is accepted, both players SHALL swap the active / waiting role. The reasons for declining a move are listed in the following table: | Reason | Value | Description | |-----------------------|-------|---------------------------------------------| | INVALID_MOVE_SYNTAX | 1 | E.g., indices out of bounds | | PIECE_NOT_FOUND | 2 | The piece is not at the specified position. | | NEED_PROMOTION | 4 | Target piece for promotion is missing. | | PIECE_PINNED | 5 | Piece cannot move because it is pinned. | | KING_IN_CHECK | 6 | The move would leave the king in check. | | KING_MOVES_INTO_CHECK | 7 | The king would be moved into check. | | MISSING_CHECK | 8 | The check-flag was not set. | | MISSING_CHECKMATE | 9 | The checkmate-flag is not set. | | INVALID_CHECK | 10 | The check-flag was incorrectly set. | | INVALID_CHECKMATE | 11 | The checkmate-flag was incorrectly set. | | RULES_VIOLATED | 32 | Other rules would be violated by this move. | ### End the Game The active player, before making a move, SHALL determine if the game has ended. The game SHALL be ended if a [checkmate](#checkmate) or [stalemate](#stalemate) position has been reached, or the [clock runs out](#clock-timeout). The game SHOULD be ended if a draw can be [claimed](#claim-a-draw) due to a threefold repetition of the same position, insufficient material, or playing 50 moves without any captures or pawn moves. The game MAY be ended at any time by any (including the waiting) player by [resignation](#resign). #### Checkmate Whe the active player determines they were checkmated with the last move, they SHALL send a `CHECKMATE` message to the waiting player. When receiving such a message, the waiting player SHALL end the game without sending any confirmation. #### Stalemate When the active player determines a stalemate position, they SHALL send a `STALEMATE` message to the waiting player. The waiting player SHOULD verify this claim. When verification fails, they SHALL send a `DECLINE` message, and they SHALL send an `ACCEPT` message, otherwise. Both parties SHALL end the game when the stalemate was agreed on. Otherwise, both parties SHOULD continue playing. #### Clock Timeout When the clock of the active player times out, they SHALL send a `TIMEOVER` message to the waiting player. When receiving such a message, the waiting player SHALL end the game without sending any confirmation. #### Claim a Draw The active player SHOULD claim a draw, when * the position is already repeated a third time (threefold repetition rule) * there is not enough material for both players on the board (nobody can win) * no capture or pawn move was made within the last 50 moves The draw is claimed by sending a `THREEFOLD`, `NOMATERIAL`, or `50MOVES` message, respectively. The waiting player SHOULD verify this claim. When verification fails, they SHALL send a `DECLINE` message, and they SHALL send an `ACCEPT` message, otherwise. Both parties SHALL end the game when the draw was agreed on. Otherwise, both parties SHOULD continue playing. #### Resign Both the active and the waiting player MAY send a `RESIGN` message any time. When a player receives a `RESIGN` message, they SHALL end the game without any further confirmation. ### Offer a Draw _TODO: draw offers by the active player are bugged - see issue #980_ _TODO: the description is very confusing and should be cleaned up after fixing issue #980_ Both the active and the waiting player MAY send a `REMIS` message any time to offer a draw. When the waiting player receives such an offer, they MAY choose to answer it with either an `ACCEPT` or a `DECLINE` message. When the offer was accepted, both players SHALL end the game. Otherwise, they SHALL continue playing. When an offer was declined, the requesting player SHOULD NOT send another offer for the same position. When the active player receives such an offer, they MAY ignore it. No confirmation is sent. Instead, if the player chooses to accept the offer, they SHALL send a `REMIS` message on their own. ### Propose Resignation The waiting player MAY propose resignation by sending a `TAUNT` message. The active player MAY ignore such messages completely. Implementations MAY choose to display a message to the active player. If the active player decides to follow the proposal, they SHOULD send a `RESIGN` message, as described [above](#resign). The waiting player SHOULD NOT use this message excessively or inappropriately. It serves to inform the opponent about a decisive position and is intended to encourage them to resign a lost game so that both players can make better use of their time. ## Message Code Table The following table shows the definitions of the network codes. | Code Name | Byte | With Payload | |--------------|------|--------------| | ACCEPT | 0x01 | no | | DECLINE | 0x02 | no | | GAMEINFO | 0x10 | yes | | PGNDATA | 0x11 | yes | | MOVE | 0x20 | yes | | ACCEPT_MOVE | 0x21 | no | | DECLINE_MOVE | 0x22 | yes | | CHECKMATE | 0x30 | no | | STALEMATE | 0x31 | no | | NOMATERIAL | 0x32 | no | | THREEFOLD | 0x33 | no | | 50MOVES | 0x34 | no | | RESIGN | 0x41 | no | | REMIS | 0x42 | no | | TAUNT | 0x43 | no | | TIMEOVER | 0x44 | no | The following codes are reserved for implementation. They are not used during transmissions and can be used as return values for functions to indicate errors. | Code Name | Byte | |-----------|------| | AGAIN | 0x70 | | CONNLOST | 0x80 | | ERROR | 0xFF |