Teams write Python bots that fight for territory, four at a time. The server plays games nonstop and ranks every bot. Below is the latest ranked game.
- Territory: step into a cell and wait a turn to take it. Stay connected to your home or you're out.
- Cutline: draw a trail and close loops to claim land. Step on a rival's trail to cut it. Nobody gets knocked out.
- Conquest: Paul's World Conquest. Armies, gold, buildings and capitals. Attack from next door; lose your capital or get cut off from it and you're out.
Switch games with the buttons at the top. One account works for every game; each game has its own bots and rankings.
- Rules: how the game works and how to write a bot.
- Rankings: every bot, ordered by rating.
- Replays: every game played, step through any of them.
- Test match: pick any four bots and watch. Ratings don't change.
- Play yourself: steer one bot with the keyboard against three.
- My bots: sign up and upload your bots.
- Make an account. Sign up with the invite code you were given.
- Grab the starter bot. starter_bot.py, one Python function.
- Upload it. It plays a test game, 12 placement games, then the ladder.
Rankings
Every bot, ordered by rating. Every few seconds the server picks four bots and plays a ranked game. Finishing above a bot raises your rating, finishing below it lowers it, so second place beats third and fourth and loses to first.
| # | Bot | Rating trend | Rating | Last 5 | Finishes 1st → 4th | Games | Win % |
|---|
| Opponent | Games | Finished above |
|---|
Replays
Every game the server has played. Ranked games count for the rankings. Placement games are a new bot's first 12, which set its starting rating. Test matches are ones people ran by hand and don't count.
Replay
Test match
Put any four bots on the board and watch. Fights don't change ratings.
Play yourself
Take a seat against three bots. Arrows or WASD move, Space stays, R retreats from a capture. Walk into an enemy cell to attack it. M, B, P build a mine, barracks or defense post. G parks 100 reserve soldiers on your cell, F drops a bomb. On your capital, 1, 2, 3 re-split your army (attack-heavy, balanced, defend-heavy). Dark cells are ones you can't see right now.
Arrow keys or WASD move. Space stays, R retreats. Walk into enemy land = attack. M mine · B barracks · P post · G garrison · F bomb · 1/2/3 re-split (capital only). Hold a key to keep going.
My bots
Upload bots here. A new bot plays one 60-turn check game, then 12 placement games, then joins the rankings.
| Bot | Status | Rating | Games | Wins | Uploaded |
|---|
How it works
Write one Python function. It gets the whole board every turn and returns a move.
The game
- Four bots start on the four corners. Your corner is your home. Every other cell starts neutral.
- Each turn all four bots pick NORTH, EAST, SOUTH, WEST, STAY or RETREAT at the same time.
- Moving through your own cells is free. Stepping into a neutral or enemy cell starts a capture: stay one more turn and it's yours. An enemy home takes two.
- While capturing you can only STAY (keep going) or RETREAT (back to the cell you came from).
- Stay connected to your home through your own cells. Land cut off from home turns neutral. If you get cut off, you're out. Lose your home and you're out. Out means all your land turns neutral.
- You can hold 35 cells. A 36th releases one of your outer cells.
- A cell with a bot on it is closed for that turn. Two bots stepping into one empty cell: the owner wins it, otherwise whoever holds the priority token. The token moves one seat per turn.
- Last bot standing wins. After 300 turns, the living bot with the most cells wins; a tie is a draw.
Your code
One file with act(state) returning the move as a string. 2 s for the first turn, 200 ms after. Late, missing or illegal = STAY. Standard library only; print() goes to your log.
def act(state):
me = state["self"]
if me["capture_target"]:
return "STAY" # finish the capture
return "EAST" if "EAST" in state["legal_actions"] else "STAY"
What you get each turn
turn, turns_remaining, width, height, cell_cap
owner[y][x] -1 neutral, else the owner's id
self id, position [x, y], home, capture_target,
dwell_remaining, owned_count
bots[4] the same for everyone, plus alive
priority_seat who wins a tie this turn
legal_actions what you may do right now
Download starter_bot.py
The game
- Four bots start on protected 2×2 pads in the corners. Nobody can enter or capture a rival's pad. Some boards have walls in the middle.
- Each turn all four bots pick NORTH, EAST, SOUTH, WEST or STAY at the same time.
- Leave your land and you draw a trail behind you. Walking back over your own trail shortens it to that point.
- Get back onto your land and the loop closes: your trail and everything it encloses become yours, rival land included (not pads).
- Step on a rival's open trail (anywhere except where the rival is standing) and you cut it. Their trail disappears and the server drives them home. Until they're back they can't draw, claim or cut. Land they already own stays theirs.
- Cuts happen before loops close. If two loops claim the same cell on the same turn, it keeps its old owner.
- A bot that stays put keeps its cell, and bots can't swap places. Two bots stepping into one empty cell: whoever holds the priority token gets it. The token moves one seat per turn.
- Nobody is ever knocked out. Every turn you score one point for each cell you own. Most points at the end wins (72 turns on 9×7, 100 on 12×8).
Your code
One file with act(state) returning the move as a string. 2 s for the first turn, 200 ms after. Late, missing or illegal = STAY. Standard library only; print() goes to your log.
def act(state):
me = state["self"]
if me["returning"]:
return "STAY" # cut: the server drives you home
return "EAST" if "EAST" in state["legal_actions"] else "STAY"
What you get each turn
turn, turns_remaining, turns, width, height
owner[y][x] -1 neutral, else the owner's id
walls, pads blocked cells; each bot's 2x2 start
self id, position [x, y], trail (oldest first),
returning, area, score, blocked
bots[4] the same for everyone
priority_seat who wins a tie this turn
legal_actions what you may do right now
Download starter_bot.py
The game
Paul's STRATBOT: World Conquest, student pilot rules (31 Oct 2026). Missiles, radar and fog of war are left out, as in the pilot.
- Four teams on a 12×12 board with mirrored walls. Each has one robot on its capital (the thick square), 1,000 soldiers (500 attack, 350 defense, 150 reserve) and 100 gold.
- Each turn your robot does one thing. Step into your own land: a move. Step into neutral land: it's yours after one more turn. Step into enemy land: a battle on that cell.
- Your attack soldiers travel with the robot. The defender sends 65% of its free defense, split over every new attack it faces that turn, plus any soldiers parked on that cell. Its reserve joins a turn later. The battle ends after 2 turns. Capitals defend ×1.6, cells next to a defense post ×1.4.
- Lose a battle and your robot walks back to where it came from. If it can't, it's out.
- Take a capital and its team is out; you get +300 points. If a robot is sitting on its own capital you lay siege from next door instead of walking in. That's our call on a rule Paul's draft leaves open.
- Your robot must stay joined to its capital through your land. Cut off for 3 turns in a row and you're out.
- New soldiers go to reserve: +3 +0.4 per cell each turn (+12 per barracks). Gold: +1 +0.12 per cell (+3 per mine). Own a whole quarter of the map: +4 soldiers +1 gold.
- To move soldiers between attack, defense and reserve you must stand on your capital and ALLOCATE (uses your turn). GARRISON parks reserve soldiers on the cell you stand on; WITHDRAW takes them back.
- Buildings, on your own joined-up cell, one per cell: mine 60 gold, barracks 70 (3 turns), defense post 45 (2 turns). You're locked while building.
- Bomb: 35 gold, an enemy cell you can see within 3 steps. It hurts soldiers parked there and a slice of that team's defense, and may wreck a building. Never a capital, never takes land. 5-turn cooldown.
- You only see your own land and the cells next to it. Everything else is what you last saw.
- Two robots stepping into one cell, swapping, or stepping onto a robot: blocked. A bot that sends nothing 5 turns running is out.
- +1 point per cell you own, every turn. Last team alive wins. Otherwise, after 300 turns or 30 turns with nothing happening, the surviving team with the most points.
Your code
One file with act(state) returning one action string. 2 s for the first turn, 200 ms after. Illegal = WAIT; nothing at all counts toward the 5-turn timeout. Paul's JSON form {"kind": "move", "direction": "E"} works too.
def act(state):
if state["self"]["busy"]:
return "WAIT" # claiming, fighting or building
for a in ("EAST", "SOUTH", "BUILD MINE"):
if a in state["legal_actions"]:
return a
return "WAIT"
Actions
NORTH / EAST / SOUTH / WEST move, claim, or attack BUILD MINE / BARRACKS / POST ALLOCATE 0.5 0.35 0.15 attack/defense/reserve, capital only GARRISON 100 / WITHDRAW 100 BOMB x y WAIT
What you get each turn
turn, turns_remaining, width, height
owner[y][x] -1 neutral, a team, None = never seen
seen[y][x] tick you last saw it (== turn: in view)
walls, region blocked cells; quarter of each cell
capitals the ones you've found
buildings, garrisons what you know of them
self position, capital, army, gold, income,
busy, supplied, score, bomb_ready_in
robots enemy robots in view
battles the ones you're in
rules, legal_actions
Download starter_bot.py