Quick Overview

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.

Implement a multi-rover Mars controller

Company: Shopify

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: easy

Interview Round: Technical Screen

## Problem Build a small command-line “Mars Rover Controller” program. ### Single rover (v1) A rover starts at coordinate **(0, 0)** on an infinite 2D grid and initially faces **North**. The controller must support these commands: - `L`: turn left 90° (N→W→S→E→N) - `R`: turn right 90° (N→E→S→W→N) - `M`: move forward 1 cell in the direction the rover is currently facing After **each** command is processed, the program must report the rover’s **current position and facing direction**. ### Multiple rovers (v2) Extend the controller to manage **multiple rovers** and support: - `CREATE <id>`: create a new rover with the default starting state (0,0,N) - `DELETE <id>`: delete a rover - `SELECT <id>`: make the rover with `<id>` the active rover - Movement/turn commands (`L`, `R`, `M`) apply to the **currently selected** rover Define behavior for invalid operations, e.g. selecting or deleting a non-existent rover, or issuing `L/R/M` with no rover selected. ### Collision avoidance (v3) Add collision prevention: - If the selected rover executes `M` and the **target cell is already occupied by another rover**, the move must **fail** and the rover must remain in its current position/direction. - The program must still report state after the command; you may choose an error/status message format. ## Input / Output You may design the exact CLI format (interactive REPL or reading lines from stdin), but it must be unambiguous and testable. At minimum, specify: - Accepted command syntax - What is printed after each command (position + direction, and optionally status on failures) ## Constraints / Notes - Grid is unbounded; coordinates may be negative. - Rover IDs are unique strings. - Aim for clean, testable design; include unit tests. ## Example (one possible interaction) ``` CREATE a SELECT a M R M CREATE b SELECT b M SELECT a M # fails if b is at the target cell ``` (Your exact printed output format may differ, but it must include position + facing after each command.)

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.

Build a command-line **Mars Rover Controller** as a single function `solution(commands)` that takes a list of command strings, processes them in order, and returns a list of output strings (one per command). A rover lives on an **infinite 2D grid**, starts at **(0, 0) facing North**, and coordinates may be negative. ### v1 — single rover - `L` — turn left 90 degrees (N -> W -> S -> E -> N) - `R` — turn right 90 degrees (N -> E -> S -> W -> N) - `M` — move forward one cell in the current facing direction ### v2 — multiple rovers - `CREATE <id>` — create a rover at the default state (0,0,N) - `DELETE <id>` — delete a rover - `SELECT <id>` — make `<id>` the active rover - `L`/`R`/`M` apply to the **currently selected** rover ### v3 — collision avoidance - An `M` whose target cell is **occupied by another rover** fails: the rover stays put and the line is marked `[BLOCKED]`. Collision is enforced **only on `M`** (rovers may share (0,0) at spawn). ### Output format (one line per command) ``` CREATE <id> -> "created <id>" err: "ERROR: rover '<id>' already exists" DELETE <id> -> "deleted <id>" err: "ERROR: no such rover '<id>'" SELECT <id> -> "selected <id>: (x, y) F" err: "ERROR: no such rover '<id>'" L | R -> "(x, y) F" err: "ERROR: no rover selected" M -> "(x, y) F" | "(x, y) F [BLOCKED]" | "ERROR: no rover selected" ``` where `F` is one of `N/E/S/W`. Deleting the selected rover clears the selection. Blank command strings are skipped. An unknown command yields `"ERROR: unknown command '<CMD>'"`.

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

  1. 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.
  2. 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.
  3. 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.
  4. 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].
  5. 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.

Loading coding console...