import { timingSafeEqual } from 'crypto'; export type Difficulty = 'LOW' | 'MEDIUM' | 'HIGH'; export const DIFFICULTY_RANK: Readonly> = { LOW: 0, MEDIUM: 1, HIGH: 2, }; export function compareDifficulty(a: Difficulty, b: Difficulty): number { return DIFFICULTY_RANK[a] - DIFFICULTY_RANK[b]; } export function computeLivePoints( initial: number, minimum: number, decaySolves: number, currentSolveCount: number, ): number { if (!Number.isFinite(initial) || !Number.isFinite(minimum)) return minimum; const i = Math.max(0, Math.floor(initial)); const m = Math.max(0, Math.floor(minimum)); const d = Math.max(0, Math.floor(decaySolves)); const c = Math.max(0, Math.floor(currentSolveCount)); if (i < m) return Math.max(0, m); if (d <= 0) return i; if (c >= d) return m; const span = i - m; const raw = i - span * (c / d); return Math.max(m, Math.round(raw)); } export function rankBonusForPosition(position: number): number { if (!Number.isInteger(position) || position <= 0) return 0; if (position === 1) return 15; if (position === 2) return 10; if (position === 3) return 5; return 0; } export function safeEqualString(a: string, b: string): boolean { const ab = Buffer.from(a, 'utf8'); const bb = Buffer.from(b, 'utf8'); if (ab.length !== bb.length) { let diff = ab.length ^ bb.length; const max = Math.max(ab.length, bb.length); for (let i = 0; i < max; i += 1) { diff |= (ab[i] ?? 0) ^ (bb[i] ?? 0); } return false; } return timingSafeEqual(ab, bb); }