Snake Game

Level: Advanced 60–90 min

Concepts: StateAlgorithmsBoundariesEdge Cases

Solutions: C# | TypeScript | Python


Implement the game logic for the classic Snake game. No UI required — focus on the rules, state transitions, and collision detection.

Requirements

The game takes place on a rectangular grid of configurable size (e.g. 10x10).

The Snake

  • The snake starts at position (0, 0) moving right, with a length of 1
  • The snake moves one cell per tick in its current direction
  • Valid directions: Up, Down, Left, Right
  • The snake cannot reverse direction (e.g. moving Right cannot change to Left)

Movement

Each tick:

  1. The snake moves one cell in its current direction
  2. If the new head position contains food, the snake grows by 1 (tail doesn’t move)
  3. If the new head position is empty, the snake moves (tail follows)
  4. If the new head position is a wall or the snake’s own body, the game is over

Food

  • One piece of food exists on the grid at a time
  • When the snake eats food, a new piece of food appears at a random empty cell
  • Food cannot spawn on the snake’s body
  • Accept an injectable random source for testability

Scoring

  • Each food eaten scores 1 point
  • The game tracks the current score

Grid

  • The grid has walls on all four edges
  • The snake wraps around OR dies at walls (choose one and document it)

Test Cases

ScenarioSetupActionResult
Initial stateNew game 5x5Snake at (0,0), length 1, moving right
Move rightSnake at (0,0)tickSnake at (1,0)
Move downSnake at (0,0), direction DowntickSnake at (0,1)
Eat foodSnake at (0,0), food at (1,0)tickSnake length 2, score 1
Grow correctlySnake [(0,0)], food at (1,0)tickSnake [(1,0),(0,0)]
Hit wallSnake at (4,0) moving right, 5x5 gridtickGame over
Hit selfSnake [(3,0),(2,0),(1,0),(0,0)], direction Down then Left then Uptick x3Game over (hits own body)
Cannot reverseMoving rightchange direction LeftDirection stays Right
Food respawnsSnake eats foodNew food at random empty cell

Bonus

  • Implement wall-wrapping as an alternative to wall-death (configurable)
  • Add speed levels — the snake moves faster as the score increases
  • Add obstacles — static blocks on the grid that kill the snake on contact
  • Track high scores across multiple games

Hint

Represent the snake as a list of coordinates (head first). Movement is: prepend the new head position, remove the tail (unless eating). This makes growth trivial — just skip the tail removal. Test the movement logic before adding food or collisions.

Reference Walkthrough

Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/snake-game. Twenty-three scenarios across initial state, basic movement, direction changes, eating food, wall collisions, self collision, game-over behavior, and winning — shared across all three languages — with a mutable Game aggregate backed by an immutable Snake (head-first body list), Position value type, Direction enum, and injectable FoodSpawner for deterministic testing. BoardBuilder and SnakeBuilder make test setup readable.

  • C# (.NET 8, xUnit, FluentAssertions) — walkthrough
  • TypeScript (Node 20, Vitest, strict types) — walkthrough
  • Python (3.11, pytest, frozen dataclass, Enum) — walkthrough

This kata ships in Agent Full-Bake (F3) mode: one commit per language with the full domain design landing together. The walkthroughs read as design rationalewhy the snake is a head-first list (movement = prepend head, optionally pop tail), why Snake.Move() returns a new instance (collision detection reads pre-move state), why FoodSpawner is a function not an interface (single-method collaborator), why direction reversal is silently ignored rather than throwing (spec says “direction stays”). The reference chooses wall-death over wall-wrapping; bonus items (wrapping, speed levels, obstacles) are deliberately out of scope. See the repo’s Gears section for when middle gear is the right call.