Mars Rover
Level: Intermediate 30–60 minConcepts: Design
Solutions: C# | TypeScript | Python
Develop an API that moves a rover around a grid on Mars.
- You are given the initial starting point(x,y) of a rover and the direction (N,S,E,W) it is facing.
- The rover receives a string of commands. Implement commands that:
- Move the rover forward(f)
- Move the rover backward(b)
- Turn the rover left(l)
- Turn the rover right(r)
- Implement wrapping from one edge or the grid to another - Planets are spheres after all.
Hint
Your constructor should look like: MarsRover(location, direction, gridSize). E.g var rover = new MarsRover([0,0],‘e’,[50,50]);
Example
The rover is on a 100x100 grid at location (0, 0) and facing SOUTH. The rover is given the commands “fflff” and should end up at (2,2).
Bonus
Implement obstacle detection before each move to a new square. If a given sequence of commands encounters an obstacle, move the rover up to the last possible point and reports the obstacle. You will need to amend your code to take in an array of obstacles.
Reference Walkthrough
Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/mars-rover. This is an F2 (light builder) kata: one primary entity (Rover), three value enums (Direction, Command, MovementStatus), one domain exception (UnknownCommandException), and two small test-folder builders — RoverBuilder (.at().facing().onGrid().withObstacleAt()) and CommandBuilder (.forward().left().build() → "FL"). Obstacle blocking is modelled as a result state on the rover (status, lastObstacle), not an exception — the kata brief asks the rover to report the obstacle, which it does as a first-class state rather than a thrown error.
Scope note — pure domain only. The reference covers position, heading, forward/backward movement, rotation, grid wrapping, and obstacle detection. A renderer (ASCII grid print), a CLI loop, alternative command formats (whitespace, lowercase, numeric repeats like 3F), and multi-rover worlds are all out of scope and listed as stretch goals in the repo README. Those responsibilities introduce collaborators (renderers, input parsers, shared world state) — which is F3 territory, not F2.
- C# (.NET 8, xUnit, FluentAssertions 6.12.0) — walkthrough
- TypeScript (Node 20, Vitest 1.6, TS 5 strict) — walkthrough
- Python (3.11, pytest) — walkthrough
This kata ships in Agent Full-Bake mode at middle gear, the F2 (light builder) tier. See the repo’s Gears section for why middle gear is the deliberate choice.
Related reading
- The Test Pyramid Was an Economic Argument
The test pyramid was not a quality law. It was a cost structure: unit tests were cheap, integration tests were expensive, so you wrote many of the first and few of the second. Agents collapsed the cost of writing tests at every level, and the cheapest test that still tells the truth is the one that pins a seam the agent cannot fake. - Test Deletion Is a Privileged Operation
The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review. - The Instruction File Is Not the Discipline
Teams that want their agent to do TDD reach for the instruction file. The TDAD paper measured this directly: adding a 'do TDD' instruction raised regressions by nearly two-thirds. Contextual test discovery cut them by seventy percent. The instruction is theatre. The codebase's test surface is the discipline.