All communication is conceptually line-oriented, but, in order to permit including arbitrary octet sequences, lines are delimited not by a terminator octet sequence but rather by a prefix count. A line is represented by sending a its octet count, as a valid number (see below), then a terminator, which must be 0x7e (ASCII ~), then as many octets as the count specifies. It is an error if the count is not a valid number or the count terminator octet is wrong. Communication is not lock-step; in principle, either end may send a line of data at any time. In the descriptions below, double quotes "" mark literal text (which must be in ASCII), with whitespace always explicitly mentioned where it can occur. Brackets [] mark optional portions, and the line length field is never mentioned explicitly. A line is limited to no more than 65536 octets, not including the count and count terminator; exceeding this limit is an error. When something "is an error", it indicates that a conformant implementation never generates such a thing, and receiving it is a protocol violation, for which no recovery procedure is specified. Most implementations will probably act more or less as if the connection had dropped unexpectedly. A "valid number" is zero or more octets giving a number in decimal ASCII. Leading 0s must not appear; a value of 0 is represented as zero octets. A valid number's value will always be in the range 0 through 1048575. A "counted string" below is a string of arbitrary content, sent as an octet count as a valid number, then a terminator, which must be 0x22 (ASCII "), then as many octets as the count specifies. An incorrect count terminator character is an error. Counted strings may in general be zero-length, though in some cases zero-length strings are errors. A "simple number" is a valid number, then a terminator, which must be 0x23 (ASCII #). An incorrect count terminator character is an error. Such numbers are inherently unsigned. When a line contains entities that are partially or wholly self-delimiting, there is the possibility for stray octets. (For example, a line whose definition specifies that it ends with a counted string has the possibility for stray octets after the string.) If any such octets are present, it is an error. A connection may be in any of three states: UNREGISTERED, MEETING, or PLAYING. All connections start out UNREGISTERED; to convert from UNREGISTERED to MEETING, a client uses a REG line, which the server responds to with a YOUARE line. UNREGISTERED connections may not do anything but register with REG (and PING and PONG). The server also maintains a set of pending games, games waiting for more players. A pending game may be open, in which case anyone may join it, or closed, in which case a password is required to join it. In either case, as soon as a game has its required complement of players willing to play in it, the game begins and all the players involved switch to PLAYING, leaving any (other) pending games they may be involved in. When a game ends, its players switch back to MEETING. Any MEETING player may create a game at any time, specifying player count and board size (and password, for closed games), and may join any game (given the password, for closed games). Whenever a player enters the MEETING state, the server generates a series of PLAYER lines giving the current list of MEETING clients and GAME lines giving the current list of pending games; as clients enter and leave the MEETING state, the server generates PLAYER lines, and as pending games appear and disappear, the server generates GAME lines, to keep these lists current. A pending game disappears either by starting, which happens as soon as it has its complement of players, or by being abandoned, which happens as soon as all involved players leave it. Players join and leave pending games with JOIN lines, and create new games with NEWGAME lines. As players join and leave pending games without the games themselves disappearing, GAME lines are generated to keep the count of desired players up-to-date. Update lines (PLAYER and GAME) are sent to all MEETING clients. Line formats follow, together with an indication of which end sends them (a leading C and/or S, for client and/or server, in parens). A line not conforming to one of these formats is an error. (CS) "MAGIC:" str dir N This must be the first line sent by either side; it is an error if not (not even PING and PONG may occur earlier). str is a counted string holding the "magic number" string "vwfhrjkuzdqpfhbjxzihdxnsyhqinuoputwozofbivhixhms". dir is a single octet saying whether the sending end is speaking the protocol from the point of view of a client (0x63, ASCII c) or server (0x73, ascii s). N is simple number giving the protocol version number, which must be 1 for the protocol described here. (CS) "PING:" data At any time after sending its MAGIC line, either end may send a PING line. data may be any number of octets, with any value, provided the protocol limits are not exceeded. A PING must always elicit a PONG. Note that the PONG may be delayed if there are messages queued for delivery by the end sending the PONG - the PONG will normally go at the tail of the delivery queue - but this behaviour must not be relied upon for correctness. However, if multiple PINGs are sent, the PONGs will be sent in order, possibly interleaved with messages generated by the other end. (CS) "PONG:" data This must be sent in response to a PING, and at no other time. The data must be identical to the data found in the PING that provoked the PONG. (C) "REG:" name name is a counted string, giving a name which is attached to the player on the list of players. It need not be unique, since other information such as the host address and name will be attached as well, but uniqueness usually helps. The name may not be longer than 64 octets. REG is not permitted unless the connection is UNREGISTERED. (S) "YOUARE:" ID ID is a short string assigned by the server, identifying the player, sent as a counted string; it is an error for it to be zero-length. YOUARE is sent in response to a REG line, telling the client which its own ID string is, so it can recognize it in contexts like PLAYER and GAME lines. This is sent before any PLAYER:+ lines provoked by the REG. (S) "PLAYER:+" ID addr ident playername Identifies a newly-MEETING player. ID is a short string assigned by the server, and acts as an identifier for this player elsewhere; it will not be zero-length. addr is a text representation of the client host's address (usually a text representation of an IP address, such as 10.20.30.40 or 1234:56:7::ab4). ident is a further mechanized identification string; for connections over IP, this will typically be generated by means such as querying an RFC1413 daemon. playername is the name string provided by the client in its REG line. Each of these is sent as a counted string. ("Newly-MEETING" means from the point of view of the player receiving it; for example, when a player joins, it gets a PLAYER:+ line for each MEETING player, even long-standing ones.) (S) "PLAYER:-" ID Identifies a player who is no longer a MEETING player. ID is the player's ID string, sent as a counted string. After this, the ID string is no longer valid and may be reassigned to another player. (S) "GAME:+" ID flags totplayers curplayers pcsize bdsize gamename plID... Describes a pending game. ID is a short string assigned by the server, acting as an identifier for this game elsewhere, and is sent as a counted string; it will not be zero-length. flags is a counted string holding flag characters indicating aspects of the game; see below. totplayers is the total number of players the game wants; curplayers is the current number of players in the game; pcsize is the size of the pieces, the number of squares in the largest piece; bdsize is the size of the board, the number of squares to a side of the board. Each of the four is sent as a simple number. gamename is a string specified when the game was created, for human benefit; it is sent as a counted string. Following gamename are one or more player ID strings, curplayers of them in all, giving the IDs of the players currently in the game; each is sent as a counted string. The flags string contains zero or more octets from 0x00 Present: the game is closed; absent: open. This is generated each time a player joins or leaves a game (unless the join or leave abandons or begins the game, in which case GAME:- is generated instead, or BEGIN: to the players involved if the game begins). (S) "GAME:-" ID Describes the disappearance of a pending game. ID is a counted string holding the game's ID, as given on its GAME:+ line. After this, the ID string is no longer valid and may be reassigned to another game. When a game disappears because it begins, no GAME:- line is sent to the players participating in the game. (C) "JOIN:+o" gameID gameID is a counted string giving a game ID. The player sending the JOIN line joins that game. This form works only for open games. (C) "JOIN:+c" gameID password gameID is a counted string giving a game ID; password is a counted string giving its password. The player sending the JOIN line joins that game, if the password is correct. This form works only for closed games. (C) "JOIN:-" gameID gameID is a counted string giving a game ID. The player sending the JOIN line withdraws from that game. This works only if the player is already joined to the game. (S) "JOINSTAT:" status This is sent by the server in response to a JOIN command. status is a single octet indicating whether the JOIN command worked or not: 0x00 The JOIN command worked. 0x01 The JOIN was issued by a non-MEETING connection. (This can happen with a non-broken client, if a game begins while a JOIN is in transit.) 0x02 No such pending game was found. (This usually means the game started or was abandoned, but can also be caused by the client supplying a bad game ID.) 0x03 A JOIN:+c specified a wrong password. 0x04 A JOIN:- tried to withdraw from a game that existed but which the player was not joined to. A JOIN command which results in a game starting still produces a JOINSTAT line (which in that case will always indicate success); in this case, the JOINSTAT occurs before any of the messages resulting from the game's beginning. (C) "NEWGAME:" flags totplayers size gamename [password] Creates a new game. flags is a counted string holding flag characters, indicating aspects of the game; see below. totplayers and size are simple numbers giving the total desired player count and the game size, as for GAME lines. gamename is the game's name, as for GAME lines. The flags string contains zero or more octets from 0x00 Present: the game is closed; absent: open. Usually, this will provoke a GAME:+ line in response, but if totplayers is 1, the game begins immediately. totplayers must be in [1..4] and size must be in [1..8]; it is not a protocol error for these to be out of range, but no game is created if they are. If the game is closed, the password for it is also given (as a counted string). The player must be MEETING for this to work. If issued when PLAYING, no error occurs, but no game is created; any other state is an error. (S) "BEGIN:" nplayers pcsize bdsize yournum plID... Indicates that a game is beginning. This is sent to each of the players involved in the game; the rest of the players simply see the game disappearing and the players leaving any other games they were joined to. nplayers and pcsize are the totplayers and size values from when the game was created; bdsize is the size of the board side and is chosen by the server based on pcsize. Each of the three is sent as a simple number. yournum (also a simple number) differs for each player, describing where that player stands in the game's turn order; see below. Following yournum are nplayers player ID strings, each sent as a counted string, giving the players involved, in order of increasing yournum values. yournum and nplayers between them allow each client to work out how the turn rotation goes. nplayers=1 yournum will be 0 and the player plays all four colours in turn. nplayers=2 yournum will be 0 or 1; the players play alternately, each playing two diagonally opposite colours. nplayers=3 yournum will be 0, 1, or 2; players play in order of increasing yournum values, with the fourth player played by the three players in rotation. nplayers=4 yournum will be in [0..3]; players play in order of increasing yournum values. A list of PIECE messages follows immediately, then a TURN message. The TURN message is not redundant; the turn rotation does not necessarily begin with the player with a yournum of 0 (except for nplayers=1 games, of course), and, for three-player games, which player first plays the fourth colour also is not necessarily any particular yournum value. (S) "PIECE:" ID bitmap These list the pieces available to the players. ID is a counted string giving a short identifier for this piece; it is an error for it to be zero-length. bitmap is a counted string holding the bitmap. Conceptually, the bitmap is an XxY rectangle of bits; this bitmap is encoded as an octet holding X, then an octet holding Y, then ceil((X*Y)/8) octets holding the bitmap. 0 bits represent spaces and 1 bits represent piece squares; the bits are packed into bytes by first converting them to a bitstream in (X,Y) order (0,0), (1,0), ..., (X-1,0), (0,1), (1,1), ..., (X-1,1), ..., (X-1,Y-2), (0,Y-1), (1,Y-1), ..., (X-1,Y-1), padding with 0 to 7 trailing 0 bits so the bit string holds a multiple of 8 bits, and grouping into 8-bit pieces. Each 8-bit piece is sent as an octet, ordered such that within an octet, earlier bits in the bitstring are more significant within the octet, and such that earlier 8-bit chunks in the string are earlier octets. For example, the size-6 piece with filled squares at (0,0), (1,0), (1,1), (1,2), (2,2), and (1,3) occupies a 3x4 rectangle * * . . * . . * * . * . and is represented by the octet sequence 0x03 0x04 0xc9 0xa0 (which is then wrapped in counted-string framing when the PIECE line is formed). The rectangle will always be minimal; that is, its first and last row and column will be nonblank. The number of piece shapes in the game is not explicitly represented anywhere; it can be determined by counting PIECE lines between the BEGIN and the following TURN. (S) "TURN:+" colour [4thplayer] (S) "TURN:-" colour [4thplayer] The next colour to play is colour, which is a number in the range [0..np-1] where np is the nplayers value for the game the receiving player is involved in; it is sent as a simple number. 4thplayer is present only when nplayers=3; it gives the yournum value of the next player to play colour 3 (if colour is 3, the value given is for this turn). If the character before colour is +, the player receiving it is next to play; if -, not. (S) "TURN:DONE" [score...] The game is over. Players are returned to UNREGISTERED status and should send REG lines to reregister for more games if desired, or disconnect if not. For nplayers=1 games, no score values follow. For nplayers=2 games, two scores follow, the first being the sum of the scores for player 0's colours, the second, for player 1's. For nplayers=3 games, three scores follow, the scores for players 0, 1, and 2 in order; the fourth colour's score is ignored. For nplayers=4 games, four scores follow, in order, 0, 1, 2, and 3. Scores, when present, are always simple numbers. A colour's score is the number of squares covered by that colour on the board, plus a 12.5% bonus if all that colour's pieces were played. (C) "PLAY:" piece transform locX locY This is how a player plays. piece is a counted string holding the ID from the PIECE line for the piece being played. transform is a counted string describing how it is being transformed; see below. locX and locY are simple numbers giving where the piece is being played. This is always the board cell closest to (0,0) covered by the transformed piece rectangle. transform is a counted string holding zero or more octets giving transformations which are applied to the piece image before it is placed, here described by giving the size of the post-transformation rectangle in terms of the pre-transformation sizes (X,Y), and giving how to locate the contents of a post-transformation cell (x,y) in the pre-transformation image. octet size transform description 0x00 (X,Y) (X-1-x,y) reflect about a vertical line 0x01 (X,Y) (x,Y-1-y) reflect about a horizontal line 0x02 (Y,X) (y,x) reflect about the X=Y line The transformations are applied in the order they appear in the transform string. If the play is acceptable, a PLAYED line is produced to each player and a new TURN line is produced; if not, a PLAYFAIL line is produced to the player who tried to PLAY and nothing is produced to the others. The square that must be covered by a colour's first move is (where B is the board's size): colour cell 0 (0,0) 1 (0,B-1) 2 (B-1,B-1) 3 (B-1,0) (S) "PLAYFAIL:" reason A PLAY attempt failed. reason is a single octet giving the reason it failed: 0x00 It's not the player's turn. 0x01 The piece has already been played. 0x02 The piece would fall partially or wholly off the board. 0x03 The piece would overlap an already-played piece. 0x04 The piece does not touch corner-to-corner with an already-played piece of the same colour. 0x05 The piece touches edge-to-edge with an already-played piece of the same colour. 0x06 The piece does not cover that colour's corner square. 0x07 The transform contains an invalid octet. 0x08 The piece ID is not valid. Note that some reasons are impossible for some moves; for example, 0x06 is possible only for a colour's first move. If multiple errors can apply, which one is reported is not specified (for example, it's possible for all of 0x00 through 0x05 to apply simultaneously; in this case, any of them may be the one reported). (S) "PLAYED:" colour piece transform locX locY colour has played piece transformed by transform at (locX,locY). colour is as for TURN lines; piece, transform, locX, and locY are as for PLAY lines. The transform may not be the same string as on the PLAY line, but the effect on the board will be correct. (As examples of why the transform may differ, the server may find it convenient to canonicalize it, or may send different transforms of the bitmaps to different players in their PIECE lines and thus need to send different transform strings to get the same effect on the board.) (C) "CHAT:" to msg to is a player ID string, or a zero-length string, represented as a counted string. msg is a counted string giving a text message. If to is not a zero-length string, the text message is sent to the player named by it; if it is zero-length, the text message is sent to "everyone" - which means all MEETING players, when the CHAT comes from a MEETING player, or all players in the current game, when the CHAT comes from a PLAYING player. It is not possible for players in different games to communicate, nor for a PLAYING player and a MEETING player. This always provokes a CHATSTAT reply from the server. (S) "CHATSTAT:" status This responds to a CHAT line, giving what happened. status is a single octet: 0x00 The CHAT worked; the message was sent. 0x01 The destination player does not exist or is inaccessible to the sending player. (S) "MSG:" from kind msg This carries text from a CHAT command. from is the originating player's ID and msg is the message, each as a counted string; kind is a single octet describing the kind of message (see CHAT): 0x00 The message was sent to "everyone" 0x01 The message was sent to just this player