Implement a multi-rover Mars controller
Company: Shopify
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to implement stateful command parsing, entity management for multiple rovers, and collision-avoidance on an unbounded 2D grid, emphasizing deterministic simulation, input/output specification, and robust handling of invalid operations.
Constraints
- Grid is unbounded; coordinates may be negative.
- Rover IDs are unique non-empty strings.
- Commands are case-insensitive for the keyword (CREATE/M/etc.); IDs are case-sensitive.
- Collision is enforced only on M (rovers may overlap at the (0,0) spawn cell).
- Each command produces exactly one output line; blank lines are skipped.
Examples
Input: (['CREATE a', 'SELECT a', 'L', 'M', 'M'],)
Expected Output: ['created a', 'selected a: (0, 0) N', '(0, 0) W', '(-1, 0) W', '(-2, 0) W']
Explanation: v1 single rover: create+select a (starts (0,0) N). L turns it to face West (no move). Two M's walk it west to (-1,0) then (-2,0). Demonstrates turning and negative coordinates on the unbounded grid.
Input: (['CREATE a', 'SELECT a', 'M', 'R', 'M', 'CREATE b', 'SELECT b', 'M', 'SELECT a', 'M'],)
Expected Output: ['created a', 'selected a: (0, 0) N', '(0, 1) N', '(0, 1) E', '(1, 1) E', 'created b', 'selected b: (0, 0) N', '(0, 1) N', 'selected a: (1, 1) E', '(2, 1) E']
Explanation: The prompt's example interaction. a -> (0,1) N, turns R, moves to (1,1) E. b created+moved to (0,1). Re-selecting a and moving: a faces East at (1,1), target (2,1) is free (b is at (0,1)), so it moves freely to (2,1) -- the final M does NOT block because the cells don't line up.
Hints
- Model direction as an index 0=N,1=E,2=S,3=W so a right turn is (d+1)%4 and a left turn is (d-1)%4 -- no if/elif ladder, no sign bugs.
- Keep a (dx,dy) delta table per direction (N=(0,1), E=(1,0), S=(0,-1), W=(-1,0)) as the single source of truth for movement.
- Separate per-rover state {(x,y,facing)} from controller-level state (selection + an occupancy map cell->rover_id). Only the controller can see the whole grid, so collision logic lives there.
- On a successful M, free the rover's old cell in the occupancy index before claiming the new one; on a blocked M, change nothing and append [BLOCKED].
- Handle the error branches explicitly: no selection for L/R/M, unknown/duplicate ids for CREATE, missing ids for SELECT/DELETE, and clearing selection when the selected rover is deleted.