AI Implementation feature(863): Challenges Page and Challenge Solve Modal (#45)

This commit was merged in pull request #45.
This commit is contained in:
2026-07-23 00:13:59 +00:00
parent dcda3dfd4d
commit 0bd1d9472a
40 changed files with 4710 additions and 130 deletions
@@ -0,0 +1,54 @@
import { timingSafeEqual } from 'crypto';
export type Difficulty = 'LOW' | 'MEDIUM' | 'HIGH';
export const DIFFICULTY_RANK: Readonly<Record<Difficulty, number>> = {
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);
}