Katkat

Design a Testable 2048 Game Engine

AsanaSoftware Engineer · Technical Screen

Last updated

This problem tests object-oriented design principles, state management, and the ability to decouple business logic from external dependencies like random number generation to ensure testability.

Problem Statement

Design a core engine for the 2048 game. Your engine should maintain the state of a 4x4 grid and provide an interface to move tiles (Up, Down, Left, Right). When tiles are moved, they should slide until they hit the wall or another tile. If two tiles of the same value collide, they merge into a single tile with double the value.

Requirements

  1. Game State: Provide an immutable representation of the board.
  2. Tile Generation: The game must spawn a '2' or '4' in an empty cell after every successful move. To ensure the game is deterministic for testing, the strategy for generating new tiles must be injectable.
  3. Game Over Logic: Provide a way to determine if no further valid moves are possible.
  4. Testability: The engine must allow a test suite to inject a specific board state and specific random values to verify complex move sequences.

Proposed Interface

Define the class structure, focusing on the public API for move execution and board observation. You do not need to implement the full UI/UX logic, just the engine mechanics.

Examples

Input Board:
[[2, 2, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0]]

Action: Move Left
Output Board:
[[4, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0],
 [0, 0, 0, 0]]

Constraints

  • Use a 4x4 grid.
  • A tile can only merge once per turn.
  • Assume the board is initialized with two tiles at random positions.

Hints

Hint 1

Consider using the Strategy Pattern to decouple the tile-spawning logic from the move execution logic.

Hint 2

Represent the board as a 2D array or a flattened list, but ensure the public getter returns a copy or an immutable wrapper to prevent external tampering with internal state.

Hint 3

Model the 'Move' operation as a function that takes the current board state and returns a new board state, making it easier to verify state transitions in unit tests.

Follow-up questions

  • How would you modify this engine to support 'Undo' functionality for the last move?
  • If the game engine needed to support multiple concurrent players, what concurrency mechanisms would you introduce to prevent race conditions during updates?
  • How would you adapt your design if the board size could be changed to N x N at runtime?