From e5a651951d1dfe3aa95abb9d9251f2eea2687c9b Mon Sep 17 00:00:00 2001 From: fiatcode Date: Tue, 24 Feb 2026 10:53:19 +0700 Subject: [PATCH] docs: document Mars Rover kata --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 803531d..d8ef3b1 100644 --- a/README.md +++ b/README.md @@ -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 ---