Overview
Snake is the proof-of-concept game for Game Grammar. It demonstrates how discrete events — movements, collisions, growth, death — can be emitted as a structured sequence that a transformer learns to predict. The implementation runs on a 10×10 grid (configurable) and generates events on everystep() call. The game never touches the model directly. Instead, events are tokenized and fed to the transformer, which learns the grammar of Snake gameplay purely from next-token prediction.
Snake tests movement physics, conditional growth, and self-collision — the core primitives needed to validate that event-driven game-agnosticism works.
Game Rules
The Snake game follows standard rules:- Movement: Snake moves one cell per tick in the current direction
- Input: Player can change direction, but cannot reverse (e.g., UP→DOWN is ignored)
- Food: Eating food increments score, grows the snake by 1, and spawns new food
- Death: Game ends when the snake hits a wall or collides with its own body
- Legal actions: Any direction except the opposite of current direction
SnakeState
The game state is represented as an immutable dataclass defined incore.py:
Action enum defines four directions:
SnakeGame Class
TheSnakeGame class implements the minimal game protocol required for event generation:
Initialization
Core Methods
reset() -> SnakeState
Initializes a new game:
- Spawns snake at center of grid
- Randomly selects starting direction
- Places food in empty cell
- Returns initial state
step(action: Action) -> (SnakeState, list[Event], bool)
Executes one game tick and returns:
- New state
- List of events emitted
doneflag (True if game ended)
legal_actions(state: SnakeState) -> list[Action]
Returns valid actions for current state (all directions except opposite):
Event Emission
On everystep() call, the game emits a sequence of events with salience levels. Events are defined in core.py:
Event Types
The Snake game emits these event types:| Event Type | Entity | Trigger | Salience | Payload |
|---|---|---|---|---|
INPUT_U/D/L/R | player | Player input | MOVEMENT | {"action": "UP"} |
MOVE | player | Successful move | MOVEMENT | {"pos": (x, y)} |
EAT | player | Head lands on food | RULE_EFFECT | {"pos": (x, y)} |
GROW | player | After eating | RULE_EFFECT | {"length": int} |
FOOD_SPAWN | food | After eating | RULE_EFFECT | {"pos": (x, y)} |
SCORE | player | After eating | RULE_EFFECT | {"score": int} |
DIE_WALL | player | Hit boundary | COLLISION | {"pos": (x, y)} |
DIE_SELF | player | Self-collision | COLLISION | {"pos": (x, y)} |
Physics Implementation
Thestep() method implements game physics in this order:
1. Direction Resolution
2. Input Event
3. Compute New Head Position
4. Wall Collision Check
5. Food Collision Check
6. Body Update
7. Self-Collision Check
8. Successful Move Event
9. Growth and Food Respawn
The order matters: the model learns that
EAT → GROW → FOOD_SPAWN is a mandatory sequence. This is conditional rule learning — events follow causal chains that the transformer predicts.Example Event Sequence
A typical gameplay sequence looks like this:TICK bundles:
- Player input
- Movement or death
- Optional rule effects (growth, scoring, spawning)
MOVEis always adjacent to previous positionEATat food position triggersGROWandFOOD_SPAWNDIE_WALLorDIE_SELFends the episode- Score increments by 1 when eating
Training Results
With 31K parameters trained on 200 episodes:| Metric | Result |
|---|---|
| Physical validity | 95% — moves are adjacent cells, positions in bounds |
| Rule validity | 100% — EAT→GROW+FOOD_SPAWN, DIE→EOS |
| Loss | 4.47 → 0.25 (random baseline: ln(74) ≈ 4.3) |
- One-cell-per-tick movement
- Eating triggers growth and food respawn
- Death ends the episode
- Positions stay within bounds
The model learned these rules from event sequences alone, without explicit rule specifications. This validates the core premise: game grammar emerges from next-token prediction.
Agents
Three agents generate training data, defined inagents.py:
RandomAgent (40%)
Randomly selects from legal actions:GreedyAgent (40%)
Minimizes Manhattan distance to food:WallFollowerAgent (20%)
Prefers moves that keep a wall adjacent:Next Steps
- Tier 2 Evaluation: Test conditional rule emergence (does the model predict GROW after EAT?)
- Tier 3 Evaluation: Detect archetype patterns in generated sequences
- Visualization: Render sampled sequences as playable replays
- Ouroboros: Let the model play against itself and train on self-generated data
