Files
hoerdle/lib/gameState.ts

156 lines
4.9 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { getTodayISOString } from './dateUtils';
export interface GameState {
date: string;
guesses: string[]; // Array of song titles or IDs guessed
isSolved: boolean;
isFailed: boolean;
lastPlayed: number; // Timestamp
}
export interface Statistics {
solvedIn1: number;
solvedIn2: number;
solvedIn3: number;
solvedIn4: number;
solvedIn5: number;
solvedIn6: number;
solvedIn7: number;
failed: number;
}
const STORAGE_KEY = 'hoerdle_game_state';
const STATS_KEY = 'hoerdle_statistics';
export function useGameState(genre: string | null = null, maxAttempts: number = 7) {
const [gameState, setGameState] = useState<GameState | null>(null);
const [statistics, setStatistics] = useState<Statistics | null>(null);
const STORAGE_KEY_PREFIX = 'hoerdle_game_state';
const STATS_KEY_PREFIX = 'hoerdle_statistics';
const getStorageKey = () => genre ? `${STORAGE_KEY_PREFIX}_${genre}` : STORAGE_KEY_PREFIX;
const getStatsKey = () => genre ? `${STATS_KEY_PREFIX}_${genre}` : STATS_KEY_PREFIX;
useEffect(() => {
// Load game state
const storageKey = getStorageKey();
const stored = localStorage.getItem(storageKey);
const today = getTodayISOString();
if (stored) {
const parsed: GameState = JSON.parse(stored);
if (parsed.date === today) {
setGameState(parsed);
} else {
// New day
const newState: GameState = {
date: today,
guesses: [],
isSolved: false,
isFailed: false,
lastPlayed: Date.now(),
};
setGameState(newState);
localStorage.setItem(storageKey, JSON.stringify(newState));
}
} else {
// No state
const newState: GameState = {
date: today,
guesses: [],
isSolved: false,
isFailed: false,
lastPlayed: Date.now(),
};
setGameState(newState);
localStorage.setItem(storageKey, JSON.stringify(newState));
}
// Load statistics
const statsKey = getStatsKey();
const storedStats = localStorage.getItem(statsKey);
if (storedStats) {
const parsedStats = JSON.parse(storedStats);
// Migration for existing stats without solvedIn7
if (parsedStats.solvedIn7 === undefined) {
parsedStats.solvedIn7 = 0;
}
setStatistics(parsedStats);
} else {
const newStats: Statistics = {
solvedIn1: 0,
solvedIn2: 0,
solvedIn3: 0,
solvedIn4: 0,
solvedIn5: 0,
solvedIn6: 0,
solvedIn7: 0,
failed: 0,
};
setStatistics(newStats);
localStorage.setItem(statsKey, JSON.stringify(newStats));
}
}, [genre]); // Re-run when genre changes
const saveState = (newState: GameState) => {
setGameState(newState);
localStorage.setItem(getStorageKey(), JSON.stringify(newState));
};
const updateStatistics = (attempts: number, solved: boolean) => {
if (!statistics) return;
const newStats = { ...statistics };
if (solved) {
switch (attempts) {
case 1: newStats.solvedIn1++; break;
case 2: newStats.solvedIn2++; break;
case 3: newStats.solvedIn3++; break;
case 4: newStats.solvedIn4++; break;
case 5: newStats.solvedIn5++; break;
case 6: newStats.solvedIn6++; break;
case 7: newStats.solvedIn7++; break;
default:
// For custom attempts > 7, we currently don't have specific stats buckets
// We could add a 'solvedInOther' or just ignore for now
break;
}
} else {
newStats.failed++;
}
setStatistics(newStats);
localStorage.setItem(getStatsKey(), JSON.stringify(newStats));
};
const addGuess = (guess: string, correct: boolean) => {
if (!gameState) return;
const newGuesses = [...gameState.guesses, guess];
const isSolved = correct;
const isFailed = !correct && newGuesses.length >= maxAttempts;
const newState = {
...gameState,
guesses: newGuesses,
isSolved,
isFailed,
lastPlayed: Date.now(),
};
saveState(newState);
// Update statistics when game ends
if (isSolved || isFailed) {
updateStatistics(newGuesses.length, isSolved);
}
};
return { gameState, statistics, addGuess };
}