word-waltz / commit
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'); +}