Object-Oriented Design: Snake Game
Company: Amazon
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Onsite
# Object-Oriented Design: Snake Game
Design the object-oriented model and core logic for the classic **Snake** game.
The snake lives on a 2D grid of fixed width and height. On each game tick the snake advances one cell in its current direction. The player may change the snake's direction among up, down, left, and right. When the snake's head moves onto the cell containing **food**, the snake **grows** by one segment and new food appears on an empty cell; otherwise the snake simply moves forward (the head advances and the tail recedes by one cell). The game **ends** when the head moves into a wall (off the grid) or into a cell occupied by the snake's own body. The player accumulates **score** as food is eaten.
Provide:
- the class design — classes, their key fields and responsibilities, and how they relate;
- the core algorithms — processing one tick/move, collision detection, growth, and scoring.
Assume the rendering and input layers are separate and call into your model; do not design pixels or key-handling. Favor a clean, testable, extensible model.
### Constraints & Assumptions
- The grid is a rectangle of `width` x `height` cells; cells are addressed by integer `(row, col)`.
- The game advances in discrete ticks driven by an external clock; one tick = one move.
- Exactly one food item exists at a time in the base game.
- The model is the single source of truth for game state; the view reads it and the controller feeds it direction changes and ticks.
- Single-player, single snake for the base problem; extensions are explored in Part 3.
### Clarifying Questions to Ask
- When the snake eats food and grows, does the tail stay put for that tick (so the snake gets one cell longer), and where does the new food spawn — uniformly at random over empty cells?
- Is a 180-degree reversal (e.g. moving left, then immediately right) allowed, ignored, or a loss? Standard Snake **ignores** a direct reversal.
- When moving forward without eating, may the head legally enter the cell the tail is **vacating** this same tick? (Standard Snake: yes.)
- What happens if the snake fills the entire board — is that a win, and how should we signal it?
- Do we need pause/resume, restart, or persistence of high scores, or just a single play-through?
- Is input synchronous with ticks, or can multiple direction changes arrive between two ticks (only the last should matter)?
### Part 1 — Domain model and class design
Define the classes that represent the game's state and their responsibilities and relationships. Cover how you represent a position, the snake's body, direction, the food, the board, and the top-level game/engine that ties them together and tracks status and score.
```hint Identify the nouns
Walk through the prompt and underline its nouns — position, direction, snake body, food, board, score, status. Most map directly to a class; resist the urge to bundle them all into one big `Game` object.
```
```hint Body representation
The body is a sequence with two hot ends — you push a new head and pop the tail every move. A **deque** of positions models exactly that, and a companion **hash set** of occupied cells gives O(1) self-collision checks.
```
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### Part 2 — The tick/move algorithm
Specify what happens on a single tick: computing the next head, detecting collisions (wall and self), eating-and-growing vs. moving forward, spawning new food, and updating score and game status. Be explicit about ordering and the subtle tail edge case.
```hint Order matters
There's a strict order per tick: compute the candidate head, check it against the walls, then check it against the snake's own body, and only then decide whether you're eating or just moving forward. Think about which version of the body — before or after the tail moves this tick — you should be checking self-collision against.
```
```hint Keep it O(1)
With a deque + an occupancy hash set, each tick is constant work: peek/compute head, set-lookup for collision, push head and (conditionally) pop tail, updating the set in lockstep.
```
#### Clarifying Questions for this Part
- On the eating tick, is new food guaranteed placeable — i.e. is there always at least one empty cell — and what do we do if there is not (win vs. error)?
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### Part 3 — Extensibility
Show how the design absorbs likely changes without rewrites: multiple or special food types (bonus points, shrink, speed-up), static obstacles, wrap-around walls, variable speed/levels, and a second snake (multiplayer). Point to the seams in your design that make each change local.
```hint Find the seams
Each extension maps to a seam: food *behavior* → a `Food` type/strategy with an `onEaten(game)` effect; walls vs. wrap-around → a board boundary policy; obstacles → extra occupied cells the collision check already understands; multiplayer → multiple `Snake` instances the engine ticks in turn.
```
#### What This Part Should Cover
```premium-lock What This Part Should Cover
```
### What a Strong Answer Covers
```premium-lock What a Strong Answer Covers
```
### Follow-up Questions
- How do you make the tick **deterministic and unit-testable** given that food placement is random — what do you inject?
- When the board is nearly full, uniformly random food placement by rejection sampling gets slow. How would you place food efficiently in O(empty cells) or better?
- If direction-change input arrives on a different thread than the tick, how do you keep state consistent without races?
- Extend to multiplayer: define the collision rules when two snakes' heads meet, or one head hits another's body, and how the engine resolves a tick fairly.
Quick Answer: This question evaluates a candidate's ability to translate a familiar game into a clean object-oriented model, covering class decomposition, encapsulation, and data structure choices for a real-time update loop. It tests object-oriented design and system-level thinking commonly assessed in system design interviews, requiring both conceptual class design and practical reasoning about collision detection, state transitions, and extensibility.