-
Notifications
You must be signed in to change notification settings - Fork 3
Home
Documentation for Litama, a server for the Onitama board game.
- Found at https://litama.herokuapp.com
- Source code at https://github.com/TheBlocks/Litama
See the end of this document for a Python client example.
Connect to the server at wss://litama.herokuapp.com
with WebSocket. Note that you can also use the ws
protocol instead of wss
, but your connection will not be secure.
After connecting, you will be able to send commands and receive data from the server.
Format: create [username]
Example: create SomeUsername
Format: join [matchId] [username]
Example: join 5fa04e6ec83ffd1ff3e70217 AnotherUsername
Format: state [matchId]
Request the state of the game. This is the same information given to you if you have subscribed to a game state with the spectate
command.
Example: state 5fa04e6ec83ffd1ff3e70217
Format: move [matchId] [token] [card] [move]
-
[card]
must be in lowercase. - For
[move]
, letters are used for columns and numbers are used for rows. This is the same as in chess.
The server responds to this command with a confirmation that the move was made. If you are on a connection that has been subscribed to the game state (i.e. you sent a spectate
command), you will receive the game state as well in a following message.
Example: move 5fa04e6ec83ffd1ff3e70217 DpEI2fMXGur0yKKLPljlLjrbDegn53RN boar a1a2
Format: spectate [matchId]
This command subscribes you to all future game state broadcasts of this game. This is useful after you create or join a game, or as a spectator.
After a successful spectate command, you will receive 2 messages from the server: one to confirm the spectate command and one which broadcasts the current game state.
Example: spectate 5fa04e6ec83ffd1ff3e70217
All responses by the server are in JSON format.
- All responses contain a
"messageType"
key (string value) which tells you what the server is responding to or sending, as well as what you should expect in the message. - All responses contain a
"matchId"
key (string value) so that you know which game it is responding to. This allows you to play concurrent games over the same Websocket connection. Note that the matchId does not always have to be valid. For example, when trying to join a game with an invalid match id, the error message will use the id you sent.
The possible values for "messageType"
are:
"create"
"join"
"state"
"move"
"spectate"
"error"
These mirror the commands because a reply is sent in response to a command. The messageType of the reply will almost always be the same as the command you just used (exceptions include error and state messages). The format of each is described below.
Fields:
-
messageType
(string) -
matchId
(string) - You must give this ID to your opponent so that they can connect to the game. -
token
(string) - Use this token to make moves during the game. Do not share this. -
index
(int) - Keep track of this to know which side you are on. You need to check thestate
packet to see which side is your index.
Example:
{
"messageType": "create",
"matchId": "5f9e0312cf7016b31ea197c0",
"token": "waN5rQjbbZJcPs4QuejoApUqDzcqcPSe",
"index": 0
}
Fields:
-
messageType
(string) -
matchId
(string) - The id of the match that you just joined. -
token
(string) - Same ascreate
command. -
index
(int) - Same ascreate
command.
Example
{
"messageType": "join",
"matchId": "5f9e0312cf7016b31ea197c0",
"token": "DpEI2fMXGur0yKKLPljlLjrbDegn53RN",
"index": 1
}
Fields:
-
messageType
(string) -
gameState
(string) - Either"waiting for player"
(when only 1 player has joined),"in progress"
, or"ended"
. -
usernames
(JSON object containing strings) - The usernames of the players connected to the match. Both values will be the username of the first player if a second player has not connected yet. This is to prevent bruteforcing a desired side. -
matchId
(string) -
indices
* (JSON object containing ints) - The indices associated to each side. -
currentTurn
* (string) - Either"blue"
or"red"
and indicates who must make the next move. -
cards
* (JSON object containing string and 2 string arrays) - Contains the cards in play for each player and on the side. -
startingCards
* - Same ascards
but for the cards at the start of the game. -
moves
* (string array) - Contains all the moves that have been made. Moves are in"card:move"
format. E.g."boar:e1e2"
. -
board
* (string) - String representation of the current board. The leftmost digit is blue side. Each number represents a different piece, where 0 = no piece, 1 = blue student, 2 = blue master, 3 = red student, 4 = red master. See https://git.io/onitama to see how the board is laid out. The first character represents the piece of a1, second on b1, then c1, etc. -
winner
* (string) - Either"blue"
,"red"
, or"none"
.
Fields marked with * are only included in games with a gameState
of in progress
or ended
.
Example:
{
"messageType": "state",
"usernames": {
"red": "username1",
"blue": "username2"
},
"indices": {
"red": 1,
"blue": 0
},
"matchId": "5f9e0312cf7016b31ea197c0",
"currentTurn": "red",
"cards": {
"red": ["tiger", "crane"],
"blue": ["crab", "ox"],
"side": "elephant"
},
"startingCards": {
"blue": ["crab", "elephant"],
"red": ["tiger", "crane"],
"side": "ox"
},
"moves": ["elephant:a1b2"],
"board": "0121101000000000000033433",
"gameState": "in progress",
"winner": "none"
}
Just replies to let you know it succeeded.
Fields:
-
messageType
(string) -
matchId
(string)
Example:
{
"messageType": "move",
"matchId": "5f9e0312cf7016b31ea197c0"
}
Just replies to let you know it succeeded.
Fields:
-
messageType
(string) -
matchId
(string)
Example:
{
"messageType": "spectate",
"matchId": "5f9e0312cf7016b31ea197c0"
}
-
messageType
(string) -
matchId
(string) -
error
(string) - An error message. One of"Invalid command sent"
,"Match not found"
,"Not allowed to join"
,"Game ended"
,"Token is incorrect"
,"'move' or 'card' not given properly"
,"Cannot move opponent's pieces or empty squares"
, or"Invalid move"
. -
query
(string) - Shows which command this error is a response to
Example:
{
"messageType": "error",
"matchId": "5f9e0312cf7016b31ea197c0",
"error": "Invalid move",
"query": "move"
}
Here is a Python client to test out the server. Note that you need to press enter whenever you are expecting multiple server responses (i.e. after a spectate
command or after any other command when subscribed to a game state).
import asyncio
import websockets
async def litama():
uri = "wss://litama.herokuapp.com"
async with websockets.connect(uri) as websocket:
while True:
sent = input("> ")
# Press enter to just wait for the server's next response instead of sending anything
# This is useful when you get multiple responses for a single command.
# I.e. After sending a create, join, move, or spectate command.
if sent != "":
await websocket.send(sent)
received = await websocket.recv()
print(f">>> {received}")
asyncio.get_event_loop().run_until_complete(litama())