| 12345678910111213141516171819202122232425262728293031323334353637383940414243 |
- 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<number, CachedResult>,
- ): 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];
- }
|