Files
vim-sudoku/src/useScore/useScore.ts
T
2025-10-19 17:59:12 +01:00

96 lines
3.0 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import type { BoardManager } from '../useBoard/types';
import type { GameStatusManager } from '../useGameStatus/types';
import type { ScoreManager, UseScoreProps } from './types';
import { useTimer } from './useTimer';
export function useScore({ board, gameStatusManager, keystrokeCount }: UseScoreProps): ScoreManager {
const timer = useTimer();
const [mistakes, setMistakes] = useState<number>(0);
const [hints, setHints] = useState<number>(0);
const addMistake = useCallback(() => {
setMistakes(prev => prev + 1);
}, []);
const addHint = useCallback(() => {
setHints(prev => prev + 1);
}, []);
const calculateEfficiency = useCallback((): number => {
const boardString = board.boardRef.current.map(row =>
row.map(cell => cell.value || '.').join('')
).join('');
const filledCells = boardString.replace(/\./g, '').length;
const totalCells = 81;
const givenCells = board.initialBoardRef.current.replace(/\./g, '').length;
const userFilledCells = filledCells - givenCells;
if (userFilledCells === 0) return 100;
const optimalMoves = userFilledCells;
const actualMoves = keystrokeCount;
const efficiency = Math.round((optimalMoves / actualMoves) * 100);
return Math.max(0, Math.min(100, efficiency));
}, [board, keystrokeCount]);
const calculateFinalScore = useCallback((): number | null => {
const { gameStatus } = gameStatusManager;
if (gameStatus !== 'game-won') return null;
const efficiency = calculateEfficiency();
const timeInSeconds = timer.timeValue / 1000;
const timeBonus = Math.max(0, 3600 - timeInSeconds) * 10;
const mistakePenalty = mistakes * 100;
const hintPenalty = hints * 200;
const baseScore = 10000;
const efficiencyBonus = efficiency * 50;
const finalScore = baseScore + efficiencyBonus + timeBonus - mistakePenalty - hintPenalty;
return Math.max(0, Math.round(finalScore));
}, [gameStatusManager, calculateEfficiency, timer.timeValue, mistakes, hints]);
useEffect(() => {
const { gameStatus } = gameStatusManager;
if (gameStatus === 'started') {
timer.startTimer();
} else if (gameStatus === 'paused' || gameStatus === 'game-over' || gameStatus === 'game-won') {
timer.stopTimer();
}
if (gameStatus === 'waiting') {
timer.resetTimer();
setMistakes(0);
setHints(0);
}
}, [gameStatusManager.gameStatus, timer]);
useEffect(() => {
const { gameStatus, setGameStatus } = gameStatusManager;
if (gameStatus === 'started' && board.isComplete() && board.isFullyValid()) {
setGameStatus('game-won');
}
}, [board, gameStatusManager]);
return {
timeValue: timer.timeValue,
keystrokes: keystrokeCount,
mistakes,
hints,
efficiency: calculateEfficiency(),
finalScore: calculateFinalScore(),
startTimer: timer.startTimer,
stopTimer: timer.stopTimer,
resetTimer: timer.resetTimer,
addMistake,
addHint,
calculateEfficiency,
calculateFinalScore
};
}