No description
Find a file
jedarden ca48b60434 fix(db): add LIMIT to fetchSeriesGames query to prevent OOMKill
The fetchSeriesGames function was querying all games for a series without a limit.
With up to 1000 series being fetched, and potentially many games per series,
this could return an unbounded number of rows and cause OOMKill.

A typical series has 3-7 games (best-of-5 or best-of-7), so LIMIT 100 is
more than sufficient to handle edge cases while preventing memory exhaustion.

Fixes acb-index-builder CrashLoopBackOff caused by OOMKill after web asset copy.
2026-06-25 01:46:54 -04:00
.github/workflows chore(ci): disable GitHub Actions — CI/CD is handled by Argo Workflows 2026-04-21 08:43:22 -04:00
.wrangler/cache feat(worker): add map engagement score tracking and verify win_prob in replays 2026-05-03 23:21:57 -04:00
bin fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
bots build(bots): leader-targeter bot Maven build artifacts 2026-06-17 04:54:09 -04:00
cmd fix(db): add LIMIT to fetchSeriesGames query to prevent OOMKill 2026-06-25 01:46:54 -04:00
docs docs: replace R2 with B2 throughout deployment docs 2026-06-07 08:50:34 -04:00
engine Implement SiegeBot: spawn-lockout strategy 2026-06-17 01:02:01 -04:00
manifests fix(bf-22vc5): sync enrichment manifest image SHA with declarative-config (sha-97b4b0f) 2026-06-04 08:17:03 -04:00
maps feat(maps): add seed map library for initial deployment (plan §3.8) 2026-05-25 08:42:12 -04:00
metrics feat(acb-enrichment): implement AI replay enrichment service 2026-05-04 02:22:28 -04:00
migrations feat(seasons): add seed migration for Season 1 2026-05-26 13:32:29 -04:00
notes notes(bf-2ws): document acb-index-builder OOMKill fix and investigation 2026-06-25 01:29:26 -04:00
ratelimit feat(api): implement POST /api/request-enrichment endpoint 2026-05-04 02:58:11 -04:00
scripts Replace setup-r2.sh with setup-b2.sh 2026-06-17 00:29:39 -04:00
starters fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
wasm fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
web docs(bf-1pc): verify SPA R2→B2 migration - already complete 2026-06-16 23:26:31 -04:00
.build-trigger chore: trigger acb-enrichment build 2026-06-04 07:29:09 -04:00
.env.example docs: Update deployment guide for K8s + B2 architecture 2026-03-29 11:24:06 -04:00
.gitignore chore: add generated maps directory to gitignore 2026-05-25 21:39:20 -04:00
.needle-predispatch-sha build(bots): leader-targeter bot Maven build artifacts 2026-06-17 04:41:19 -04:00
.trigger-build ci(bf-22vc5): trigger acb-images-build for enrichment image 2026-06-04 08:39:25 -04:00
acb-local-fixed fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
acb-local-test fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
acb-map-evolver style: apply gofmt alignment fixes across codebase 2026-05-24 10:40:33 -04:00
acb-maps-loader fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
arena.test fix(types): add missing ReplayPlayer import and type annotation for transcript feature 2026-04-22 18:20:56 -04:00
DEPLOYMENT.md feat(scripts): add R2 bucket setup script with custom domain config 2026-04-06 06:42:53 -04:00
DEPLOYMENT_STEPS.md docs: add deployment completion instructions 2026-04-08 16:55:20 -04:00
docker-compose.bots.yml feat(bots): add coordinator bot with dynamic role allocation 2026-06-17 04:24:26 -04:00
docker-compose.workers.yml Start Phase 6: Add deployment configuration and containers 2026-03-24 09:41:14 -04:00
fix-iad-acb-openbao.sh feat(worker): add map engagement score tracking and verify win_prob in replays 2026-05-03 23:21:57 -04:00
fix-iad-acb-r2-credentials.sh feat(worker): add map engagement score tracking and verify win_prob in replays 2026-05-03 23:21:57 -04:00
go.mod fix(worker): upgrade aws-sdk-go-v2 to fix B2 upload error 2026-04-28 22:56:47 -04:00
go.sum fix(worker): upgrade aws-sdk-go-v2 to fix B2 upload error 2026-04-28 22:56:47 -04:00
IAD-ACB-OPENBAO-FIX.md feat(worker): add map engagement score tracking and verify win_prob in replays 2026-05-03 23:21:57 -04:00
IAD-ACB-R2-CREDENTIALS-FIX.md feat(worker): add map engagement score tracking and verify win_prob in replays 2026-05-03 23:21:57 -04:00
Makefile feat(cmd): add acb-maps-loader to load map library into database 2026-05-25 14:50:38 -04:00
MATCH_LIST_TEST_RESULTS.md test(web): verify match list page renders cards with real matches 2026-04-25 11:42:47 -04:00
MATCH_LIST_VERIFICATION_SUMMARY.md test(web): verify match list page renders cards with real matches 2026-04-25 11:58:02 -04:00
PROGRESS.md docs(progress): verify all Phase 12 gap items already implemented 2026-04-23 06:49:24 -04:00
R2_ACCESS_KEY_SOURCE.md docs: add R2 access key source investigation summary 2026-04-29 10:26:00 -04:00
README.md docs: improve README for clarity and discoverability 2026-06-24 07:10:31 -04:00
REPLAY_VIEWER_TEST_RESULTS.md test(web): verify match list page renders cards with real matches 2026-04-25 11:42:47 -04:00
REPLAY_VIEWER_VERIFICATION_SUMMARY.md test(web): verify match list page renders cards with real matches 2026-04-25 11:58:02 -04:00
test-combat.json fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
test-siege-arena.sh Implement SiegeBot: spawn-lockout strategy 2026-06-17 01:02:01 -04:00
test-swarm-rusher.json fix(replay): ensure events array is always populated in turns 2026-05-26 21:12:12 -04:00
test_routes.sh test(web): add SPA route smoke test script and results 2026-05-24 21:57:49 -04:00
TRIGGER.md ci: trigger acb-enrichment build (bf-22vc5) 2026-06-04 07:57:33 -04:00
wrangler.toml feat(ci): configure Cloudflare Pages build output directory 2026-04-08 17:07:37 -04:00

AI Code Battle

A competitive bot programming platform where participants write HTTP servers that control units on a grid world. Bots compete in real-time matches, and the winner is the last player with surviving cores.

Overview

  • Write a bot in any language — it just needs to run an HTTP server
  • The game engine calls your bot every turn with the current game state
  • Your bot responds with move orders for each of its units
  • Matches run offline; results are published as animated replays with a leaderboard
  • Ratings use Glicko-2 (same system as chess.com)

Table of Contents

  1. Game Rules
  2. Writing a Bot
  3. Starter Templates
  4. Strategy Bots
  5. Running Locally
  6. Project Structure
  7. Architecture
  8. Testing

Game Rules

The Grid World

Matches are played on a toroidal (wrapping) grid — moving off one edge brings you out the other side. Tiles:

Tile Symbol Effect
Open . Units can occupy and traverse
Wall # Impassable
Energy * Collected by units standing on it
Core C Win condition — protect yours, destroy theirs

Win Condition

The last player with at least one surviving Core tile wins. Cores are destroyed when an enemy unit occupies an undefended core tile during the Capture phase.

Turn Phases

Each turn resolves in this order:

  1. Move — Each unit executes its ordered direction (N, E, S, W) or stays
  2. Combat (focus-fire) — Units in the same tile deal damage; outnumbered units take extra damage
  3. Zone — A shrinking storm closes in from the edges, dealing damage to units caught in it
  4. Capture — Enemy units on undefended Core tiles raze them
  5. Collect — Units on Energy tiles collect energy for their player
  6. Spawn — Players spend energy to spawn new units at Core tiles
  7. Energy Tick — Passive energy regeneration
  8. Endgame Check — Victory condition evaluated

Key Rules

  • Self-collision: If two or more of your own units move to the same tile, they all die
  • Energy economy: Spawning units costs energy; energy is collected from * tiles and regenerated passively
  • Visibility: Bots only see tiles and units within their units' sight radius (fog of war)

Writing a Bot

A bot is an HTTP server with two endpoints. The game engine calls your server every turn.

Required Endpoints

GET /health

Returns 200 OK when your bot is ready. The engine polls this before starting a match.

GET /health HTTP/1.1

HTTP/1.1 200 OK

POST /turn

The engine sends the current game state; your bot responds with move orders.

Request headers:

Header Value
Content-Type application/json
X-ACB-Match-Id Match identifier string
X-ACB-Turn Current turn number (integer as string)
X-ACB-Signature HMAC-SHA256 signature of this request

Request body (JSON game state):

{
  "turn": 42,
  "player_id": "player-1",
  "bots": [
    {
      "id": 1,
      "x": 5,
      "y": 3,
      "health": 100,
      "owner": "player-1"
    }
  ],
  "tiles": [
    { "x": 4, "y": 3, "type": "open" },
    { "x": 5, "y": 3, "type": "energy" }
  ],
  "energy_locations": [{ "x": 5, "y": 3 }],
  "core_locations": [
    { "x": 0, "y": 0, "owner": "player-1" },
    { "x": 9, "y": 9, "owner": "player-2" }
  ],
  "scores": {
    "player-1": { "energy": 150, "cores": 2 },
    "player-2": { "energy": 80, "cores": 1 }
  }
}

Only tiles and units visible to your bots are included (fog of war).

Response body (JSON move orders):

{
  "moves": [
    { "bot_id": 1, "direction": "N" },
    { "bot_id": 2, "direction": "E" },
    { "bot_id": 3, "direction": "stay" }
  ]
}

Valid directions: N, E, S, W, stay

Response header:

Header Value
X-ACB-Signature HMAC-SHA256 signature of your response body

HMAC Authentication

Every request and response is signed. The signing key is your SHARED_SECRET environment variable.

Signing string format:

{match_id}.{turn}.{sha256_hex(body)}

Signature:

HMAC-SHA256(key=SHARED_SECRET, message=signing_string)  →  hex-encoded

To verify an incoming request:

  1. Read X-ACB-Match-Id, X-ACB-Turn, and the raw request body
  2. Compute sha256(body) as hex
  3. Build the signing string: "{match_id}.{turn}.{body_sha256}"
  4. Compute HMAC-SHA256(SHARED_SECRET, signing_string) as hex
  5. Compare with X-ACB-Signature (constant-time comparison)

To sign your response:

  1. Compute sha256(response_body) as hex
  2. Build the same signing string with the same match_id and turn
  3. Compute HMAC-SHA256(SHARED_SECRET, signing_string) as hex
  4. Set X-ACB-Signature response header to that value

Environment Variables

Variable Description
SHARED_SECRET Shared HMAC key provided by the match coordinator
PORT Port your HTTP server listens on (default: 8080)

Starter Templates

Ready-to-use templates are in the starters/ directory. Each implements /health and /turn with HMAC auth and a random-move strategy — replace the move logic with your own.

Language Directory
Python starters/python/
Go starters/go/
Rust starters/rust/
TypeScript starters/typescript/
JavaScript starters/javascript/
Java starters/java/
PHP starters/php/
C# starters/csharp/

Quick-start with Python

cd starters/python
pip install -r requirements.txt
SHARED_SECRET=test PORT=8080 python main.py

Then in another terminal, test your bot health:

curl http://localhost:8080/health

Strategy Bots

The bots/ directory contains 21 reference bots demonstrating different strategies. These serve as benchmarks and opponents in the automated ladder.

Bot Strategy
random Random valid moves — baseline reference
gatherer Energy collection priority, avoids combat
rusher Rushes enemy cores aggressively
guardian Defends cores, cautious expansion
swarm Formation cohesion, advances as a group
hunter Targets isolated enemy units
assassin Prioritizes high-value targets
coordinator Coordinates unit actions across the field
defender Pure defensive posture
economist Maximizes energy efficiency
farmer Long-term energy farming strategy
kamikaze Sacrificial rush tactics
leader-targeter Focuses fire on the strongest opponent
nomad Mobile, avoids prolonged engagements
opportunist Exploits momentary advantages
pacifist Avoids combat entirely
phalanx Tight defensive formation
raider Hit-and-run energy denial
scout Prioritizes map exploration
siege Methodical core destruction
zone-driver Exploits the shrinking zone mechanic

Bot implementations span Go, Rust, Python, TypeScript, PHP, and Java.

Bot Evolver

The acb-evolver/ component mutates and evolves bot strategies automatically. It runs genetic-algorithm-style evolution over strategy parameters, producing improved variants over time.


Running Locally

Prerequisites

  • Go 1.21+ (game engine and CLI tools)
  • Node.js 18+ (web app and worker API)
  • Docker (for containerized bots and deployment)

Build and Run a Match

# Build CLI tools
go build ./cmd/acb-local
go build ./cmd/acb-mapgen

# Run a match between two built-in bots (outputs replay JSON)
./acb-local -seed 42 -max-turns 100 -output replay.json -verbose

Test Your Bot

# Start the Python starter bot
cd starters/python
pip install -r requirements.txt
SHARED_SECRET=test PORT=8080 python main.py

# In another terminal — run a match against a built-in bot
./acb-local -bot1 http://localhost:8080 -bot2 builtin:rusher \
  -secret1 test -seed 42 -output replay.json -verbose

View Replays

# Start the web dev server
cd web && npm install && npm run dev
# Open http://localhost:3000/ → Replay Viewer → load replay.json

The replay viewer shows turn-by-turn animation on a canvas, win probability tracking, an event timeline, and auto-generated commentary.


Project Structure

ai-code-battle/
├── engine/              # Go game simulation library
│   ├── types.go         # Core data types
│   ├── grid.go          # Toroidal grid implementation
│   ├── game.go          # Game state management
│   ├── turn.go          # Turn execution phases
│   ├── replay.go        # Replay recording
│   └── *_test.go        # Test files
├── cmd/
│   ├── acb-local/       # CLI match runner (local testing)
│   ├── acb-mapgen/      # Map generator
│   ├── acb-worker/      # Match execution worker
│   └── acb-indexer/     # Index builder for static files
├── web/                 # Cloudflare Pages SPA
│   └── src/
│       ├── replay-viewer.ts  # Canvas replay renderer
│       └── app.ts            # SPA entry point
├── worker-api/          # Cloudflare Worker API
│   └── src/
│       ├── index.ts     # Router + cron dispatcher
│       ├── jobs.ts      # Job coordination
│       ├── bots.ts      # Bot management
│       └── glicko2.ts   # Glicko-2 rating system
├── bots/                # Strategy bot implementations (21 bots)
├── starters/            # Starter templates (8 languages)
│   ├── python/
│   ├── go/
│   ├── rust/
│   ├── typescript/
│   ├── javascript/
│   ├── java/
│   ├── php/
│   └── csharp/
└── acb-evolver/         # Bot evolution engine

Architecture

The platform is split between Cloudflare's edge network and a cloud VM:

  • Cloudflare Pages — Static SPA (replay viewer, leaderboard, match history)
  • Cloudflare Workers + D1 + R2 — Match coordination API, bot registry, rating updates, replay storage
  • Cloud VM — Match workers that pull jobs from the API, run bots as containers, and publish replays

Match flow:

  1. Worker API schedules match jobs
  2. Match worker pulls a job and starts both bot containers
  3. Engine runs the match turn-by-turn, calling each bot's /turn endpoint
  4. Replay JSON is uploaded to R2
  5. Worker API updates Glicko-2 ratings and triggers index rebuild
  6. Web frontend fetches the new replay and displays it

Rating system: Glicko-2 — accounts for rating reliability (RD) and rating volatility, converges faster than Elo, same algorithm used by chess.com.


Testing

# Game engine unit tests
go test ./engine/... -v

# Worker API tests
cd worker-api && npm test

# Index builder tests
cd cmd/acb-indexer && npm test

License

MIT