import type { TargetWord, CachedResult } from '@wordle/shared'; /** * Select a target word weighted by proximity to the player's skill level. * * Algorithm: * 1. Compute a weight for each target based on how close its difficulty * is to the player's skill (Gaussian-like: 1 / (1 + (diff - skill)^2)) * 2. Pick randomly, weighted by those weights. * * Uncached words get default difficulty 3.0 — they converge to real values * as words get played and cached. */ export function selectPlayAgainWord( targets: TargetWord[], skillMetric: number, cache: Map, ): TargetWord { if (targets.length === 0) { throw new Error('No target words available'); } // Compute weights: closer difficulty = higher weight const weights = targets.map((t) => { const diff = cache.get(t.id)?.difficulty ?? 3.0; const delta = diff - skillMetric; return 1 / (1 + delta * delta); }); // Weighted random selection const totalWeight = weights.reduce((sum, w) => sum + w, 0); let r = Math.random() * totalWeight; for (let i = 0; i < targets.length; i++) { r -= weights[i]; if (r <= 0) { return targets[i]; } } // Fallback (floating point edge case) return targets[targets.length - 1]; }