Initial hidden11 MVP
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import playersData from "@/data/players.json";
|
||||
import puzzlesData from "@/data/puzzles.json";
|
||||
import type { Difficulty, Feedback, Guess, Player, Position, Puzzle } from "./types";
|
||||
|
||||
export const POSITIONS: Position[] = ["GK", "DEF", "MID", "WING", "ST"];
|
||||
export const DIFFICULTIES: Difficulty[] = ["easy", "medium", "hard"];
|
||||
export const MAX_ATTEMPTS = 6;
|
||||
|
||||
export const players = playersData as Player[];
|
||||
export const puzzles = puzzlesData as Puzzle[];
|
||||
|
||||
export function getTodayKey(date = new Date()): string {
|
||||
return date.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
export function getPuzzleNumber(dateKey: string): number {
|
||||
const epoch = Date.UTC(2026, 0, 1);
|
||||
const current = Date.parse(`${dateKey}T00:00:00.000Z`);
|
||||
return Math.max(1, Math.floor((current - epoch) / 86400000) + 1);
|
||||
}
|
||||
|
||||
export function getDailyPuzzles(dateKey: string): Puzzle[] {
|
||||
const dated = puzzles.filter((puzzle) => puzzle.date === dateKey);
|
||||
const fallback = puzzles.filter((puzzle) => puzzle.date === "2026-05-02");
|
||||
const source = dated.length === 3 ? dated : fallback;
|
||||
|
||||
return DIFFICULTIES.map((difficulty) => {
|
||||
const puzzle = source.find((item) => item.difficulty === difficulty);
|
||||
if (!puzzle) {
|
||||
throw new Error(`Missing ${difficulty} puzzle`);
|
||||
}
|
||||
return puzzle;
|
||||
});
|
||||
}
|
||||
|
||||
export function findPlayer(id: string | null): Player | undefined {
|
||||
if (!id) return undefined;
|
||||
return players.find((player) => player.id === id);
|
||||
}
|
||||
|
||||
export function validateGuess(puzzle: Puzzle, guess: Record<Position, string | null>): Guess {
|
||||
return {
|
||||
slots: POSITIONS.map((position) => ({
|
||||
position,
|
||||
playerId: guess[position],
|
||||
feedback: scoreSlot(puzzle.solution[position], guess[position]),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export function isSolved(guess: Guess): boolean {
|
||||
return guess.slots.every((slot) => slot.feedback === "correct");
|
||||
}
|
||||
|
||||
export function isAttemptComplete(guess: Record<Position, string | null>): boolean {
|
||||
return POSITIONS.every((position) => Boolean(guess[position]));
|
||||
}
|
||||
|
||||
export function getFixedGuess(puzzle: Puzzle): Record<Position, string | null> {
|
||||
return POSITIONS.reduce<Record<Position, string | null>>((acc, position) => {
|
||||
acc[position] = position === puzzle.fixedPosition ? puzzle.solution[position] : null;
|
||||
return acc;
|
||||
}, {} as Record<Position, string | null>);
|
||||
}
|
||||
|
||||
function scoreSlot(solutionId: string, guessId: string | null): Feedback {
|
||||
if (!guessId) return "empty";
|
||||
if (guessId === solutionId) return "correct";
|
||||
|
||||
const solution = findPlayer(solutionId);
|
||||
const guess = findPlayer(guessId);
|
||||
|
||||
if (!solution || !guess) return "wrong";
|
||||
|
||||
const hasClubRelation = solution.club === guess.club;
|
||||
const hasLeagueMatch = solution.league === guess.league;
|
||||
const hasNationalityMatch = solution.nationality === guess.nationality;
|
||||
const hasPositionMatch = solution.position === guess.position;
|
||||
|
||||
return hasClubRelation || hasLeagueMatch || hasNationalityMatch || hasPositionMatch ? "partial" : "wrong";
|
||||
}
|
||||
Reference in New Issue
Block a user