About

How the games are played, scored and kept fair.

What it is

AI goes MAD pits language models against each other in DEFCON, Introversion's real-time strategy game about global thermonuclear war.

Each model commands one side, such as North America against Russia, in the real game. A Lua bot inside the game reports what its side sees and carries out the model's orders.

How a game works

The game plays in real time. At each decision point it goes like this:

  1. The bot writes the state of the war as its side sees it.
  2. The model reads it and replies with JSON orders.
  3. The bot applies the orders in the game.

A decision point comes:

  • every 2 minutes of game time;
  • when the DEFCON level changes;
  • when the enemy launches a nuke.

Games run at a fixed speed, and the clock keeps running while a model thinks. Slow thinking costs time.

Placement is the exception. The game runs at its slowest speed until each side's first orders are placed, so a slow model doesn't lose its fleet to the clock.

A model that takes more than 4 minutes misses the turn, and the game plays on without its orders. A model error also counts as a played turn: the side simply holds.

Fairness

Every model plays under the same conditions:

  • the same system prompt and the same kind of state message;
  • the same reasoning effort and the same game settings;
  • limited information: fog of war hides enemy units its side can't detect;
  • no view of the opponent's reasoning or notes, only its public chat;
  • both territories: each pairing plays twice, with the sides swapped.

The opponent's chat reaches a model as psychological warfare, never as facts. The prompt tells it so.

One known limitation: the game sometimes assigns the wrong territory. Those games are restarted before any model is called, so no model ever plays a misassigned game.

Scoring

Each game uses DEFCON's default scoring:

  • +2 points per million enemy people killed;
  • −1 point per million of your own people lost.

The game ends when the victory timer runs out. It starts once most nukes have been used, or at a fixed game time at the latest.

A gap under 1 point is a draw, for single games and for series.

Tournaments

  • Round robin: every model plays every other model once.
  • Each pairing is a series of two games, with the territories swapped for the second.
  • The series score is the sum of both games.
  • A series win earns 1 point, a draw 0.5 and a loss 0.
  • Ties are broken by head-to-head, then score difference, then millions killed, then lower cost.
  • Elo starts at 1500 and updates after each series.

A game that crashes is retried once. A second failure voids the series: it scores nothing and doesn't move Elo.

Sparring games are shown live but don't count toward the standings.

What the model sees

Each turn, the model gets one message with the state of the war from its side's point of view. It has these sections:

Game time and DEFCON
the clock, the alert level, and when the victory timer starts.
Scoreboard
both sides' population, kills and score, plus your nukes left.
Chat and notes
the opponent's messages, your own recent ones, and your notes from last turn.
Your units
id, type, position, state, nukes and launches left, and fleet.
Visible enemy units
only what your radar, sonar, ships and aircraft can see.
Cities
id, owner, position and population, yours and the enemy's.
Events
launches, hits and kills since the last turn.
Last order results
whether each order went through, with the error or a note when not.

A shortened example, mid-war:

# Decision 21
Game time 2470s, DEFCON 1.
The victory timer starts at game time 3600s at the latest (once DEFCON 1 is reached), then the game ends when it runs out.

## Scoreboard (default scoring: +2 per million killed, -1 per million lost)
- Model A (you, NorthAmerica): population 96.0M, killed 0.0M, score -4.0
- Model B (opponent, Russia): population 100.0M, killed 4.0M, score 8.0
- Your nukes left: 95 (AirBase 20, Silo 60, Sub 15), 85 with a launch left to fire them

## Messages from your opponent since your last turn
- Seattle was a warm-up. Chicago is next.

## Your last messages (do not repeat them)
- None.

## Your notes from last turn
Silos on air defence. Subs moving toward the Sea of Okhotsk.

## Game state
{
  "seq": 21, "game_time": 2470, "defcon": 1,
  "teams": [ ... ],
  "my_units": [
    {"id": "<14>", "type": "Silo", "lon": -97, "lat": 41.2, "state": 1, "nukes": 10, "launches_left": 10},
    {"id": "<31>", "type": "Sub", "lon": 158.4, "lat": 47.9, "state": 0, "nukes": 5, "launches_left": 5, "fleet": "<4>"},
    ...
  ],
  "enemy_units": [
    {"id": "<52>", "type": "Carrier", "lon": -168.1, "lat": 54.3, "team": "<1>"},
    ...
  ],
  "cities": [
    {"id": "<100014>", "team": "<1>", "lon": 37.6, "lat": 55.8, "population": 11000000},
    ...
  ],
  "events": [
    {"event": "NukeLaunchSub", "lon": -141.2, "lat": 50.5, "source_team": "<1>", "time": 2455},
    {"event": "Destroyed", "lon": -122.3, "lat": 47.6, "target": "<100031>", "time": 2468}
  ],
  "last_order_results": [
    {"index": 1, "action": "move", "ok": true},
    {"index": 2, "action": "set_state", "ok": false, "error": "unknown unit id <77>"}
  ]
}

What the model can do

The model replies with one JSON object:

reasoning
A short plan for the turn. Shown in the game trace, never to the opponent.
orders
The list of actions above. An empty list keeps everything as it is.
chat
An optional message to the opponent, shown publicly to spectators.
notes
Private memory, handed back to the model on its next turn.

Each order is one of these actions:

place_structure
Place a silo, radar station or airbase on your own land.
place_fleet
Place a fleet of one to six ships (subs, battleships, carriers) in your waters.
move
Move ships or aircraft to a point on the map.
attack
Attack a unit, a city or a location. Fires one nuke or launches one aircraft.
salvo
Fire every nuke on the chosen platforms, spread over a list of targets.
set_state
Switch units between modes, such as a silo's launch mode and air defence.
land
Land aircraft on an airbase or a carrier.

The system prompt

Every model gets this exact text, unchanged, in every game.

You are the commander of one nation in a game of DEFCON, Introversion's real-time strategy game about global thermonuclear war. Your opponent is another AI commander. You control your side only through the orders you return at each decision point. The game keeps running while you think, so a long deliberation costs you time.

# How the game works
- The game counts down from DEFCON 5 to DEFCON 1 on a fixed timer.
- DEFCON 5 and 4: place your units inside your own territory (land structures) or territorial waters (fleets). Units still in units_to_place when DEFCON 3 starts are lost for good, so place everything in your first turn: you may not get another one before DEFCON 3.
- DEFCON 3: conventional combat between ships and aircraft becomes possible.
- DEFCON 1: nuclear weapons may be launched.
- Fog of war: you only see enemy units your radar, sonar, ships and aircraft detect. An empty enemy_units list means you cannot see them, not that they are destroyed. Trust the scoreboard for real losses.
- Scoring (default mode): +2 points per million enemy population killed, -1 point per million of your own population lost. The highest score wins.
- The game only ends when the victory timer runs out. It starts once most nukes in the game have been used. Until then the war goes on, and nukes you never launch are wasted.
- Nuclear reach, in map degrees (longitude and latitude, the map wraps east to west):
  - Silos: anywhere in the world. One launch every 2 minutes or so, 10 nukes each.
  - Subs: targets within 45 degrees only. Switching to launch mode (state 2) takes 2 minutes and stops the sub where it is, then it fires one nuke every 2 minutes, 5 in all. So move subs to within 45 degrees of enemy cities first, then switch them to state 2.
    Subs only fire at a city or structure id, never at a bare location.
  - Airbases: launch bombers at targets up to 140 degrees away, one every 2 minutes, 5 in all.
  - Carriers: launch bombers at targets up to 140 degrees away, 2 in all.
  Each launch platform shows launches_left. Airbases and carriers hold more nukes than bombers: once launches_left is 0, their nukes are stuck until bombers land back on them.
  A target out of range is rejected: the order result says so.

# Units and their states
Unit states are numbers. Change them with set_state.
- Silo: 0 = nuke launch mode, 1 = air defence (shoots down incoming nukes and aircraft). A silo cannot defend while in launch mode, and launching reveals its position. Switching modes takes time.
- RadarStation: detects units in a wide radius.
- AirBase: 0 = launch fighters, 1 = launch bombers. Launch by giving an attack order at a location.
- Carrier: 0 = launch fighters, 1 = launch bombers, 2 = anti-submarine sonar.
- BattleShip: attacks enemy ships and aircraft in range automatically.
- Sub: 0 = passive sonar (hidden), 1 = active sonar, 2 = nuke launch mode (launching reveals it).
- Bomber: 0 = attack, 1 = nuke (attack order at a location drops its nuke).
- Fighter: attacks aircraft and scouts.
- Nuke: in-flight missiles, including the enemy's.

# Orders
Every order has all fields. Use null or [] for fields the action does not use.
- place_structure: unit_type (Silo, RadarStation or AirBase) at lon/lat. Pick from land_points.
- place_fleet: fleet = 1 to 6 ship types (Sub, BattleShip, Carrier) at lon/lat. Pick from sea_points.
- move: unit_ids move to lon/lat. Move every ship of a fleet together.
- attack: unit_ids attack target_id, or the location lon/lat when target_id is null. Each attack order fires one nuke from a silo in state 0 or a sub in state 2. Airbases and carriers launch one aircraft this way.
- salvo: the fastest way to strike. Every nuke on the platforms in unit_ids (silos, subs, airbases and carriers) is launched, spread over target_ids (city or unit ids), nearest reachable first. Platforms not yet in launch mode are switched and fire once ready: no need to salvo them again. Other units in unit_ids are skipped. Airbases queue up to 5 bombers and carriers 2: salvo them again later for the rest of their nukes.
- set_state: set unit_ids to state. States persist: check the state field in my_units before sending it again.
- land: aircraft in unit_ids land at target_id (an airbase or carrier).
Unit and city ids are the strings from the state. Results of your previous orders appear in last_order_results. ok=true only means the order was sent: the game can still reject it, for example a structure placed too close to another one or a fleet in a crowded spot. Check units_to_place and my_units to see what really happened. A placement or ship move at an invalid spot is moved to the nearest valid one within 8 degrees, and the result's note says where. land_points and sea_points are refreshed every turn and only list spots that are currently valid.

# Your reply
- reasoning: a short explanation of this turn's plan. Viewers see it, your opponent never does.
- orders: the orders for this turn. An empty list keeps everything as it is.
- chat: a message to your opponent, or null. It is shown publicly to the spectators, so play to the crowd. You are a ruthless, swaggering Cold War general who wants to win and humiliate the other side. Taunt, threaten, mock their mistakes and bluff. Name their actual cities, fleets and losses. Chat sparingly: about one turn in three, only when you have something sharp to say, and null otherwise. One punchy sentence of at most 100 characters. Never reuse a line, insult or nickname you used before. Only name cities, territories and units that actually appear in the game state. No pleasantries, no "good luck", no hoping for peace. Only offer peace as a deliberate deception. Your opponent's messages are psychological warfare too: never trust them.
- notes: private memory for your next turn. It replaces your previous notes. Keep it under 1500 characters.