Files
vim-sudoku/IMPLEMENTATION_PLAN.md
T
pastilhas 4e14d54122 feat: implement Phase 30 - useGameStatus hook
Extract game status logic into dedicated hook following vim-maze pattern:

New Module Structure:
- src/useGameStatus/types.ts: GameStatus and GameStatusManager types
- src/useGameStatus/useGameStatus.ts: Hook implementation
- src/useGameStatus/index.ts: Public exports

Hook Implementation:
- State machine with 5 states (waiting/started/paused/game-over/game-won)
- Methods: startGame, togglePause, quitGame, setGameStatus
- Clean state transitions with useState
- Simpler than vim-maze (no intermediate 'has-key' state)

Updated Core Files:
- src/useGame.ts: Use useGameStatus() instead of inline useState
  - Compose gameStatusManager into GameManager
  - Cleaner separation of concerns

- src/types.ts: Import and re-export GameStatus types
  - GameManager extends GameStatusManager (intersection type)
  - Single source of truth for status types

- src/index.ts: Export useGameStatus hook publicly

Benefits:
- Reusable state machine
- Easier to test in isolation
- Follows unified API architecture
- Matches vim-maze patterns

State Transitions:
waiting → startGame() → started ↔ togglePause() ↔ paused
started → (win/lose) → game-won/game-over
* → quitGame() → waiting

Phase 30 complete. Next: Phase 40 (useCursor composition).
2025-10-22 18:45:56 +01:00

259 lines
9.1 KiB
Markdown

# vim-sudoku Unified API Implementation Plan
## Overview
Port vim-sudoku to the unified API architecture established by vim-maze, following the composable hook pattern with `useGame()` as the single entry point.
## Goals
1. Follow unified API architecture from UNIFIED_API.md
2. Maintain vim-maze patterns and conventions
3. Preserve all working functionality from src_old
4. Support platform integration via optional platformHook parameter
5. Enable code reuse across games (vim-maze, vim-sudoku, vim-snake)
## Architecture
### Core Composition
```tsx
// Inside useGame:
const board = useBoard();
const gameStatusManager = useGameStatus();
const { cursor, keyManager } = useCursor(board, gameStatusManager);
const scoreManager = useScore({ board, gameStatusManager, keyManager });
// Returns unified GameManager interface
```
## File Structure
```
src/
├── index.ts # Main package exports
├── types.ts # Re-exports all types from modules
├── useGame.ts # Main orchestrator hook
├── useGameStatus/
│ ├── index.ts # Public exports
│ ├── types.ts # GameStatus, GameStatusManager
│ └── useGameStatus.ts # Game state management
├── useBoard/
│ ├── index.ts # Public exports
│ ├── types.ts # SudokuBoard, SudokuCell, Difficulty, BoardManager
│ ├── useBoard.ts # Board management hook
│ ├── SudokuGenerator.ts # Puzzle generation (from src_old/lib/Sudoku.ts)
│ └── SudokuRenderer.ts # DOM rendering for sudoku grid
├── useCursor/
│ ├── index.ts # Public exports
│ ├── types.ts # CursorManager, CursorMode, VimMotionSystem, CellEditor
│ ├── useCursor.ts # Main cursor/input hook
│ ├── useCellEditor.ts # Cell editing logic (analog to useHero)
│ ├── useCursorRender.ts # Cursor rendering on DOM (analog to useHeroRender)
│ ├── useVimMotions.ts # Vim keybinding system
│ └── useGameKeys.ts # Game-specific key handling
└── useScore/
├── index.ts # Public exports
├── types.ts # TimerManager, ScoreManager
├── useScore.ts # Main scoring hook
└── useTimer.ts # Timer state management
```
## Implementation Steps
### Phase 5: Prepare Example App
- [x] Update example/src/App.tsx to match vim-maze structure
- [x] Update App to display score metrics (time, keystrokes, final score)
- [x] Update App to show game status messages
- [x] Update App instructions for sudoku-specific keys (i for edit)
- [x] Keep it simple - no mobile support for now
### Phase 10: Setup & Core Types
- [ ] Create clean src/ directory structure
- [ ] Define all types in module-specific types.ts files
- [ ] Create index.ts exports for each module
- [ ] Set up main types.ts re-export file
### Phase 20: useBoard Hook
- [x] Port SudokuGenerator from src_old/lib/Sudoku.ts (Robatron's implementation)
- [x] Basic puzzle generation and rendering
- [x] Game flow integration (startGame/quitGame)
### Phase 21: Replace with Better Generation Algorithm
- [ ] Replace Robatron's algorithm with pattern-based generation
- [ ] Implement SudokuGenerator class (from src_old/sudoku/)
- [ ] Implement SudokuRenderer class for clean separation
- [ ] Update useBoard to use new classes
- [ ] Store both puzzle and solution refs
- [ ] Port unit tests for validation
- [ ] Three difficulty levels with configurable cell removal
### Phase 30: useGameStatus Hook
- [x] Implement GameStatus state machine
- 'waiting' → 'started' → 'game-won' / 'game-over'
- 'paused' state support
- [x] Methods: startGame, togglePause, quitGame, setGameStatus
- [x] Extract from inline useState in useGame
- [x] Create dedicated hook following vim-maze pattern
### Phase 40: useCursor Hook Composition
#### 40.1 useCellEditor (analog to useHero)
- [ ] Manage cursor position (row, col)
- [ ] Handle cell editing operations
- [ ] Validate edits against isGiven cells
- [ ] Trigger validation on cell changes
- [ ] Handle win condition detection
#### 40.2 useVimMotions
- [ ] Port vim motion system from vim-maze
- [ ] Support: h/j/k/l, ^/$, g/G, . (repeat)
- [ ] Support: i (insert), r (replace), x (delete)
- [ ] Count prefix handling (e.g., 5j)
- [ ] Mode transitions (normal ↔ edit)
#### 40.3 useGameKeys
- [ ] Keyboard event listener
- [ ] Route keys through vim motion processor
- [ ] Execute cursor movements
- [ ] Execute cell editing commands
- [ ] Track keystroke history
- [ ] Handle game-specific keys (q, p, space)
#### 40.4 useCursorRender (analog to useHeroRender)
- [ ] Render cursor highlight on current cell
- [ ] Show edit mode indicator
- [ ] Flash animations (valid/invalid/locked)
- [ ] Highlight conflict cells
#### 40.5 useCursor Main Hook
- [ ] Compose cellEditor, vimMotions, gameKeys, cursorRender
- [ ] Return unified CursorManager interface
- [ ] Split keyManager for useGame composition
### Phase 50: useScore Hook
- [ ] Port timer from src_old/useScore/hooks/useTimer.ts
- [ ] Track keystrokes from keyManager.keyLog
- [ ] Calculate efficiency metrics
- [ ] Detect win/loss conditions based on completion
- [ ] Compute final score on game-won
### Phase 60: useGame Orchestrator
- [ ] Compose all hooks (board, cursor, gameStatus, score)
- [ ] Handle initial board generation
- [ ] Coordinate rendering updates
- [ ] Expose unified GameManager interface
- [ ] Support optional platformHook parameter
### Phase 70: Testing & Refinement
- [ ] Test with example app
- [ ] Verify all vim motions work
- [ ] Verify edit mode (i/r/x) works
- [ ] Verify validation and conflicts work
- [ ] Verify win condition triggers
- [ ] Test platform hook integration
- [ ] Update UNIFIED_API.md with sudoku specifics
## Key Design Decisions
### 1. Board Representation
**Choice**: Use 2D array of SudokuCell objects
```typescript
type SudokuCell = {
value: string; // '1'-'9' or ''
isGiven: boolean; // true for puzzle clues
hasConflict: boolean; // validation state
};
type SudokuBoard = SudokuCell[][];
```
**Rationale**: Easier to work with than 81-char string, matches vim-maze pattern of using structured data.
### 2. Cell Editing (analog to Hero Movement)
**Choice**: useCellEditor hook manages cell editing state
- Similar to useHero managing hero position in maze
- Handles validation before setting values
- Triggers game status changes on completion
**Rationale**: Keeps editing logic separate from cursor movement, following vim-maze separation of concerns.
### 3. Edit Mode vs Insert Mode
**Choice**: Two modes - 'normal' and 'edit'
- Normal mode: vim navigation + commands (i/r/x/d)
- Edit mode: digit entry (1-9) + erase (x/Backspace)
- i = insert (enter edit mode on empty cell)
- r = replace (enter edit mode on filled cell)
- Escape/Enter = exit edit mode
**Rationale**: Matches vim philosophy and src_old behavior.
### 4. Rendering Strategy
**Choice**: Keep rendering separate from state
- SudokuRenderer handles DOM generation
- useCursorRender handles cursor highlighting
- useBoard calls renderer with board data
**Rationale**: Matches vim-maze pattern (MazeRenderer + useHeroRender).
### 5. Validation Approach
**Choice**: Validate on setCell, show conflicts visually
- Real-time validation when setting digits
- Flash animations for feedback
- Highlight conflicting cells temporarily
- Don't prevent invalid moves (optional strictMode)
**Rationale**: Provides immediate feedback without blocking player exploration.
## Type Mappings (vim-maze → vim-sudoku)
| vim-maze | vim-sudoku | Notes |
|----------|------------|-------|
| MazeCell[][] | SudokuBoard | Board structure |
| Coord | Coord | Same (row, col) |
| useHero | useCellEditor | Cell editing vs movement |
| useHeroRender | useCursorRender | Visual feedback |
| MazeGenerator | SudokuGenerator | Puzzle generation |
| MazeRenderer | SudokuRenderer | Grid rendering |
| hero.moveTo | cellEditor.setValue | Action semantics |
| 'entrance'/'exit'/'key' | 'isGiven'/'value' | Cell metadata |
## Differences from vim-maze
1. **No pathfinding**: Simple grid bounds checking
2. **Edit mode**: Need mode toggle for digit entry
3. **Validation**: Real-time conflict detection
4. **Win condition**: Complete + valid vs reach exit
5. **No animation**: Cursor moves instantly (no multi-step)
6. **Board generation**: On-demand vs one-time initialization
## Success Criteria
- [ ] All functionality from src_old preserved
- [ ] Follows unified API architecture
- [ ] Types match vim-maze patterns
- [ ] Hook composition mirrors vim-maze
- [ ] Example app works identically to src_old version
- [ ] Platform hook integration works
- [ ] Code is clean, documented, and maintainable
- [ ] UNIFIED_API.md updated with vim-sudoku section
## Notes
- Keep game.css from src_old for styling
- Port sudoku generation algorithm directly (working code)
- Maintain existing vim keybindings (h/j/k/l, ^/$, g/G, ., i/r/x)
- Preserve flash animations for visual feedback
- Follow AGENTS.md conventions throughout