fuzzyworld

word-waltz / commit

added emoji for each game played

26f9fd7255347ae76c3893db251aa4ed333683be · Pavel Safronov · 2026-03-25 22:37:00 -0700 · parents 42caeb8510d0

added emoji for each game played
 src/components/Scoreboard.ts     | 11 ++++++++++-
 src/components/SoloScoreboard.ts | 11 ++++++++++-
 src/styles/main.css              | 10 ++++++++++
 src/utils/scoring.ts             | 29 +++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/src/components/Scoreboard.ts b/src/components/Scoreboard.ts
index 4dc1aa1..8286201 100644
--- a/src/components/Scoreboard.ts
+++ b/src/components/Scoreboard.ts
@@ -1,4 +1,5 @@
 import type { Player, PlayerId, Round } from '../types.js';
+import { guessesToEmoji } from '../utils/scoring.js';
 
 /**
  * Scoreboard — running score display
@@ -133,7 +134,15 @@ export function mountScoreboard(container: HTMLElement, props: ScoreboardProps):
         : `failed to solve "${r.word}"`;
       const li = document.createElement('li');
       li.className = 'scoreboard__round';
-      li.textContent = `${solverName}: ${result}`;
+      const textEl = document.createElement('span');
+      textEl.textContent = `${solverName}: ${result}`;
+      li.appendChild(textEl);
+      if (r.guesses.length > 0) {
+        const emojiEl = document.createElement('div');
+        emojiEl.className = 'scoreboard__emoji';
+        emojiEl.textContent = guessesToEmoji(r.guesses, r.word);
+        li.appendChild(emojiEl);
+      }
       ol.appendChild(li);
     });
     historyEl.appendChild(ol);
diff --git a/src/components/SoloScoreboard.ts b/src/components/SoloScoreboard.ts
index d7b7d9e..101d650 100644
--- a/src/components/SoloScoreboard.ts
+++ b/src/components/SoloScoreboard.ts
@@ -6,6 +6,7 @@
  */
 
 import type { SoloRound } from '../types.js';
+import { guessesToEmoji } from '../utils/scoring.js';
 
 interface SoloScoreboardProps {
     playerName: string;
@@ -118,7 +119,15 @@ export function mountSoloScoreboard(
                 : `failed to solve "${r.word}"`;
             const li = document.createElement('li');
             li.className = 'scoreboard__round';
-            li.textContent = result;
+            const textEl = document.createElement('span');
+            textEl.textContent = result;
+            li.appendChild(textEl);
+            if (r.guesses.length > 0) {
+                const emojiEl = document.createElement('div');
+                emojiEl.className = 'scoreboard__emoji';
+                emojiEl.textContent = guessesToEmoji(r.guesses, r.word);
+                li.appendChild(emojiEl);
+            }
             ol.appendChild(li);
         });
         historyEl.appendChild(ol);
diff --git a/src/styles/main.css b/src/styles/main.css
index 615a19a..775f007 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -301,6 +301,16 @@ header {
 .scoreboard__round {
     font-size: 0.8rem;
     color: var(--color-muted);
+    display: flex;
+    flex-direction: column;
+    gap: 3px;
+}
+
+.scoreboard__emoji {
+    font-size: 0.7rem;
+    line-height: 1.4;
+    letter-spacing: 0.05em;
+    white-space: pre;
 }
 
 /* --- Wordle board ----------------------------------------- */
diff --git a/src/utils/scoring.ts b/src/utils/scoring.ts
index 576dc10..c60efc4 100644
--- a/src/utils/scoring.ts
+++ b/src/utils/scoring.ts
@@ -20,3 +20,32 @@ export function calculateScore(guessCount: number, solved: boolean): number {
   if (!solved) return 0;
   return Math.max(0, 7 - guessCount);
 }
+
+const WORD_LEN = 5;
+
+function evaluateGuess(guess: string, secret: string): Array<'correct' | 'present' | 'absent'> {
+  const result: Array<'correct' | 'present' | 'absent'> = Array(WORD_LEN).fill('absent');
+  const remaining = secret.split('');
+  for (let i = 0; i < WORD_LEN; i++) {
+    if (guess[i] === secret[i]) { result[i] = 'correct'; remaining[i] = ''; }
+  }
+  for (let i = 0; i < WORD_LEN; i++) {
+    if (result[i] === 'correct') continue;
+    const idx = remaining.indexOf(guess[i]);
+    if (idx !== -1) { result[i] = 'present'; remaining[idx] = ''; }
+  }
+  return result;
+}
+
+const EMOJI: Record<'correct' | 'present' | 'absent', string> = {
+  correct: '🟩',
+  present: '🟨',
+  absent: '⬛',
+};
+
+/** Convert a list of guesses for a given secret word into Wordle emoji rows. */
+export function guessesToEmoji(guesses: string[], secret: string): string {
+  return guesses
+    .map((g) => evaluateGuess(g, secret.toUpperCase()).map((s) => EMOJI[s]).join(''))
+    .join('\n');
+}