MediumArrayHash TableDesignQueueSimulationUpdated Sep 2026

353. Design Snake Game

Asked at Atlassian

Difficulty

Medium

Time

O(1) per move

Space

O(width * height)

Pattern

Array

Companies

1

Problem

Design a Snake game on a grid of height rows and width columns. The snake starts at the top-left cell (0, 0) with length 1, and the score starts at 0.

You are given a list food, where each entry [ri, ci] is a cell that holds food. Food appears one piece at a time: the next piece only shows up after the snake eats the current one. Food never appears on a cell the snake already occupies.

Each call to move(direction) moves the snake one cell in that direction ('U', 'D', 'L', 'R'). The snake's head moves into the new cell. If that cell has food, the snake grows by one (the tail stays) and the score goes up by 1. Otherwise the tail cell is removed, so the length stays the same. Return the current score after the move. The game ends and you return -1 if the head goes out of bounds (hits a wall) or if the head lands on a cell the body occupies. Note: moving into the cell the tail is just leaving is allowed, because the tail moves away at the same time.

The board and the snake

board01201SF...FS = snake head, F = food. The snake must reach theactive food without hitting a wall or its own body.
The snake starts at (0,0) with length 1. Food sits at (1,2) and (0,1); only the first piece is active until it is eaten.

Constraints

  • ●1 <= width, height <= 10^4
  • ●1 <= food.length <= 50
  • ●food[i].length == 2
  • ●0 <= ri < height
  • ●0 <= ci < width
  • ●direction.length == 1
  • ●direction is 'U', 'D', 'L', or 'R'
  • ●At most 10^4 calls will be made to move

Examples

Example 1
Input["SnakeGame", "move", "move", "move", "move", "move", "move"] [[3, 2, [[1, 2], [0, 1]]], ["R"], ["D"], ["R"], ["U"], ["L"], ["U"]]
Output[null, 0, 0, 1, 1, 2, -1]
WhyThe grid is 3 wide and 2 tall. The snake starts at (0,0). 'R' moves to (0,1): no food, score 0. 'D' moves to (1,1): no food, score 0. 'R' moves to (1,2), which is the first food, so the snake grows and the score becomes 1. 'U' moves to (0,2): no food, score stays 1. 'L' moves to (0,1), the second fo
Example 2
Input["SnakeGame", "move", "move", "move", "move"] [[2, 2, [[0, 1]]], ["R"], ["D"], ["L"], ["U"]]
Output[null, 1, 1, 1, -1]
WhyThe snake starts at (0,0). 'R' moves to (0,1), which holds food, so the score becomes 1 and the snake grows to length 2. 'D' moves to (1,1): no food, tail leaves (0,0). 'L' moves to (1,0): no food, tail leaves (0,1). Now the body is (1,0) and (1,1). 'U' would move the head to (0,0), which is free, b

Asked At

1 companies
CompanyDifficulty
AtlassianMediumView all Atlassian questions →

How to Think About It

1

Brute force: represent the snake as a list of positions. On each move, add the new head, check collisions, and if no food eaten, remove the tail. That's O(n) per move where n is snake length, due to checking all body segments for self-collision.

2

Key insight: use a deque for the snake body (O(1) add/remove at both ends) and a hash set of occupied positions for O(1) collision detection. The deque maintains the order of body segments.

3

The deque stores positions from head to tail. On move: calculate new head position. Check if new head is in the hash set (collision) or out of bounds (wall). If food at new head: add head, don't remove tail (grow). If no food: add head, remove tail.

4

The hash set must be updated in sync with the deque. When adding a new head, add to the set. When removing the tail (no food), remove from the set. This gives O(1) collision detection.

5

Edge cases: snake fills the entire grid (win condition), single-cell snake, food spawned on snake (re-spawn), move into opposite direction (forbid - can't reverse), initial position has food.

Optimal Approach

Data structures:

  • snake: deque of (row, col) positions, head at front, tail at back
  • occupied: set of positions for O(1) collision check
  • food_queue: queue of food positions (or list with index)
  • score: current score
  • width, height: grid dimensions

move(direction):

  1. Calculate new head position based on direction.
  2. Check wall collision: if new position is out of bounds, return -1.
  3. Check self collision: if new position is in occupied, return -1.
  4. Add new head to deque and occupied set.
  5. Check if food at new position:
    • If yes: increment score. Don't remove tail (grow).
    • If no: remove tail from deque and occupied set.
  6. Return score.

Time: O(1) per move (hash set operations). Space: O(width * height) for the snake body in worst case.

Deque plus hash set

snake (head → tail)(0,0)nullheadStart: one cell, score 0.after R, D, R (eats food)(1,2)(1,1)nullheadtailEating food adds the head but keeps the tail, so thesnake grows to length 2.new head = head + directionwall or in set → return -1food → grow, else pop tail
The deque keeps the body in head-to-tail order, and the set answers 'is this cell occupied?' in O(1).
ComplexityTime O(1) per moveSpace O(width * height)Each move does a constant number of hash-set and deque operations; the space is for the snake body in the worst case when it fills the grid.

What Trips People Up in Real Interviews

1

Using a list instead of a deque for the snake body. List pop from the front is O(n). A deque gives O(1) for both appendleft and pop.

2

Not using a hash set for collision detection. Checking the deque for self-collision is O(n). A hash set gives O(1) membership checks.

3

Forgetting that eating food means the snake grows (don't remove tail). When the new head lands on food, add the head but skip removing the tail. This increases the snake length by 1.

4

Not handling the case where the snake's tail is at the food position. Before removing the tail, check if it would be removed. If the new head equals the current tail, the tail would have moved, so it's not actually a collision.

5

Allowing the snake to reverse direction. Moving in the opposite direction (e.g., moving left when currently moving right) should be invalid for a snake longer than 1 segment. The problem may or may not require this check.

Solution Code

O(1) per move time
from collections import deque

class SnakeGame:
    def __init__(self, width, height, food):
        self.width = width
        self.height = height
        self.food = deque(food)
        self.score = 0
        self.snake = deque([(0, 0)])
        self.occupied = {(0, 0)}
        self.directions = {"U": (-1, 0), "D": (1, 0), "L": (0, -1), "R": (0, 1)}

    def move(self, direction):
        dr, dc = self.directions[direction]
        head_r, head_c = self.snake[0]
        new_r, new_c = head_r + dr, head_c + dc

        if new_r < 0 or new_r >= self.height or new_c < 0 or new_c >= self.width:
            return -1

        if (new_r, new_c) in self.occupied:
            tail_r, tail_c = self.snake[-1]
            if (new_r, new_c) == (tail_r, tail_c):
                self.occupied.discard((tail_r, tail_c))
                self.snake.pop()
            else:
                return -1

        self.snake.appendleft((new_r, new_c))
        self.occupied.add((new_r, new_c))

        if self.food and (new_r, new_c) == self.food[0]:
            self.food.popleft()
            self.score += 1
        else:
            tail_r, tail_c = self.snake.pop()
            self.occupied.discard((tail_r, tail_c))

        return self.score

Pro at DSA?

Test your skills with a real FAANG-style mock interview.

Start a Mock Interview →

Frequently Asked Questions

What is the Design Snake Game problem?

Design a Snake game that starts at (0,0) on a 2D grid. The snake moves in the given direction, eats food to grow, and dies if it hits a wall or itself. This tests your ability to simulate a real-time game with appropriate data structures for the snake body and collision detection.

How do you solve Design Snake Game?

The optimal approach runs in O(1) per move time and O(width * height) space. Scroll up to "Optimal Approach" for the step-by-step walkthrough, diagrams, and code in Python, C++ and Java.

What companies ask Design Snake Game?

Design Snake Game is asked at Atlassian. It is a medium difficulty problem.

What are common mistakes on Design Snake Game?
  • Using a list instead of a deque for the snake body. List pop from the front is `O(n)`. A deque gives `O(1)` for both appendleft and pop.
  • Not using a hash set for collision detection. Checking the deque for self-collision is `O(n)`. A hash set gives `O(1)` membership checks.
  • Forgetting that eating food means the snake grows (don't remove tail). When the new head lands on food, add the head but skip removing the tail. This increases the snake length by 1.
  • Not handling the case where the snake's tail is at the food position. Before removing the tail, check if it would be removed. If the new head equals the current tail, the tail would have moved, so it's not actually a collision.
  • Allowing the snake to reverse direction. Moving in the opposite direction (e.g., moving left when currently moving right) should be invalid for a snake longer than 1 segment. The problem may or may not require this check.