docs: document Mars Rover kata

This commit is contained in:
fiatcode 2026-02-24 10:53:19 +07:00
parent 5ee4e1edc0
commit e5a651951d

121
README.md
View file

@ -312,6 +312,86 @@ calculator.add('2,1001'); // Returns: 2 (1001 ignored)
---
### 5. Mars Rover ✅
**Implementation:** [`lib/mars_rover.dart`](lib/mars_rover.dart)
**Tests:** [`test/mars_rover_test.dart`](test/mars_rover_test.dart)
A Command Pattern kata simulating a robotic rover navigating a plateau on Mars. Demonstrates clean separation of concerns, value objects, and command-based control.
#### Domain Context
A rover explores a rectangular plateau with coordinate-based navigation:
**Core Concepts:**
- **Position:** (x, y) coordinates on the plateau grid
- **Direction:** Cardinal directions (N, E, S, W)
- **Plateau:** Grid with defined boundaries that wrap around (toroidal topology)
**Commands:**
- `L` - Turn left 90 degrees (changes direction, not position)
- `R` - Turn right 90 degrees (changes direction, not position)
- `M` - Move forward one grid point in current direction
**Example Navigation:**
```
Starting: (0,0) facing North
Commands: "MMRMMLM"
- MM: Move to (0,2) facing North
- R: Turn to face East (still at 0,2)
- MM: Move to (2,2) facing East
- L: Turn to face North (still at 2,2)
- M: Move to (2,3) facing North
Result: (2,3) facing North
```
#### Key Design Decisions
**Direction Enum:** Encapsulates rotation logic using modular arithmetic. Each direction knows how to turn left/right, eliminating conditional branching.
**Value Objects:**
- `Position` is immutable—movement returns new position instances
- `Plateau` encapsulates boundary wrapping logic
- Prevents invalid states at the type level
**Command Pattern (Implicit):** The `execute()` method delegates to command handlers (`turnLeft()`, `turnRight()`, `moveForward()`). Each command is isolated and testable.
**Wrapping Logic:** Plateau boundaries wrap around (toroidal topology). Moving past edge (e.g., x=5→6 on 5x5 grid) wraps to opposite side (x=0).
#### Usage
```dart
import 'package:tdd_katas/mars_rover.dart';
// Create rover at position (1,2) facing North on 5x5 plateau
final rover = Rover(
x: 1,
y: 2,
direction: 'N',
plateauWidth: 5,
plateauHeight: 5,
);
rover.execute('LMLMLMLMM');
print('Position: (${rover.x}, ${rover.y})'); // Position: (1, 3)
print('Direction: ${rover.direction}'); // Direction: N
```
#### The "Aha!" Moments
1. **Enums as Behavior Carriers:** Direction enum doesn't just store values—it encapsulates rotation logic. Turning left/right becomes `direction.turnLeft()`, eliminating lookup tables.
2. **Value Objects Prevent Bugs:** Immutable `Position` means movement can't corrupt state. New position calculated, validated, then assigned. Boundary wrapping isolated in `Plateau`.
3. **Switch Expressions Shine:** Modern Dart's `switch` expression makes direction-based movement elegant and exhaustive. Compiler enforces handling all directions.
4. **Modular Arithmetic for Rotation:** `(index + 1) % 4` handles right rotation elegantly. No if-statements, no edge cases—math models the domain perfectly.
5. **Refactoring Without Fear:** Two refactoring commits drastically improved code structure. Tests stayed green throughout, proving behavior preservation.
---
## Running Tests
```bash
@ -323,6 +403,7 @@ dart test test/roman_numerals_test.dart
dart test test/bowling_game_test.dart
dart test test/gilded_rose_test.dart
dart test test/string_calculator_test.dart
dart test test/mars_rover_test.dart
# Run with coverage
dart test --coverage
@ -630,19 +711,19 @@ Decision: Skip refactor commit—code is already excellent.
## Comparing the Katas
### All Four Katas at a Glance
### All Five Katas at a Glance
| Aspect | Roman Numerals | Bowling Game | Gilded Rose | String Calculator |
|--------|----------------|--------------|-------------|-------------------|
| **Complexity** | Beginner | Intermediate | Advanced | Beginner |
| **Approach** | Greenfield TDD | Greenfield TDD | Legacy refactoring | Bug hunting |
| **State** | Stateless | Stateful | Stateful | Stateless |
| **Algorithm** | Table-driven | Frame iteration | Strategy pattern | String parsing |
| **Key Challenge** | Pattern recognition | State & bonuses | Refactoring safely | Finding bugs |
| **Design Pattern** | Value Object | Implicit strategy | Explicit strategy | Filters & pipes |
| **Lines of Code** | ~45 production | ~30 production | ~120 production | ~25 production |
| **Test Count** | ~15 tests | ~10 tests | ~17 tests | 6 tests |
| **Aha! Moment** | Table = data | Simple → complex | Refactor = safe | Tests find bugs |
| Aspect | Roman Numerals | Bowling Game | Gilded Rose | String Calculator | Mars Rover |
|--------|----------------|--------------|-------------|-------------------|------------|
| **Complexity** | Beginner | Intermediate | Advanced | Beginner | Intermediate |
| **Approach** | Greenfield TDD | Greenfield TDD | Legacy refactoring | Bug hunting | Greenfield TDD |
| **State** | Stateless | Stateful | Stateful | Stateless | Stateful |
| **Algorithm** | Table-driven | Frame iteration | Strategy pattern | String parsing | Command pattern |
| **Key Challenge** | Pattern recognition | State & bonuses | Refactoring safely | Finding bugs | Navigation & wrapping |
| **Design Pattern** | Value Object | Implicit strategy | Explicit strategy | Filters & pipes | Command + Value Objects |
| **Lines of Code** | ~45 production | ~30 production | ~120 production | ~25 production | ~95 production |
| **Test Count** | ~15 tests | ~10 tests | ~17 tests | 6 tests | 23 tests |
| **Aha! Moment** | Table = data | Simple → complex | Refactor = safe | Tests find bugs | Enums carry behavior |
### What Each Kata Teaches
@ -669,16 +750,24 @@ Decision: Skip refactor commit—code is already excellent.
- Incremental debugging with clear commits
- Regression prevention through test accumulation
**Mars Rover:**
- Command pattern for behavior delegation
- Value Objects for domain modeling (Position, Plateau, Direction)
- Enums as behavior carriers, not just constants
- Coordinate systems and wrapping logic
- Progressive refactoring with confidence
### Progressive Learning Path
1. **Roman Numerals first:** Learn TDD fundamentals without state complexity
2. **Bowling Game second:** Apply TDD to stateful problems
3. **Gilded Rose third:** Master refactoring legacy code with tests as safety net
4. **String Calculator fourth:** Practice bug hunting and fixing with TDD
5. **Next kata:** Choose based on what you want to practice:
- **Mars Rover:** Command pattern, multiple behaviors
3. **Mars Rover third:** Master Command pattern and value objects
4. **Gilded Rose fourth:** Refactor legacy code with tests as safety net
5. **String Calculator fifth:** Practice bug hunting and fixing with TDD
6. **Next kata:** Choose based on what you want to practice:
- **Prime Factors:** Mathematical decomposition, algorithmic thinking
- **Tennis Scoring:** State machines, domain language
- **FizzBuzz:** Classic conditional logic exercise
---