Player implementations are external to the game itself. A player is a separate executable that communicates with the game via standard input and standard output. The player is executed when the game starts up and continues running until the game is finished. At the start of each turn, the game engine sends the player a description of the game state. The player reads this description from standard input, chooses a move and sends it back by writing it to standard output.
The game state is sent to the player in a plain-text format. The first line contains a turn number, t. Under normal operation, the value of t will start with zero and increment by one with each game snapshot received by the player. The next line contains a positive integer, p, giving the number of pucks. This is followed by p lines, each describing a single puck. A puck is described by five parameters, floating point X and Y coordinates for the center of the puck, floating point X and Y components of the puck's velocity and an integer indicating the puck's color. The player's color is represented by zero, the opponent's color by one and grey by two.
The list of pucks is followed by a list of bumpers. The bumper list starts with an integer, b, indicating the number of bumpers. This is followed by b lines, each describing a single bumper. A bumper is described by four parameters, floating point X and Y coordinates for the bumper's center and floating point X and Y components of the bumper's velocity. Although the bumper list begins with a count of the number of bumpers, this count will always be four. The list of bumpers is ordered so that the two owned by the player are the first two on the list, and the two owned by the opponent are the second two.
The game state ends with a list of sleds. This list starts with an integer s indicating the number of sleds. This is followed by 2 s lines, two lines for each sled. A sled description starts with location and orientation information on the first line. The floating point X and Y location of the center of the sled is followed by a floating point rotation value giving the direction the sled is moving. The sled direction is measured counter-clockwise in radians from the positive X axis. This direction reflects the cumulative effect of of the various turns the sled has made, and it will not necessarily fall in the [ -π, π] range. For example, if the player constantly makes left turns, the sled direction will only increase.
The second line of a sled description gives a description of the trail behind the sled. This is given as an integer n followed by n floating-point X, Y pairs. The trail description starts with the oldest point on the trail and ends with the sled's current location. Wrapping around the edges of the field is indicated by including a point on each edge in the trail. For example, if the sled wrapped around from the left edge of the field to the right edge, the trail would include a point ( 0, y ) followed immediately by a point ( 800, y ).
There are always two sleds. Like the bumpers, the sled descriptions are ordered so that the player's sled is given first and the opponent's sled is given second.
The termination of the game is indicated by a value of -1 for the turn number. Player should read game states and respond with moves until they encounter a turn number of -1.
At each turn, the player is to print a desired move to standard output. The move is described by five floating point parameters, the X and Y components of an acceleration vector to be applied to the first bumper, the X and Y components of an acceleration vector to be applied to the second bumper and a desired change in direction for the player's sled. Left turns for the sled are expressed as positive values, and turns to the right expressed as negative values. The five parameters for each move should be printed, space-separated on a single output line. To ensure that the game is able to read the move immediately after it is produced, the player should flush standard output after the move is printed.
Player moves are applied instantly at the start of the turn. The requested changes in sled direction and bumper velocity are made all at once, and then the next turn is simulated.
If the player requests an acceleration value for a bumper or a turn angle for the sled that is too large, the values are constrained to the legal range. For example, if a player requests that the sled turn -0.6 radians, the sled will turn only -0.5 radians. Acceleration vectors for the bumpers are constrained to 8 in magnitude. If the player provides an acceleration vector that is larger than this, the game will apply an acceleration of 8 in the same direction as the vector provided by the player.
After a snapshot of the game state is sent, the player generally has 0.1 seconds to respond with a move. For the first turn of the game, the player has a full second to respond, but subsequent turns give the player only 0.1 seconds. The additional time for the first move reflects the need to give languages like Java an opportunity to demand-load code used by the player. This can cause the first move to take longer than subsequent moves.
If the player fails to respond or if the response is received too late, the game will assign a null move to the player, with all five move parameters set to zero. The game expects to receive a move for each state that is sent to a player, but the game engine does not maintain a queue of game states on behalf of each player. If a player falls behind in parsing game states and responding with a desired move, the engine will discard, rather than queue, subsequent states for the player. A player that is too slow to respond will receive a sampling of the states, and the value of the turn number will indicate that one or more states have been dropped.
At the end of the game, a report is printed to standard output indicating any game states that were discarded without being sent to each player. Likewise, a list is printed reporting any moves that were not received from the player in time.
Communication with the player is encoded so that both players can think of themselves as the red player, the one that starts out on the left. Internally, the first player given at startup is considered the red player. For the second player, game state is encoded with coordinates for all objects rotated 180 degrees, object lists reversed and colors re-mapped so that both players can believe they are starting on the left edge of the screen. Although the game engine uses zero to represent red, one to represent blue, and two to represent grey, colors in the player's game state description are re-mapped so that zero is the player's own color, one is the opponent's color and two is grey. This is intended to simplify the design of the player somewhat. Developers may wish to hard-code some behaviors with coordinates or color values chosen at compile time.
Players take turns every 0.1 seconds. The 0.1 second delay is intended to give the player an adequate time to select a next move. However, recording animation frames at this rate yields a jumpy playback of recorded games. To help smooth things out, the game engine writes out additional, intermediate states to game trace files. A turn is logged as 3 frames, each reflecting an intermediate state of the turn's simulation. This behavior should not be visible to players participating in the game, but, if ignored, it might cause some confusion about apparent inconsistency between the player's view of the game and the contents of a game trace file.
Your player's standard output is used to communicate with the game engine. While developing your player, you will want to send any debugging output you need to standard error rather than standard output, so that the game engine doesn't think it's part of your move.
As described later in this document, the game engine can operate synchronously with the player, waiting indefinitely for each move before performing the next simulation step. This lets the developer suspend the real-time response requirement during debugging. The game engine can also be configured to dump game state and player move information for every turn in a game. This can let the developer inspect the sequence of messages exchanged between the game after a game is completed.
Once you have a working player, you will want to submit it to the Queue ICPC Challenge site to see how it does against real opponents.
Player code will be compiled and will run on a virtual machine running on a 3.0 Ghz Xeon processor installed with version 5.2 CentOS. Java submissions will be compiled and run with version 1.6 of the Sun JDK, and C++ submissions will be compiled with version 4.1.2 of g++. C# submissions will be compiled and run using version 2.6.1 of of Mono.
Player code will have uncontested use of a single core and 1 GB of physical memory, except for the overhead associated with the operating system and the virtual machine environment. During execution, player submissions will be permitted to read from standard input and write to standard output and standard error. They may also open files in the current directory for reading and even create new threads. Attempts to access other system resources (e.g., read from files elsewhere, create network connections, start new processes) may result in disqualification.
Players may be implemented in either C/C++/C# or Java. Each turn, the player interacts with the game by reading game states from standard input and writing a desired move to standard output.
Source code for a player may consist of multiple files, but all files must reside in a single directory. Java implementations should place all classes in the default package.
Submissions can include source files and data files supporting the player, but the submission for a single player cannot exceed 256 kilobytes in total size and 50 individual files. During execution, player's source code and any other submitted files will be available in the current directory.
For C/C++ submissions, all files ending in .cpp will be compiled and linked together into an executable. During compilation, the submission directory will be the current directory. Player code will be compiled with the -O option and will be linked with -lpthread.
For Java submissions, all files ending in .java will be compiled. Only one main function is expected in the resulting classes, and that class will be executed as the player.
For C# submissions, all files ending in .cs will be compiled with a single invocation of gmcs. The resulting executable will be run via mono.
Submission language is determined by the file name extensions used in the submission. Submissions that appear to contain a mixture of languages (e.g. some ending in .java and some in .cpp) will be considered invalid, as will submissions do not compile or do not have a single entry point.