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
This commit is contained in:
2025-11-02 17:09:21 +00:00
parent 897cb5de13
commit b962ebf214
+268
View File
@@ -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<number | null>(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