frequency.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. import type { SolverStep } from '@wordle/shared';
  2. function getFeedback(target: string, guess: string): string {
  3. const tu = target.toLowerCase(), gu = guess.toLowerCase();
  4. const counts: Record<string, number> = {};
  5. for (const ch of tu) counts[ch] = (counts[ch] ?? 0) + 1;
  6. const r: string[] = Array(5).fill('x');
  7. for (let i = 0; i < 5; i++) { if (gu[i] === tu[i]) { r[i] = 'g'; counts[gu[i]]--; } }
  8. for (let i = 0; i < 5; i++) { if (r[i] === 'g') continue; if ((counts[gu[i]] ?? 0) > 0) { r[i] = 'y'; counts[gu[i]]--; } }
  9. return r.join('');
  10. }
  11. function letterFrequency(words: string[]): Record<string, number> {
  12. const freq: Record<string, number> = {};
  13. for (const w of words) {
  14. const seen = new Set<string>();
  15. for (const ch of w) { if (!seen.has(ch)) { freq[ch] = (freq[ch] ?? 0) + 1; seen.add(ch); } }
  16. }
  17. return freq;
  18. }
  19. function scoreWord(word: string, freq: Record<string, number>): number {
  20. const seen = new Set<string>(); let s = 0;
  21. for (const ch of word) { if (!seen.has(ch)) { s += freq[ch] ?? 0; seen.add(ch); } }
  22. return s;
  23. }
  24. export function solveFrequency(target: string, allWords: string[], maxAttempts = 6): { attempts: number; steps: SolverStep[] } {
  25. let candidates = [...allWords];
  26. const steps: SolverStep[] = [];
  27. for (let attempt = 1; attempt <= maxAttempts; attempt++) {
  28. const freq = letterFrequency(candidates);
  29. const pool = attempt === 1 ? allWords : candidates;
  30. let bestGuess = pool[0]; let bestScore = -1;
  31. for (const g of pool) { const s = scoreWord(g, freq); if (s > bestScore) { bestScore = s; bestGuess = g; } }
  32. const fb = getFeedback(target, bestGuess);
  33. steps.push({ guess: bestGuess, colors: fb.split('') });
  34. if (fb === 'ggggg') return { attempts: attempt, steps };
  35. candidates = candidates.filter((c) => getFeedback(c, bestGuess) === fb);
  36. if (candidates.length === 0) return { attempts: maxAttempts + 1, steps };
  37. }
  38. return { attempts: maxAttempts + 1, steps };
  39. }