96 lines
3.0 KiB
TypeScript
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
|
|
};
|
|
} |