This is a Python client for AI battles! This is a boilerplate repository for quickly getting a bot set up that can connect and authenticate with the server. How the bot implements and plays the game is up to you.
The server is currently being hosted on Heroku: https://blunderdome-server.herokuapp.com/
Server code here: https://github.com/dprgarner/battlebot-server
Before playing a game, each bot needs to register with the server. This consists of making a POST request to the GraphQL endpoint /graphql
, consisting of the game type, the name of the bot, and your name. The server will return a response containing the bot data and the password, which is used to authenticate the bot when connecting via websocket. This registration can be done via the online GraphiQL interface at /graphql
.
The provided helper file register.py
will make this request and save the JSON file to auth.json
. To save the authentication data to a different file, add the --auth
parameter, e.g. --auth=auth2.json
.
> $ python register.py --hostname=blunderdome-server.herokuapp.com --gametype=NOUGHTS_AND_CROSSES --owner=David --name=MyAwesomeBot
Bot MyAwesomeBot registered successfully
> $ cat auth.json
{
"hostname": "blunderdome-server.herokuapp.com",
"password": "8ad86f2934f347abf60ee7c192c96fbc8383de273c4c092de7ae97151b84d934",
"name": "MyAwesomeBot"
}
When a websocket connection is made, after the initial WebSocket handshake, the client should send a JSON object containing the game type gameType
, the name of the bot name
, and the bot's password password
. The server will then return the JSON { "authentication": "ok" }
if the login is successful, or disconnect if not. If the authentication is successful, the server will pair the bot off with any other connected bot to a start a game, or will maintain the connection if no other connected bots are available.
The provided helper file client.py
will handle the connection to the server, using the saved auth.json
file, and wait for a game to start.
> $ python client.py
Bot connected - waiting to start game...
Traceback (most recent call last):
File "client.py", line 79, in <module>
Client()
File "client.py", line 15, in __init__
self.play_game()
File "client.py", line 75, in play_game
raise NotImplementedError('Write your bot\'s logic here.')
NotImplementedError: Write your bot's logic here.
The provided client.py file should be modified or extended with your custom logic for running the game. All communication between the client and server is via JSON, so the client provides the two helper methods recv
, which pauses until the server sends some data and then decodes it to an object, and send
, which encodes a JSON-serialisable object and sends the data to the server. If the server closes the connection, the method recv
will return None.
To play in a contest, add the name of the contest as an argument, e.g.
> $ python client.py --contest=round-robin
The client will add an extra key to the login hash and will repeatedly attempt to reconnect after each game is played. The server will match up bots which are playing in the contest with other bots in the contest, provided that they have played each other less than five times in the contest. The API endpoint /games/<game_name>/contest/<contest_name>
gives a summary of the games played in the contest and the rankings of the bots. A bot scores three points for a win, one point for a draw, and no points for a loss. Ties are broken on most wins, then fewest losses.
As soon as a game starts, the server will send an update of the following form to the client bot:
{
"state": {
"bots": [
"IdiotBot2",
"IdiotBot"
],
"complete": false,
"board": [
[
"",
"",
""
],
[
"",
"",
""
],
[
"",
"",
""
]
],
"waitingFor": ["IdiotBot2"],
"marks": {
"X": "IdiotBot2",
"O": "IdiotBot"
}
}
}
The client sends turns to the server, and the server validates the turn and responds with the new state and the played turn. A turn dispatched from the client to the server should look like this:
{
"mark": "X",
"space": [2, 2]
}
A space is specified as a two-entry array, with each entry an integer from 0 to 2, specifying the row and column to place the mark in respectively. The mark should be "O" or "X", depending on whether the client is playing "X"es or "O"s.
The following is an example of a server response, at the end of the game:
{
"turn": {
"name": "IdiotBot2",
"valid": true,
"space": [1, 2],
"time": 1498036964996,
"mark": "X"
},
"state": {
"complete": true,
"bots": [
"IdiotBot2",
"IdiotBot"
],
"reason": "complete",
"board": [
[
"O",
"O",
"X"
],
[
"X",
"O",
"X"
],
[
"O",
"X",
"X"
]
],
"marks": {
"X": "IdiotBot2",
"O": "IdiotBot"
},
"waitingFor": ["IdiotBot"],
"victor": "IdiotBot2"
}
}
If a bot disconnects the websocket during the course of the game, then the bot is disqualified. If the bot makes three invalid moves, or takes longer than five seconds to play a move, then the bot is disqualified.
If you want to test your bot out, I'd suggest registering a second bot and having them play each other. I've also written a bot which randomly plays valid noughts and crosses turns, but doesn't really have any strategy - I can spin this up to repeatedly connect to the server when someone wants to try their own bot out.
Happy bot-writing!
The documentation of this game is kept here: https://github.com/dprgarner/battlebot-server#bumblebots
The boilerplate Python client bumblebots.py
moves each drone in a random direction on each tick, without checking for the validity of the move, or making any attempt to move towards a flower. The client also prints out a representation of the board after each tick, with the drones superimposed on the board (rendered as @
s and &
s.) Hopefully this should be enough to get started!
ISC