refactor: separate score calculation from score management

BREAKING CHANGES:
- Remove timeLimit from GameOptions (use gameOver function instead)
- Remove finalScore from ScoreManager (pure data collection only)
- Remove rows/cols parameters from useScore
- Remove finalScore calculation logic from useScore hook

ADDITIONS:
- Create calculateMazeScore() utility function
- ScoreManager now only returns raw metrics: timeValue, keystrokes, optimalSteps, efficiency, distToKey, distToExit
- Score calculation moved to consumer (calculateMazeScore takes scoreManager + mazeSize)
- Example app now uses calculateMazeScore to compute final score on game-won

BENEFITS:
- ScoreManager is now a pure data collector with no side effects
- Scoring algorithm is reusable and testable in isolation
- Game-over conditions fully controlled via gameOver option
- Clear separation of concerns: collection vs calculation
This commit is contained in:
2025-11-02 17:04:21 +00:00
parent 060c8abb24
commit 0749aba648
8 changed files with 46 additions and 41 deletions
+30
View File
@@ -0,0 +1,30 @@
import type { ScoreManager } from './types';
/**
* Calculate the final maze score based on performance metrics
*
* Formula:
* Base Score = 1000 - (time penalty) - (keystroke penalty)
* Size Multiplier = max(1.0, (mazeSize) / 500)
* Final Score = min(1000, max(0, round(Base Score × Size Multiplier)))
*
* Penalties:
* - Time Penalty = seconds / 10
* - Keystroke Penalty = keystrokes / 2
*
* @param scoreManager - Current score metrics
* @param mazeSize - Total cells in maze (rows * cols)
* @returns Final score between 0-1000
*/
export function calculateMazeScore(scoreManager: ScoreManager, mazeSize: number): number {
const seconds = scoreManager.timeValue / 1000;
const timePenalty = seconds / 10;
const keystrokePenalty = scoreManager.keystrokes / 2;
const sizeMultiplier = Math.max(1.0, mazeSize / 500);
const baseScore = 1000 - timePenalty - keystrokePenalty;
const score = Math.min(1000, Math.max(0, Math.round(baseScore * sizeMultiplier)));
return score;
}