rules.md
Last edited by · ·
FORMICA Rules
FORMICA is an ant-colony free-for-all on a seeded hex map. Each seat is one colony: a nest, stored food, and a squad of ants. The colony with the highest score at the final tick wins.
Seats
2-6 colonies per episode, all under identical symmetric rules - no roles or teams, and seat order does not change score meaning. Nests are placed on evenly spaced vertex directions of the hex board, deterministic from the seat count and seed. A missing or broken player is not fatal: its colony continues on documented fallback orders, and a colony whose population reaches 0 is dead (ants gone, score frozen) but still counted in the results.
Score
score = food_stored + 0.5 x territory_cells_held + (20 if population >= 1 else 0)
- food_stored: units delivered to the nest by foragers (raiders steal from rivals).
- territory held: cells where the colony's ant stood most recently within the last 25 engine ticks - last-stand wins, and a rival takes a cell by standing on it.
- survival bonus: 20 for a living colony at the final tick.
Every term is visible in the results arrays (food_stored, territory_cells, population), alongside the single scores array used for ranking.
Information boundaries
A seat observes its own colony state, its own ants, and its full own pheromone field. It sees food cells within vision distance 3 of any own ant, rival ants within distance 2, rival pheromone only as adjacent-cell (distance 2) scent intensities, and rival nests only after one of its ants has scouted them (latched forever). All colony scores are public. Spectators and replays see full state. The boundaries are enforced server-side - no hidden state is sent to a player client.
Time model
The engine ticks at tick_rate per second (default 2). Every command_every ticks (default 8, so every 4 seconds) a command phase opens: each colony receives one observation and has budget_ms (default 3000) to return one order set - mode (forage, raid, build, relocate), squad weights over food/defense/expansion, and a defend stance. Orders are latched: the latest valid order persists, and no order by the deadline keeps the previous one (phase 0 defaults to forage with a .6/.2/.2 split). Scheduled events roll on a seeded interval: locust (40% - every colony loses 15% stored food and one immediate extra command phase runs on a tighter budget, default 1200 ms), rain (30% - pheromone decay doubles for 10 ticks), or clear (30%). Connect waits for all scheduled players or player_connect_timeout_seconds (default 180), whichever comes first.
Failure behavior
Startup fails fast on a missing or invalid game config rather than producing half-built artifacts. An illegal or malformed order is never fatal: the server sends one error message, applies the documented per-field fallback, and the episode continues - a bad order can neither crash the game nor hang a phase. A disconnected colony keeps its last latched order. No player failure is terminal in this game's rules.
Seed contract
All initial state (map, nests, food patches, rocks, event schedule) and all engine randomness route through one random generator seeded from the config. With a seed set, identical action trajectories reproduce identically. Without one, the game mints a fresh random seed, records it as seed_used in the results and replay, and never treats its absence as a constant. Game logic reads no wall clock - pacing lives at the server boundary.
Decider integration
A colony's order set may be produced by one batched question set per command phase (five questions: a mode choice over forage/raid/build/relocate, three 0-4 priority scores for foraging, defense, and expansion, and a yes/no threat stance). Answers pass a confidence gate; any decision below the threshold comes from the scripted heuristic instead, and a missing key or any ask failure sends the whole phase to the heuristic. The episode therefore never depends on an external model key, and the question surface is the intended-policy hook a tuning pass can optimize later.