PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

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.

  • easy
  • Shopify
  • Coding & Algorithms
  • Software Engineer

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.

Input: (['CREATE b', 'SELECT b', 'M', 'CREATE a', 'SELECT a', 'M'],)

Expected Output: ['created b', 'selected b: (0, 0) N', '(0, 1) N', 'created a', 'selected a: (0, 0) N', '(0, 0) N [BLOCKED]']

Explanation: v3 collision: b moves north to occupy (0,1). a spawns at (0,0) facing N; its target (0,1) is occupied by b, so M fails -- a stays at (0,0) N and the line is marked [BLOCKED].

Input: (['M', 'SELECT ghost', 'DELETE ghost', 'CREATE a', 'CREATE a'],)

Expected Output: ['ERROR: no rover selected', "ERROR: no such rover 'ghost'", "ERROR: no such rover 'ghost'", 'created a', "ERROR: rover 'a' already exists"]

Explanation: v2 invalid-operation contract: M with no selection errors; SELECT and DELETE of a non-existent id error; creating a duplicate id errors. No state is mutated on any error.

Input: (['CREATE a', 'SELECT a', 'DELETE a', 'M'],)

Expected Output: ['created a', 'selected a: (0, 0) N', 'deleted a', 'ERROR: no rover selected']

Explanation: Deleting the currently selected rover clears the selection, so the subsequent M reports 'no rover selected' instead of dereferencing a dangling id.

Input: (['CREATE a', 'SELECT a', 'M', 'M', 'CREATE b', 'SELECT b', 'M'],)

Expected Output: ['created a', 'selected a: (0, 0) N', '(0, 1) N', '(0, 2) N', 'created b', 'selected b: (0, 0) N', '(0, 1) N']

Explanation: Freed-cell case: a walks north off (0,1) to (0,2), so (0,1) is no longer occupied. b then moves north into the now-free (0,1) successfully -- occupancy correctly releases the old cell on each move.

Input: (['CREATE a', 'SELECT a', 'R', 'R', 'R', 'R', 'L', 'M'],)

Expected Output: ['created a', 'selected a: (0, 0) N', '(0, 0) E', '(0, 0) S', '(0, 0) W', '(0, 0) N', '(0, 0) W', '(-1, 0) W']

Explanation: Direction arithmetic: four R turns cycle N->E->S->W->N (full circle back to North). One L then faces West; M moves to (-1,0). Confirms modular turn handling in both directions.

Input: ([],)

Expected Output: []

Explanation: Edge case: an empty command stream produces no output.

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.
Last updated: Jun 26, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Grid Robot Command Simulator - Shopify (medium)
  • Compute Theme Similarity - Shopify (medium)
  • Compute Jaccard Similarity for Lists - Shopify (medium)
  • Implement URL Shortening Codec - Shopify (medium)
  • Simulate a rover fleet - Shopify (medium)