Skip to content

Who controls the randomness: the world versus the agent

In snake a new apple appears every time the snake eats. Usually it lands on a random free cell, but nothing forces the game to be fair: the apple could land where it helps the snake, as far from it as possible, or wherever this particular snake will take longest to reach. This page shows how to choose who places the apple, what each choice does to each kind of player, and which promises still hold.

It is written for readers who have met the snake players on Games: one engine, four games and the three information regimes on Seeing the future, assuming the worst, or betting on the odds. When you leave you will be able to run any snake player against a kind, a hostile or an adaptive world, read the result, and say which of the player's claims the run tests.

Two questions that are easy to mix up

Think of a card table again. How the player thinks is one question: it may have peeked at the deck (clairvoyant), play as if the dealer were cheating (worst-case), or play the odds of a fair shuffle (probabilistic). That is the agent's information regime. How the dealer actually deals is a separate question: fairly, kindly, from a stacked deck, or by watching the player and dealing whatever hurts most. That is the game's world.

The two are independent: every player can sit at every table. A worst-case player assumes the dealer may cheat; a cheating dealer is the situation it was built for. A probabilistic player assumes a fair shuffle; at a cheating table its odds are simply wrong. The word adversarial is used only for the world (a dealer that plays against you); the regime that assumes nothing is called worst-case.

Snake's worlds

--world MODE chooses who places the apple. Every mode is a fixed rule of the board and the game's seed, so --seed replays a game exactly; ties between equally good cells are broken by the seed.

World Who it is Where the next apple goes
random (default) a fair dealer a uniformly random free cell; exactly the standard game
nearest a kind world the free cell with the shortest path from the head around the body
farthest a static adversary the free cell with the longest such path; a cell the head cannot reach at all counts as farthest
adversarial an adaptive adversary for each candidate cell, a copy of the actual player plays on; the cell it takes longest to eat, or dies or stalls on, wins
MODE:p a mixture each apple follows MODE with probability p, else random (e.g. farthest:0.3)

"Path" means a shortest route through free cells with the body standing still (one breadth-first search over the board per apple).

play snake --list prints the same list. Try them:

uv run grounded-decision play snake --world adversarial --size 8x8
uv run grounded-decision play snake --agents greedy_with_tail_check --world adversarial --size 8x8
uv run grounded-decision compare snake --agents grounded,cycle,greedy_with_tail_check --size 8x8 --world random,farthest,adversarial

The panel, the JSON lines ("world" in the start event) and the --view none summary name the world; the panel shows it only when it is not random.

What holds in each world

Rows are the information regimes of the snake players; columns are the worlds. N is the number of cells.

Player's regime random nearest farthest adversarial MODE:p
worst-case (grounded, grounded_multi, planned_proven, cycle) never dies; every apple within N − 1 moves (proved) the same proof holds the same proof holds the same proof holds; the adversary pushes it toward the bound the same proof holds
probabilistic (probabilistic, probabilistic_multi) never dies (the same safety proof); its speed is a bet on uniform apples, and its rollout bounds describe this world never dies; assumption not met: its bounds do not apply never dies; assumption not met never dies; assumption not met never dies; assumption not met
clairvoyant (clairvoyant, clairvoyant_multi) a benchmark: sees the apples the seed will place refused: there is no fixed future to see refused refused refused
no regime (greedy, greedy_with_tail_check, manhattan) nothing promised; measured only nothing promised nothing promised nothing promised; breaks first nothing promised

Why each cell says what it says:

  • The worst-case proof never looks at the apple's cell. The cycle invariant keeps the body in order along a Hamiltonian cycle, and every move shortens the distance to the apple along that cycle, whatever that distance is (see the snake section of the games page). A fresh apple is at most N − 1 cycle steps away, so it is eaten within N − 1 moves wherever the world put it.
  • A probabilistic statement is about a model. "Uniform over free cells" is the model; in any other world the sampled futures come from a different distribution. compare, audit and the rollout bounds then print assumption not met instead of a guarantee. The safety proof of the probabilistic planners does not depend on the model, so "never dies" still holds.
  • Clairvoyance needs a future that does not depend on the player. In the random world the seed fixes the sequence of random draws in advance. Every other world reads the body to place the apple, so the future depends on the player's own moves, and there is nothing fixed to reveal. The command line says so and stops:
$ uv run grounded-decision play snake --agents clairvoyant --world farthest --seed 0
grounded-decision play: error: the agent clairvoyant is clairvoyant (a benchmark that sees the future), but in the farthest world the future depends on the agent's own moves, so there is no fixed future to see; use the random world

Real runs: the same players in four worlds

Six players, five seeds each, on 8 × 8 (N = 64):

uv run grounded-decision compare snake --agents grounded,cycle,planned_proven,probabilistic,greedy_with_tail_check,manhattan --size 8x8 --seeds 5 --world random,nearest,farthest,adversarial

The first and last of the four tables it prints:

Comparison: snake, solo, 5 seed(s); seats: snake (assigned by the comparison); world: random

  agent                    games  won drawn lost  cut  points    moves    score overrides  win rate (95% interval)
  probabilistic                5    5     0    0    0     5.0    617.6     64.0         0  1.00 [0.48, 1.00]
  planned_proven               5    5     0    0    0     5.0    662.6     64.0         0  1.00 [0.48, 1.00]
  grounded                     5    5     0    0    0     5.0    929.6     64.0      1143  1.00 [0.48, 1.00]
  cycle                        5    5     0    0    0     5.0   1115.2     64.0         0  1.00 [0.48, 1.00]
  manhattan                    5    0     0    5    0     0.0    129.0     19.6         0  0.00 [0.00, 0.52]
  greedy_with_tail_check       5    0     0    5    0     0.0    488.4     36.2         0  0.00 [0.00, 0.52]

Comparison: snake, solo, 5 seed(s); seats: snake (assigned by the comparison); world: adversarial

  agent                    games  won drawn lost  cut  points    moves    score overrides  win rate (95% interval)
  probabilistic                5    5     0    0    0     5.0   1103.8     64.0         0  1.00 [0.48, 1.00]
  planned_proven               5    5     0    0    0     5.0   1233.6     64.0         0  1.00 [0.48, 1.00]
  grounded                     5    5     0    0    0     5.0   1589.6     64.0      2649  1.00 [0.48, 1.00]
  cycle                        5    5     0    0    0     5.0   2016.0     64.0         0  1.00 [0.48, 1.00]
  manhattan                    5    0     0    5    0     0.0    178.0     13.0         0  0.00 [0.00, 0.52]
  greedy_with_tail_check       5    0     0    5    0     0.0    206.0      6.0         0  0.00 [0.00, 0.52]

points: win 1, draw or cut-off shares 1 among the seats, loss 0. moves: mean moves per game (all players).
Note: assumption not met: probabilistic agents model the random world, but this run uses the adversarial world, so their high-probability statements do not apply here (worst-case guarantees still do).

"moves" is the mean number of moves per game and "score" the final length (64 = the board is full). Mean moves per game across all four worlds, from the same command:

Player nearest random farthest adversarial
planned_proven 215.8 662.6 913.2 1233.6
probabilistic 229.8 617.6 880.4 1103.8
cycle 359.8 1115.2 1408.0 2016.0
grounded 618.8 929.6 1265.6 1589.6
greedy_with_tail_check (final length) 59.2 36.2 41.8 6.0
manhattan (final length) 39.8 19.6 16.8 13.0

What the numbers show:

  • Every proven player fills the board in every world. The worlds change how long it takes, never whether it works.
  • The adversary attains the bound exactly against cycle. Following the cycle, an apple at cycle distance d takes exactly d moves, and the free cells all lie ahead of the head, so the worst free cell is the one just behind the tail: N − L moves for a snake of length L. The adaptive adversary finds that cell every time, so a game takes exactly 63 + 62 + … + 1 = 64 × 63 / 2 = 2016 moves, and the first apple takes exactly N − 1 = 63. The tests check this on four board shapes.
  • The adversary slows the faster proven players by 1.7 to 1.9 times (grounded 929.6 to 1589.6 moves), still within the proved N − 1 moves per apple, which the tests check apple by apple in every world on four board shapes.
  • Heuristics that do well with fair apples break. greedy_with_tail_check never died in the random world here (it stalls instead, at length 36 on average); against the adaptive adversary it stalls at length 6. The adversary found, for each apple, a cell its tail-chasing loop never reaches.
  • The kind world helps every player, and still does not save the heuristics. nearest puts the apple next to the head: cycle needs a third of its random-world moves (359.8 against 1115.2), while greedy_with_tail_check fills the board once in five games and manhattan still dies.

The adaptive adversary, precisely

For each apple the adversarial world:

  1. takes up to 64 candidate cells: every free cell when there are at most 64 (then the choice is exact), otherwise 63 cells sampled with the seed plus the farthest cell;
  2. for each candidate, in a seeded random order, copies the board, puts the apple there, copies the actual player (its internal state and its own random numbers included, so a randomised player replays exactly the draws it would make), and lets the copy play for up to 2N + 1 moves;
  3. scores the cell by the moves needed to eat it, or as infinitely bad if the copy dies or stalls (the stall rule ends a game after 2N moves without an apple);
  4. stops starting new candidates once 20,000 moves have been simulated for this apple, and places the apple on the highest-scoring cell (ties broken by the seed).

The engine hands the world the player once per match. A human player cannot be copied, so with --you the adversarial world places apples like farthest.

What the adversarial world does not establish

It is greedy in time: it hurts the player as much as it can for the next apple only, not over the whole game, and on large boards it tries a sample of cells. So a proven player's result against it is a measurement, not a worst case over every possible sequence of apples. The worst case over every sequence is what the proof covers: N − 1 moves per apple, in any world.

Other games

The same --world flag works for every game that has something random to control; play --list shows which. A game without one says so:

$ uv run grounded-decision play tictactoe --world farthest
grounded-decision play: error: tictactoe has no world modes (nothing random to control); games with worlds: snake

Game authors: the shared rules (parsing MODE:p, refusing clairvoyance in a world that depends on the player, the assumption not met note) live in grounded_decision.examples.games.worlds; its docstring is the contract (WORLDS, DEFAULT_WORLD, INDEPENDENT_WORLDS, configure(..., world=...), and the optional bind_agents hook for a world that simulates the player).