Coachable Agents Communication Standard

by John Davin, Patrick Riley, Yang Gu, and Manuela Veloso

We are also providing a C++ library for generating and parsing messages in this standard.

This standard uses variable length messages, and the player is free to include any combination of messages that it can fit in a say message string (the server currently allows 10 characters (say_msg_size), with 73 possible values for each ASCII character).

Each character will represent one piece of information (like a player number, message type, X position, etc.). While this is not the most efficient coding for space, it greatly simplifies the parsing of the messages.

The message encoding does not include the player number of the sending player because the server includes that information with say messages.

11/30/03 - Modified OpponentPos and TeammatePos message types to encode the player number in the message type ID. This allows these two message types to be sent with a cost of 4 units rather than 5. The new message type format is described in section 2 ("Message Types").
12/15/03 - Corrected a typo in the section 1 table (the ranges for the X and Y datatypes were mixed up).

1) Data types:

These are the types of data that will be represented. The range (in integral units) is listed for each type. Each data type will be represented by 1 character.

X x coordinate for a position [-53, 53)
Y y coordinate for a position [-34, 34)
dX, dY velocity values [-2.7,2.7)
#cycles confidence values for the other parameters of the message. (number of cycles since saw ball, or player) [0, 72)
player# a player number [0,11]*
msg type ID the msg ID (first char of every message) [0,29]**
* a player number of 0 can only be used in the "We have ball" and "Opponent has ball" messages listed below.
** range of msg type can expand if we add more allowable message types.

2) Message Types:

The first character in each message identifies the message type.

Message TypeSyntaxCost
Our Pos: [0, X, Y]3
Ball Pos: [1, X, Y, #cycles]4
Ball Velocity: [2, dX, dY, #cycles]4
We have ball: [3, player#]*2
Opponent has ball: [4, player#]*2
Passing to (player#): [5, player#]2
Passing to (X,Y): [6, X, Y]3
Want pass: [ 7 ]1
Opponent(player#) Pos:** [8+player#-1, X, Y, #cycles]4
Teammate(player#) Pos:** [19+player#-1, X, Y, #cycles]4
* "We have ball" and "Opponent has ball" messages can use 0 as the player# to indicate that the agent knows the team has the ball, but doesn't know which specific player number it is.
** Opponent Pos and Teammate Pos message types encode the player number in the message type ID. This is so that the messages will use only 4 characters rather than 5. The valid range for player# in computing the message type ID is [1,11].

3) Int to char and char to int conversion procedures:

char validchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSUVWXYZ().+-*/?<>_";

#define NUMCHARS 73 (note that validchars has 73 chars, so max array index is 72)

int to char:
char get_printablechar(int i){
Returns validchars[i] if i>=0 and i<NUMCHARS
Returns validchars[0] if i<0 (error case)
Returns validchars[NUMCHARS-1] if i>=NUMCHARS


char to int:
To convert from a message char to an int, the character should just be translated to its index in the validchars array. (ex, '0' -> 0, 'a' -> 10, 'c' -> 12, etc).

Rounding conventions: Divisions and multiplications in the following tables will be done with floating point arithmetic, and the final value will be cast to an int to be used as the index into the validchars array. This will be standard C integer casting - ie, the integer value will be the floor of the float.
Examples (int to char):
(20+53)/106 * NUMCHARS = 50.27 should return validchar[50].
(25+53)/106 * NUMCHARS = 53.72 should return validchar[53].

4) Mapping from Data type to server message char:

Data type valueEncoded character value
X get_printablechar( (X+53)/106 * NUMCHARS )
Y get_printablechar( (Y+34)/68 * NUMCHARS )
dX get_printablechar( (dX+2.7)/5.4 * NUMCHARS )
dY get_printablechar( (dY+2.7)/5.4 * NUMCHARS )
player# get_printablechar(player#)
msg type get_printablechar( msg type )

5) Mapping from message char to Data type value:

let i = index of the character in validchars[] (use char to int conversion from section 3 above)
(eg, for message char '2', i=2, and for message char 'a', i=10).

Data type for current charData value (eg, X,Y,dX,dY,etc)
X (i/NUMCHARS * 106) - 53
Y (i/NUMCHARS * 68) - 34
dX (i/NUMCHARS * 5.4)-2.7
dY (i/NUMCHARS * 5.4)-2.7
#cycles i
player# i
msg type i


Examples of possible messages that a player could say within the 10 character say_msg_size limit:

Encoding: After encoding, we have this message string (in pseudo code) which would be sent to the server as a say message:

get_printablechar(0) . get_printablechar((20+53)/106 * NUMCHARS) . get_printablechar((-10+34)/68 * NUMCHARS) . get_printablechar(1) . get_printablechar((30+53)/106 * NUMCHARS) . get_printablechar((29+34)/68 * NUMCHARS) . get_printablechar(5) . get_printablechar(5) . get_printablechar(4)
Encoded string = "0Op1V*554"

Decoding: A player who received this message would decode it by determining the indices in the validchars array for each character, and then reading in each message using table 5 above. The msg type ID (first character of each message unit) would be used to determine the meanings of the subsequent parameters.

To decode "0Op1V*554":

let i0 .. i8 = the index into the validchars array for each of the 9 characters received for this message (so i0=0 since validchars[0]='0', i1=50 since validchars[50]='O', i2=25 since validchars[25]='p', etc.)
i0 indicates an Our Pos message (which is the position of the player who sent the msg, as identified by the server's say msg parameters).
Our Pos X = (i1/NUMCHARS * 106) - 53 = 19.6
Our Pos Y = (i2/NUMCHARS * 68) - 34 = -10.7
i3 indicates a Ball Pos message.
Ball Pos X = (i4/NUMCHARS * 106) - 53 = 29.8
Ball Pos Y = (i5/NUMCHARS * 68) - 34 = 28.4
#cycles since saw ball = i6 = 5
i7 indicates a Passing to Player (#) message.
player# = i8 = 4

Other possible messages are:

Notes on Precision:

X: ~1.5 unit step size ( range is [-53,53] so step size in msg encoding is 106/73=1.45)

Y: 1 ( range [-34,34]=68 can be represented using the 73 char values)

dX,dY: .074 ([-2.7,2.7] so step size = 5.4/73 = .074)

The ranges and integer to char conversions (eg, (X+53)/106 * NUMCHARS ) were chosen to evenly space the value range for each of the character encodings. The omission of the maximum float value for some of the data types (ie, X=[-53,53)) was done in order to use all of the encoded char values to represent an equal range of float values. The inability to represent 53.0 is not a significant drawback because 53.0 will just map to the same character that 52.99... maps to, and 53.0 is greater than the field length anyway.

Last modified: Wed Feb 25 12:37:39 EST 2004