Katkat

Design a Robot Operations CLI

ShopifySoftware Engineer · Technical Screen

Last updated

Implement a modular robot controller for a 2D warehouse grid that processes command sequences, enforces boundary and obstacle rules, and returns a detailed execution report.

Problem Statement

You are building the core engine for a command-line interface (CLI) that controls automated guided vehicles (AGVs) in a warehouse fulfillment center.

The warehouse floor is represented as a 2D grid of size width x height, with the bottom-left corner at (0, 0) and the top-right corner at (width - 1, height - 1). The robot starts at a given coordinate (x, y) facing one of four cardinal directions: 'N', 'E', 'S', or 'W'.

Implement the WarehouseRobot class to execute a string of batch commands. The supported commands are:

  • 'L': Rotate 90 degrees counter-clockwise (e.g., 'N' -> 'W').
  • 'R': Rotate 90 degrees clockwise (e.g., 'N' -> 'E').
  • 'M': Move forward 1 grid unit in the current direction.

Movement Rules and Constraints

  1. Obstacles & Boundaries: A move cannot cause the robot to move outside grid bounds or step onto any coordinate present in obstacles.
  2. Early Termination on Block: If a forward move 'M' would hit an obstacle or exit the grid, the robot does not move, immediately halts execution of any remaining commands, and reports a status of "BLOCKED".
  3. Invalid Commands: If an unrecognized character appears in the command string, execution halts immediately with status "INVALID_COMMAND".
  4. Success: If all commands execute without obstruction or error, the status is "SUCCESS".

Class Interface

class WarehouseRobot:
    def __init__(self, width: int, height: int, obstacles: list[tuple[int, int]]):
        """Initialize the grid dimensions and obstacles."""
        pass

    def execute(self, start_pos: tuple[int, int, str], commands: str) -> dict:
        """
        Executes command string from start_pos.
        start_pos: (x, y, orientation)
        commands: e.g., "MRMLM"

        Returns a dict with:
        {
            "final_position": tuple[int, int, str],
            "status": "SUCCESS" | "BLOCKED" | "INVALID_COMMAND",
            "steps_completed": int,
            "message": str
        }
        """
        pass

Examples

Example 1: Clean Path

robot = WarehouseRobot(width=5, height=5, obstacles=[(2, 2)])
report = robot.execute((0, 0, "N"), "MMRM")
# Final position: (1, 2, 'E')
# Report:
# {
#     "final_position": (1, 2, "E"),
#     "status": "SUCCESS",
#     "steps_completed": 4,
#     "message": "All commands completed successfully."
# }

Example 2: Blocked by Obstacle

robot = WarehouseRobot(width=5, height=5, obstacles=[(1, 2)])
report = robot.execute((1, 1, "N"), "MM")
# Step 1: 'M' moves to (1, 2), which is an obstacle. It is blocked.
# Report:
# {
#     "final_position": (1, 1, "N"),
#     "status": "BLOCKED",
#     "steps_completed": 0,
#     "message": "Move blocked by obstacle at (1, 2)."
# }

Edge Cases

  • Starting position itself is out of bounds or on an obstacle (should return an immediate error).
  • Empty command string "" (should return "SUCCESS" with 0 steps completed).
  • Boundary collisions at x = 0, y = 0, x = width - 1, or y = height - 1.

Hints

Hint 1

Represent cardinal directions in clockwise order `['N', 'E', 'S', 'W']` so turn operations can use modular arithmetic `(idx ± 1) % 4`.

Hint 2

Store obstacles in a `set` rather than a `list` to ensure `O(1)` collision lookups on each movement step.

Hint 3

Decouple state transition calculation from state application so you can validate grid bounds and obstacles before mutating position.

Follow-up questions

  • How would you refactor your class to support interactive, streaming CLI input line-by-line rather than a single batch string?
  • How would you design the system to handle multiple robots navigating the same warehouse floor concurrently without collisions?
  • How would you implement an `UNDO` command that rolls back the robot's position and orientation to the previous state?