Protocol
Game loop
The run()
function uses its arguments, the receive_input and send_output callables,
to get player moves and send game-related info, respectively.
The former takes a Side
as its argument, stating which side is expecting input from.
It should return a 2-tuple of:
an
InputType
, indicating the input’s purposea 2-tuple of (or
None
under circumstances):
an
int
an
int
(orNone
under circumstances)
The latter takes an OutputType
as its first argument, indicating the output’s purpose.
Its second argument is the data, which can be a GameState
, a tuple of 2 int
s,
an InvalidMoveCode
, or a Side
. It can optionally take a third argument,
a Side
, indicating which side the output is addressed to. If the third argument is ommited
(should have a None
default value), the output concerns both sides.
Once the game starts, send_output sends the initial game state: the
OutputType.GAME_STATE
constant, and aGameState
instance.Then, it sends the turn-deciding die rolls: the
OutputType.TURN_ROLLS
constant, and aDieRolls
instance.Then, the game loop starts:
The dice are rolled and both sides get informed by send_output with: the
OutputType.MOVE_ROLLS
constant, and aDieRolls
instance.Note
If
run()
was called with move_by_turn_rolls set toTrue
, the above step will be skipped for the first iteration.Then, until a valid move is made, or game is won:
receive_input is called with the currently playing
Side
.If the first item of its results is
InputType.MOVE
:If the second item is
None
, send_output sendsOutputType.INVALID_MOVE
,InvalidMoveCode.INVALID_MOVE_TYPE
, and the currentSide
.Else, it tries to make the given move.
If it is invalid, send_output sends
OutputType.INVALID_MOVE
, anInvalidMoveCode
, and the currentSide
.Else, the move is made.
If game is won, send_output sends
OutputType.GAME_STATE
, and aGameState
instance. Then, it is called once more withOutputType.GAME_WON
. The game loop terminates.Else, if all the moves have been made for this turn, send_output sends
OutputType.GAME_STATE
, and aGameState
instance, and the other side starts their turn.
Else, if the first item is
InputType.UNDO
:If the second item is not
None
, send_output sendsOutputType.INVALID_MOVE
,InvalidMoveCode.INVALID_MOVE_TYPE
, and the currentSide
.Else, if there are no moves to undo, send_output sends
OutputType.INVALID_MOVE
,InvalidMoveCode.NOTHING_TO_UNDO
, and the currentSide
.Else, the last move is undone.
Else, send_output sends
OutputType.INVALID_MOVE
,InvalidMoveCode.INVALID_INPUT_TYPE
, and the currentSide
.
Moving
The board’s points are indexed from bottom right to bottom left, then top left to top right. The first player’s base is the bottom right quarter.
The move data should be a 2-tuple, consisting of:
the index of the die that is intended to be played, considering the order of the die rolls as they were sent by the game
the index on the board, of the piece to be moved (from source to desitnation), or
None
if player has pieces that have been hit
In case the move is invalid, send_output is called with OutputType.INVALID_MOVE
, an
InvalidMoveCode
, and the current Side
. Below is described which codes are sent in which cases:
InvalidMoveCode.DIE_INDEX_INVALID
Die index is already played
Die index does not exist
InvalidMoveCode.SOURCE_INVALID
Player has pieces that have been hit and source index is not
None
Player does not have pieces that have been hit and source index is
None
Source index does not exist
InvalidMoveCode.SOURCE_NOT_OWNED_PIECE
Source is not a piece belonging to the player
InvalidMoveCode.DESTINATION_OCCUPIED
Destination is occupied by two ore more opponent pieces
InvalidMoveCode.DESTINATION_OUT_OF_BOARD
Player is not bearing off and destination is out of the board