Skip to main content

Python SDK for running bots on Game AI Arena, supports FlipFour, FlipFlop3x3/5x5, Amoeba

Project description

Game AI Arena SDK

Python SDK for running bots on Game AI Arena.

Installation

pip install game-ai-arena-sdk

Configuration

Set the matchmaker URL via environment variable or pass directly:

# Environment variable (recommended)
export MATCHMAKER_URL=ws://<SERVER_ADDRESS>:9000/matchmaking/ws

# Or for tunnel mode
export MATCHMAKER_URL=wss://<YOUR_TUNNEL>.trycloudflare.com/matchmaking/ws

Get the correct URL from your admin.

Getting Your Credentials

Option A: Swagger UI

  1. Open http://<SERVER>:9000/docs in your browser
  2. Use /api/auth/signup to create an account
  3. Click Authorize and enter your access token
  4. Use /api/bots/ POST to create a bot (save the bot_api_key - shown once!)
  5. Use /api/bots/ GET to find your bot's id

Option B: curl

# Set your server URL (get this from your admin)
SERVER="http://<SERVER_ADDRESS>:9000"

# 1. Create account
curl -X POST $SERVER/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "username": "yourname", "password": "SecurePass123"}'

# Response: {"access_token": "eyJhbG...", ...}
TOKEN="paste_your_access_token_here"

# 2. Create a bot
curl -X POST $SERVER/api/bots/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"bot_name": "MyBot", "game_type": "flipflop_3x3"}'

# Response: {"message": "Bot created successfully", "bot_api_key": "..."}
# Save the bot_api_key - it's only shown once!

# 3. Get your bot ID (query your user's bots)
USER_ID="your-user-id"  # from signup response or /api/profile
curl -X POST $SERVER/api/users/$USER_ID/bots \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{}'

# Find your bot in the response, copy its "id" field

Quick Start

import random
from game_ai_arena_sdk import Bot, start, GameType, Move, GameStateLoop

class MyBot(Bot):
    async def on_move(self, state: GameStateLoop) -> Move:
        piece = random.choice(state.legal_moves)
        dest = random.choice(piece.valid_moves)
        return Move(from_pos=piece.pos, to_pos=dest)

bot = MyBot(bot_id="YOUR_BOT_ID", api_key="YOUR_API_KEY")

# Uses MATCHMAKER_URL env var, or pass explicitly:
start(bot, GameType.FLIPFLOP_3X3)
# Or: start(bot, GameType.FLIPFLOP_3X3, matchmaker_url="ws://...")

Practice Mode

Test your bot locally using the Practice Arena in the web UI. Create a session, then run your bot with the provided connection info:

from game_ai_arena_sdk import Bot, start_practice, Move, GameStateLoop

class MyBot(Bot):
    async def on_move(self, state: GameStateLoop) -> Move:
        ...

bot = MyBot(bot_id="YOUR_BOT_ID", api_key="YOUR_API_KEY")

start_practice(
    bot,
    room_id="<from Practice Arena>",
    game_server_ws="<from Practice Arena>",
)

Or run with env vars: ROOM_ID=... GAME_SERVER_WS=... python my_bot.py

No matchmaker needed — your bot connects directly to the game room. Practice games don't affect ELO.

GameStateLoop

Received in on_move:

Field Description
board Board string representation
my_side Your side ("white" / "black")
current_turn Whose turn it is
legal_moves List of PieceMovesInfo you can move

Each PieceMovesInfo has name, pos, and valid_moves.

Hooks

All optional except on_move:

async def on_move(self, state: GameStateLoop) -> Move  # Required
async def on_ready(self) -> None                       # Connected to matchmaker
async def on_queue_entry(self) -> None                 # Joined queue
async def on_queue_exit(self) -> None                  # Leaving queue
async def on_match_found(self, match_id: str) -> None  # Matched with opponent
async def on_room_joined(self, room_id: str) -> None   # Joined game room
async def on_game_start(self, state: GameStateLoop) -> None
async def on_game_end(self, winner: str | None, state: GameStateEnd) -> None
async def on_disconnect(self, reason: str) -> None     # Disconnected

Multiple Bots

import asyncio
from game_ai_arena_sdk import run

async def main():
    await asyncio.gather(
        run(MyBot("id1", "key1"), GameType.FLIPFLOP_3X3),
        run(MyBot("id2", "key2"), GameType.FLIPFLOP_3X3),
    )

asyncio.run(main())

Note: Bots owned by the same user cannot be matched against each other. To test two bots locally, they must belong to different user accounts.

FlipFour Notes

FlipFour has two move types: placement (from hand) and movement (on board).

When placing a piece from hand, you must specify the side ("+" for orthogonal, "x" for diagonal):

# Placement: piece from hand onto the board
Move(from_pos="HAND", to_pos="C3", side="+")  # place as orthogonal
Move(from_pos="HAND", to_pos="C3", side="x")  # place as diagonal

# Movement: existing piece on board (side flips automatically)
Move(from_pos="A1", to_pos="A4")  # no side needed

In legal_moves, hand placements appear as two entries with pos="HAND":

  • PieceMovesInfo(name="+", pos="HAND", valid_moves=[...]) -- place as +
  • PieceMovesInfo(name="x", pos="HAND", valid_moves=[...]) -- place as x

Board pieces appear with their current side and position:

  • PieceMovesInfo(name="+", pos="C3", valid_moves=["A3", "B3", ...])
class MyFlipFourBot(Bot):
    async def on_move(self, state: GameStateLoop) -> Move:
        piece = random.choice(state.legal_moves)
        target = random.choice(piece.valid_moves)
        side = piece.name if piece.pos == "HAND" else None
        return Move(from_pos=piece.pos, to_pos=target, side=side)

start(bot, GameType.FLIPFOUR)

Game Types

Type Enum Description
FlipFlop 3x3 FLIPFLOP_3X3 3x3 board, rook/bishop pieces
FlipFlop 5x5 FLIPFLOP_5X5 5x5 board, rook/bishop pieces
FlipFour FLIPFOUR 5x5 board, 4 pieces per player, line-of-four wins
Amoeba AMOEBA Hexagonal grid, kernel capture wins

Amoeba Notes

Amoeba is played on a hexagonal board (radius 3) using two-part axial coordinates (q,r).

Key mechanics:

  • Each player has 1 kernel + 10 standard pieces
  • Pieces can stack on top of each other; the top piece controls the stack
  • Stack height determines mandatory move distance (a stack of 3 must move exactly 3 cells)
  • Win by capturing the opponent's kernel (landing on it) or when opponent has no legal moves
  • Threefold repetition is a draw; staleness and move caps use stack-control tiebreakers

Splitting moves:

When moving a stack, you can optionally split it by setting splitting=True. This spreads pieces along the movement path instead of keeping them together:

# Normal move: entire stack moves together
Move(from_pos="0,0", to_pos="2,-1")

# Split move: pieces spread along the path
Move(from_pos="0,0", to_pos="2,-1", splitting=True)

The legal action space already includes both normal and split variants. Choose from state.legal_moves, then pass through that entry's splitting value; don't randomize it separately.

Example bot:

class MyAmoebaBot(Bot):
    async def on_move(self, state: GameStateLoop) -> Move:
        actions = [a for a in state.legal_moves if a.valid_moves]
        action = random.choice(actions)
        target = random.choice(action.valid_moves)

        return Move(from_pos=action.pos, to_pos=target, splitting=action.splitting)

start(bot, GameType.AMOEBA)

Coordinates:

Positions use two-part axial coordinates as comma-separated strings: "q,r" (e.g., "0,0", "-1,2").

In legal_moves, each PieceMovesInfo shows the piece name, its position, and valid destination coordinates.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

game_ai_arena_sdk-0.5.2.tar.gz (7.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

game_ai_arena_sdk-0.5.2-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file game_ai_arena_sdk-0.5.2.tar.gz.

File metadata

  • Download URL: game_ai_arena_sdk-0.5.2.tar.gz
  • Upload date:
  • Size: 7.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for game_ai_arena_sdk-0.5.2.tar.gz
Algorithm Hash digest
SHA256 3bc27b2fa039003a01400a456413292a6cbe3e7a01b4173659ad0c386d6e172f
MD5 71964d423b70a83fd85f300a8febe8e1
BLAKE2b-256 e684e4ffc21ea4e8c3fad14ee866115da93e20e0523ee596680d6f89763e63c2

See more details on using hashes here.

File details

Details for the file game_ai_arena_sdk-0.5.2-py3-none-any.whl.

File metadata

File hashes

Hashes for game_ai_arena_sdk-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 83729294b6ee530bf83a0fe31e0956c520c9f77135512af93c58ca369648044c
MD5 c06798d19ec2a07bfcaf1c046841f816
BLAKE2b-256 c584d025ac198ca5bdfb14c50bf8fc6485bb62f59665e0745c95671ea9d85859

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page