Beta

Overview

The goal of AlgoGames is to provide a place where programmers can write algorithms (“algos”) to play games. Our game engines easily interface with these algos to play matches and rank them based on their performance.

How it works

You write code to play a game. You upload your code, and our servers automatically rank your algo amongst the rest.

Our game code is seperated into the game engine and the game interface. The game engine is where all of the game logic is computed and the game interface is what allows your algos to interact with the game engine through a clean API.

The Algo

When a game is started, the game interface imports your algo and calls your setup function with the game’s initial configuration. Then, the engine sends game state information to your algo’s on_update function on each new game tick. This is where your algo makes gameplay decisions and executes them through the game interface.

Functions

on_update(state) — required

This is the main function where strategy logic is executed. It is called with every state the engine sends you. See the game-specific documentation for what on_update is given. It returns nothing: the move is sent through the game’s interface, which means an algo can decide not to move at all.

on_my_turn(state) — chess only

Chess is the one game where a state can arrive that is not yours to answer, because its players move one at a time. Both algos are sent every board, so you are shown the position your own move produced as well as the positions you have to play on:

The board you are senton_updateon_my_turn
It is your movecalledcalled, after on_update
It is your opponent’s move, which is the position your own move leftcallednot called

A move belongs in on_my_turn: the engine plays one move at a time, so a move sent for a board it did not ask you about forfeits the game. A chess algo defines on_update, on_my_turn, or both — one that only plays never has to ask whose turn it is, and one that only watches loses on the clock.

Anything you ask the engine while you are thinking ahead is answered without the boards around it going missing: a board that arrives while an answer is on its way is kept and reaches on_update in its turn, so asking a lot on your opponent’s time leaves you running on_update on boards that arrived a while ago.

Your clock only runs while it is your move, so thinking ahead in on_update while your opponent is to move costs you nothing — the same as a human studying the board on their opponent’s time. The one thing you pay for is overrunning: your clock starts the moment the engine sends you the board asking for a move, so if you are still busy with the one before it, that time is yours.

setup(...) — optional

If you define this, it is called once at the beginning of the game, before the first update. What it takes depends on the game, because each game has different things to tell you, and they arrive as named arguments rather than as one dictionary:

GameSignature
Snakesetup()
Duel Snakessetup(start_pos)
Chesssetup(color)
Racingsetup(track)

Snake tells you nothing, so its setup takes nothing. Leave the function out entirely if you have nothing to do before the first update. See the game-specific documentation for what each argument holds.

Keeping state between updates

An algo is a module rather than a class, so there is no self to hang onto. Anything you want to remember from one update to the next is a variable at the top of your file, and a function that writes to it says global first:

from algogames import SnakeInterface

turn_num = -1


def on_update(state):
    global turn_num
    turn_num += 1

    if turn_num == 0:
        SnakeInterface.log('first update')

Libraries Available

The Engine Interface

Each game has an interface that allows algos to communicate to the game engine. You use it as it is, without building one: import it and call it by name. Every interface has the method below, along with game-specific methods and attributes that can be found in the game’s respective documentation.

Methods

<Game>Interface.log(message)

Because game engines use the standard streams (stdin, stdout, and stderr) to communicate with algos, Python’s built-in print will cause issues. Instead, use this method to write to the replay console.

Anything your algo writes to stderr, such as a warning, a logging line or a traceback, also shows on its console, as an error line. Only your algo stopping ends its game.

Sending your move

Each game has its own way of being told what you want to do, and it is sent the moment you call it:

GameCall
SnakeSnakeInterface.set_direction(direction)
Duel SnakesDuelSnakesInterface.set_direction(direction)
ChessChessInterface.make_move(move)
RacingRacingInterface.set_controls(throttle, brake, steering)

Send one move per update. In Snake and Duel Snakes, sending several means the last one counts, and sending none leaves your snake carrying on as it was. In Racing, each control is the last value you sent for it, so a control you leave out stays as it was. Chess is stricter, because it plays one move and then asks the other algo: a move belongs in on_my_turn, sending none leaves the engine waiting until your clock runs out, and a second move on the same board — or any move sent from on_update — is a move it never asked for, which forfeits the game. So does a move that cannot be played on the board; every move in state.all_valid_moves can be.

The Game State

Each game has a state object that houses the current state of the game. In addition to housing information, some state objects have helper methods that perform common/menial tasks relevant to it’s respective game. See the game-specific documentation for details.

Every state has state.time_left: the seconds before the engine moves on without you, which is the end of the tick in Snake, Duel Snakes and Racing, and your clock running out in Chess. The engine sends the moment it will move on with each state, so reading it asks the engine nothing. It is measured each time you read it, so read it again as you work rather than keeping the number; it goes negative once that moment has passed.