Build a Snake Game in Angular

hard
By FrontendAtlas Editorial · Updated Oct 5, 2026
hard level
Angular component state for grid game data Template rendering for grid board cells, the snake body, and food Keyboard event handling with reverse-direction guards Timer/game loop cleanup and change detection considerations Predictable snake body updates and collision detection fakeAsync/tick tests for timer-driven movement
Build a Snake game in Angular on a fixed grid board with starter code, tests, edge cases, and interview follow-ups. Move the snake on a timer, handle keyboard direction changes, spawn food, grow score and snake body, and end on wall or body collisions while explaining game-loop and component-state decisions.
Angular component state for grid game dataTemplate rendering for grid board cells, the snake body, and foodKeyboard event handling with reverse-direction guardsTimer/game loop cleanup and change detection considerationsPredictable snake body updates and collision detectionfakeAsync/tick tests for timer-driven movement

Requirements

  • Render a 14x14 grid board with snake body segments and food.
  • Move one cell per game loop tick using keyboard controls.
  • Support Arrow key movement and WASD controls without changing the base grid board rules.
  • Buffer at most one valid perpendicular turn per tick. Validate it against the committed movement direction; same/opposite inputs do not consume the buffer.
  • Grow the snake body and increment the score when the next head cell reaches food.
  • Respawn food only in a free cell; when no free cell remains, store no food and end with a distinct win state.
  • End the game on wall collision when the next head position leaves the grid board.
  • End the game on self collision when the next head position is inside the snake body.
  • Stop movement after game over so additional timer ticks cannot keep changing component state.
  • Provide a restart/reset action that restores the initial snake, score, direction, food, and paused status.
  • Clean up timers and keyboard-driven state when the Angular component is destroyed.
  • Keep template rendering predictable by tracking each @for row and column with its stable numeric coordinate.

Expected behavior

Example gameplay timeline:

  • t=0: the head starts at zero-based coordinate (x=6, y=7), moving RIGHT; food is at (x=8, y=7).
  • t=140ms: the head moves to (x=7, y=7) and the tail drops.
  • t=280ms: the head reaches food at (x=8, y=7), score increases by 1, and the snake grows.
  • The first valid perpendicular key between ticks is buffered; later keys are ignored until movement commits it.
  • RIGHT → UP → LEFT during one tick commits UP, because LEFT is not allowed to replace the occupied buffer.
  • Eating the final free cell sets food to null, stops the timer, and shows a win instead of spawning food on the snake.

Implementation notes

  • Keep the snake body as an ordered list of grid cells with the head at index 0.
  • Keep a nullable one-turn buffer separate from the committed direction; clear it immediately when the next tick commits.
  • Compute the next head on each game loop tick before deciding whether to move, grow, or end the game.
  • Use Angular component state for score, food, gameOver, and running status, then render the grid through the template.
  • Use setInterval or an equivalent timer loop and clear it on pause, reset, wall collision, self collision, and ngOnDestroy.
  • Use deterministic fakeAsync/tick tests for timer behavior instead of relying on real elapsed time.

Solution idea

Interview answer: the base prompt is a grid-state problem plus a timer-driven game loop. Keep the snake body as an ordered list of cells, track the current direction, compute the next head on each tick, then decide whether to move, grow, or end the game. Keyboard input should update direction while accepting at most one valid perpendicular turn per tick. Food placement, restart behavior, speed changes, pause/resume, mobile controls, and deterministic tests are follow-ups. In Angular, keep the board, snake body, food, score, running state, and gameOver flag in component state, render cells through the template, and clean up the timer when the component stops or is destroyed. Treat a full board as a win: food becomes null, the loop stops, and no food cell renders.