feedback.ts 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. /**
  2. * Compute Wordle feedback colors for a guess against the target word.
  3. *
  4. * Algorithm (Feedback Scoring Rule):
  5. * 1. Mark exact-position matches (green/'g'), decrement remaining letter count
  6. * 2. For remaining positions, mark as yellow/'y' if letter still has remaining count
  7. * 3. All other positions are gray/'x'
  8. *
  9. * Returns a 5-element array of 'g' | 'y' | 'x'.
  10. */
  11. export function computeFeedback(target: string, guess: string): string[] {
  12. if (target.length !== 5 || guess.length !== 5) {
  13. throw new Error('Target and guess must be exactly 5 letters');
  14. }
  15. const targetUpper = target.toLowerCase();
  16. const guessUpper = guess.toLowerCase();
  17. // Count letters in target
  18. const targetCounts: Record<string, number> = {};
  19. for (const ch of targetUpper) {
  20. targetCounts[ch] = (targetCounts[ch] ?? 0) + 1;
  21. }
  22. const result: string[] = Array(5).fill('x');
  23. // Pass 1: greens (exact position matches)
  24. for (let i = 0; i < 5; i++) {
  25. if (guessUpper[i] === targetUpper[i]) {
  26. result[i] = 'g';
  27. targetCounts[guessUpper[i]]--;
  28. }
  29. }
  30. // Pass 2: yellows (letter present but wrong position, remaining count)
  31. for (let i = 0; i < 5; i++) {
  32. if (result[i] === 'g') continue; // already matched
  33. const ch = guessUpper[i];
  34. if ((targetCounts[ch] ?? 0) > 0) {
  35. result[i] = 'y';
  36. targetCounts[ch]--;
  37. }
  38. }
  39. return result;
  40. }