From b962ebf214ca9a95b83affec3d3002d9911161cc Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Sun, 2 Nov 2025 17:09:21 +0000 Subject: [PATCH] docs: add UNIFIED_API update recommendations - Provide detailed before/after examples for all sections - Document new gameOver pattern with flexible function-based conditions - Explain migration path for games updating to this pattern - Highlight benefits: pure data collection, separation of concerns, flexibility - Guide for updating root UNIFIED_API.md to reflect vim-maze v2.3 changes --- UNIFIED_API_UPDATES.md | 268 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 UNIFIED_API_UPDATES.md diff --git a/UNIFIED_API_UPDATES.md b/UNIFIED_API_UPDATES.md new file mode 100644 index 0000000..7562813 --- /dev/null +++ b/UNIFIED_API_UPDATES.md @@ -0,0 +1,268 @@ +# UNIFIED_API.md Update Recommendations + +This document outlines the changes needed in `/vimazing/games/UNIFIED_API.md` to reflect the scoring refactor implemented in vim-maze v2.3.0. + +## Summary of Changes + +Vim-maze has implemented a new pattern for score management: +- **ScoreManager** is now a pure data collector (no score calculation) +- **Score calculation** moved to consumer (via utility function or custom logic) +- **Game-over conditions** are fully flexible and consumer-controlled + +## Required Updates + +### 1. Example Entry Point (Line ~100) + +**OLD:** +```typescript +// vim-maze +useGame({ rows: 24, cols: 32, timeLimit: 600 }) +``` + +**NEW:** +```typescript +// vim-maze (with custom game-over condition) +useGame({ + rows: 24, + cols: 32, + gameOver: (sm) => sm.timeValue >= 600000 // 10 minutes in milliseconds +}) +``` + +### 2. Score Manager Type (Line ~189-201) + +**OLD:** +```typescript +type ScoreManager = { + // Required Timing + timeValue: number; // Current time in milliseconds + + // Required Metrics + totalKeystrokes: number; // Total keys pressed + + // Required Result + finalScore: number | null; // 0-1000 (null until game-won) + + // Optional: Game-specific metrics + // [additional fields as needed] +}; +``` + +**NEW:** +```typescript +type ScoreManager = { + // Required Timing + timeValue: number; // Current time in milliseconds + + // Required Metrics + totalKeystrokes: number; // Total keys pressed + + // Optional: Game-specific metrics + // [additional fields as needed] + // NOTE: finalScore removed - calculation moved to consumer +}; +``` + +**Add note:** +``` +**Important:** ScoreManager is now a pure data collector. +Score calculation has been moved to the consumer. +Games should provide a utility function like `calculateScore()` +or instructions for score calculation in their documentation. +``` + +### 3. GameOptions Examples (Line ~222-230) + +**OLD:** +```typescript +// vim-maze +type GameOptions = { + rows: number; + cols: number; + timeLimit?: number; +}; +``` + +**NEW:** +```typescript +// vim-maze +type GameOptions = { + rows: number; + cols: number; + gameOver?: boolean | ((scoreManager: ScoreManager) => boolean); +}; +``` + +### 4. Scoring Implementation Section (Line ~257-265) + +**OLD:** +```typescript +**vim-maze approach:** +```typescript +// Size-based: time + keystrokes × maze size +const baseScore = 1000 - timePenalty - keystrokePenalty; +const sizeMultiplier = max(1.0, (rows × cols) / 500); +const finalScore = min(1000, baseScore × sizeMultiplier); +``` +``` + +**NEW:** +```typescript +**vim-maze approach (v2.3+):** +```typescript +// Pure data collection in ScoreManager +const scoreManager = useScore({ /* dependencies */ }); +// scoreManager returns: { timeValue, keystrokes, optimalSteps, efficiency, ... } + +// Score calculation moved to consumer +import { calculateMazeScore } from '@vimazing/vim-maze'; +const finalScore = calculateMazeScore(scoreManager, mazeSize); +// Base: 1000 - (time/10) - (keystrokes/2) +// Then: multiply by size factor = max(1.0, (rows × cols) / 500) +// Final: clamp to 0-1000 +``` +``` + +### 5. Scoring Requirements Section (Line ~203-208) + +**OLD:** +``` +**Scoring Requirements:** +- Score range: 0-1000 (capped) +- Score calculated on game-won +- Based on time and keystrokes (minimum) +- Can include game-specific penalties/bonuses +``` + +**NEW:** +``` +**Scoring Requirements:** +- Score range: 0-1000 (capped) +- Based on time and keystrokes (minimum) +- Can include game-specific penalties/bonuses +- **NEW:** Score calculation moved to consumer via utility function +- Games should provide `calculateScore()` or similar utility +- Games should document their scoring formula clearly +``` + +### 6. Game-Over Conditions Pattern (New Section) + +Add a new subsection after "Scoring Requirements": + +```markdown +### Game-Over Conditions + +Starting with vim-maze v2.3+, games have full control over game-over conditions: + +```typescript +type GameOptions = { + // ...game-specific options... + gameOver?: boolean | ((scoreManager: ScoreManager) => boolean); +}; +``` + +**Examples:** +```typescript +// Static game-over +useGame({ rows: 24, cols: 32, gameOver: true }) + +// Time-based +useGame({ + rows: 24, + cols: 32, + gameOver: (sm) => sm.timeValue >= 600000 // 10 minutes +}) + +// Efficiency-based +useGame({ + rows: 24, + cols: 32, + gameOver: (sm) => sm.efficiency > 150 // >150% keystrokes +}) + +// Combined conditions +useGame({ + rows: 24, + cols: 32, + gameOver: (sm) => sm.efficiency > 150 || sm.timeValue >= 600000 +}) +``` + +**Benefits:** +- No hardcoded game-over logic in libraries +- Consumers define win/loss conditions +- Flexible for tournaments, variations, custom rules +``` + +### 7. Hook Specifications - useScore Section (Line ~424+) + +Find and update the useScore section: + +**OLD:** +```typescript +export function useScore(/* dependencies */) { + // ... + const [timeValue, setTimeValue] = useState(0); + const [finalScore, setFinalScore] = useState(null); + + // Calculate score on game-won + useEffect(() => { + if (gameStatus === 'game-won') { + const score = calculateScore(timeValue, totalKeystrokes); + setFinalScore(Math.min(1000, Math.max(0, score))); + } + }, [gameStatus]); + + return { + timeValue, + totalKeystrokes, + finalScore, + // Additional metrics + }; +} +``` + +**NEW:** +```typescript +export function useScore(/* dependencies */) { + // Returns raw metrics only - no calculation + // Score calculation moved to consumer + + return { + timeValue, + totalKeystrokes, + // Additional game-specific metrics + // finalScore removed - consumer responsibility + }; +} +``` + +Add note: +``` +**Change in v2.3+:** ScoreManager is now a pure data collector. +All score calculation has been moved to the consumer. +This provides flexibility and allows games to: +- Provide utility functions for standard scoring +- Allow consumers to implement custom scoring +- Keep the hook focused on metrics collection +``` + +## Migration Guide for Games + +For games updating to this pattern: + +1. Remove `finalScore` from `ScoreManager` type +2. Remove score calculation logic from `useScore` hook +3. Export a `calculateScore()` utility function +4. Update `gameOver` option to accept function receiving `scoreManager` +5. Remove `timeLimit` logic from `useScore` (delegate to consumer) +6. Document the new scoring approach in gameInfo + +## Benefits of This Pattern + +✅ **Pure Data Collection** - ScoreManager has no side effects +✅ **Separation of Concerns** - Scoring logic is independent +✅ **Flexibility** - Consumers control both scoring and game-over +✅ **Testability** - Scoring functions can be tested in isolation +✅ **Reusability** - Metrics available for any custom logic +✅ **Clarity** - Clear boundaries between collection and calculation