diff --git a/html/word-guesser/css/styles.css b/html/word-guesser/css/styles.css index 3833171..4cc8000 100644 --- a/html/word-guesser/css/styles.css +++ b/html/word-guesser/css/styles.css @@ -1,11 +1,19 @@ /* ============================================================ - WORD GUESSING GAME — STYLESHEET + WORD GUESSER — game stylesheet + Loads after styles.css and page.css. ============================================================ */ -/* ── Game Container ────────────────────────────────────────── */ +/* ── Scoped box-model reset ──────────────────────────────────── */ +#user_info_container *, +#gameplay_container *, +#scoreboard * { + box-sizing: border-box; +} + +/* ── Game form containers ────────────────────────────────────── */ .form_container { background-color: #ffffff; - border: 1px solid var(--border-medium); + border: 1px solid var(--border-medium, #dee2e6); border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05); max-width: 500px; @@ -16,9 +24,10 @@ gap: 15px; } +/* ── Game header ─────────────────────────────────────────────── */ .game-header h2 { - color: var(--accent-primary); - border-bottom: 2px solid var(--accent-primary); + color: var(--accent-primary, #2c3e50); + border-bottom: 2px solid var(--accent-primary, #2c3e50); display: inline-block; font-size: 1.4rem; margin-bottom: 0; @@ -28,11 +37,14 @@ #game_intro { font-size: 0.85rem; opacity: 0.7; + margin: 0; } -/* ── Notifications — fixed height, no layout shift ──────────── */ +/* ── Notifications — locked height, never shifts layout ─────── */ #notifications { + display: block; min-height: 1.5em; + max-height: 1.5em; line-height: 1.5em; overflow: hidden; text-overflow: ellipsis; @@ -42,7 +54,7 @@ font-size: 0.9rem; font-style: italic; color: var(--status-error, #d33333); - margin: 0; + margin: 4px 0; padding: 0; } @@ -53,47 +65,50 @@ color: var(--status-error, #d33333); } -/* ── Word Board ─────────────────────────────────────────────── */ +/* ── Word board ─────────────────────────────────────────────── */ #current_word { - display: flex; + display: flex !important; + flex-direction: row !important; flex-wrap: wrap; justify-content: center; align-items: center; gap: 5px; - list-style: none; - padding: 1rem 0; + list-style: none !important; + padding: 1rem 0 !important; width: 100%; - font-weight: bold; - letter-spacing: 5px; - font-size: 1.5rem; + margin: 0 !important; } #current_word li { - background-color: var(--bg-body); - border: 2px solid var(--accent-primary); + background-color: var(--bg-body, #f8f9fa); + border: 2px solid var(--accent-primary, #2c3e50) !important; + border-bottom: 3px solid var(--border-medium, #dee2e6) !important; border-radius: 4px; - border-bottom: 3px solid var(--border-medium); - display: flex; + display: flex !important; align-items: center; justify-content: center; - color: var(--accent-primary); + color: var(--accent-primary, #2c3e50); box-shadow: 2px 2px 0 rgba(44, 62, 80, 0.2); text-transform: uppercase; width: 32px; height: 42px; font-weight: bold; font-size: 1.4rem; + list-style: none !important; + margin: 0 !important; + padding: 0 !important; } .word-display-field { display: block !important; text-align: center; - padding: 2rem 0; + padding: 1rem 0; border-bottom: 2px solid #f1f3f5; } -/* ── Form Layout ────────────────────────────────────────────── */ -.formField { +/* ── Form fields (scoped to game containers) ─────────────────── */ +#gameplay_container .formField, +#splash_screen .formField { display: grid; grid-template-columns: 120px 1fr; gap: 20px; @@ -102,51 +117,52 @@ border-bottom: 1px solid #f1f3f5; } -.formField:last-of-type { +#gameplay_container .formField:last-of-type, +#splash_screen .formField:last-of-type { border-bottom: none; } -.formField label { +#gameplay_container .formField label, +#splash_screen .formField label { font-weight: 600; color: #495057; font-size: 0.9rem; } -/* ── Inputs & Buttons ───────────────────────────────────────── */ +/* ── How-to text ─────────────────────────────────────────────── */ +#game-howto p { + font-size: 0.875rem; + color: var(--text-muted, #6c757d); + text-align: center; + margin: 0; + padding: 0.5rem 0; +} + +/* ── Guess letter input ─────────────────────────────────────── */ #guess_letter { width: 50px; padding: 10px; text-align: center; font-size: 1.2rem; font-weight: bold; - border: 2px solid var(--border-medium); + border: 2px solid var(--border-medium, #dee2e6); border-radius: 4px; transition: border-color 0.2s; } #guess_letter:focus { - border-color: var(--accent-primary); + border-color: var(--accent-primary, #2c3e50); outline: none; } -#guess_count { - width: 60px; - background: #e9ecef; - border: 1px solid #ced4da; - padding: 5px; - text-align: center; - font-family: monospace; - font-weight: bold; - border-radius: 4px; -} - +/* ── Guess button ────────────────────────────────────────────── */ .submitField { - padding: 1.5rem 0; + padding: 1rem 0; text-align: center; } #guess_button { - background-color: var(--bg-header); + background-color: var(--bg-header, #2c3e50); color: #ffffff; border: none; padding: 0.8rem 2rem; @@ -159,20 +175,20 @@ } #guess_button:hover { - background-color: var(--bg-footer); + background-color: var(--bg-footer, #34495e); transform: translateY(-1px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } -/* ── Guess History Pills ────────────────────────────────────── */ +/* ── Guess history pills ────────────────────────────────────── */ #guesses { - display: flex; + display: flex !important; flex-wrap: nowrap; overflow-x: auto; gap: 5px; - padding: 5px 0; - margin: 0; - list-style: none; + padding: 5px 0 !important; + margin: 0 !important; + list-style: none !important; scrollbar-width: none; } @@ -183,31 +199,33 @@ #guesses li { background: var(--bg-tag, #e3f2fd); color: var(--accent-tag, #1976d2); - padding: 2px 8px; + padding: 2px 8px !important; border-radius: 3px; font-size: 0.85rem; font-family: "Roboto Mono", monospace; font-weight: bold; flex-shrink: 0; - border: 1px solid var(--border-tag, #bbdefb); + border: 1px solid var(--border-tag, #bbdefb) !important; + list-style: none !important; + margin: 0 !important; } -/* ── Alphabet Grid ──────────────────────────────────────────── */ -.alphabet-grid { - display: grid; +/* ── Alphabet grid ───────────────────────────────────────────── */ +#alphabet_container.alphabet-grid { + display: grid !important; grid-template-columns: repeat(9, 1fr); gap: 4px; background: #ebf3f9; - padding: 8px; + padding: 8px !important; border-radius: 8px; } .letter-btn { aspect-ratio: 1 / 1.2; - padding: 0; + padding: 0 !important; font-size: 1.1rem; font-weight: bold; - border: 1px solid #ced4da; + border: 1px solid #ced4da !important; border-radius: 4px; background: #fff; box-shadow: 0 2px 0 rgba(0, 0, 0, 0.1); @@ -215,6 +233,8 @@ transform 0.1s, background 0.1s; cursor: pointer; + line-height: 1; + margin: 0 !important; } .letter-btn:active { @@ -224,128 +244,135 @@ } .letter-btn.selected { - background: var(--bg-header); + background: var(--bg-header, #2c3e50) !important; color: #fff; - border-color: var(--bg-header); + border-color: var(--bg-header, #2c3e50) !important; box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25); } .letter-btn:disabled { - background: #e9ecef; + background: #e9ecef !important; color: #adb5bd; box-shadow: none; - border-color: transparent; + border-color: transparent !important; cursor: not-allowed; } -/* ── Game Metrics ───────────────────────────────────────────── */ +/* ── Game metrics row ────────────────────────────────────────── */ #game_metrics { - display: flex; + display: flex !important; justify-content: space-between; align-items: flex-start; gap: 15px; - padding: 10px; + padding: 10px !important; background: var(--bg-subtle, #f5f7fa); border-radius: 8px; - margin: 10px 0; + margin: 10px 0 !important; } -.formField.metric_group, #game_metrics .formField { flex: 1; - display: flex; - flex-direction: column; + display: flex !important; + flex-direction: column !important; + align-items: flex-start !important; gap: 4px; min-width: 0; + padding: 0 !important; + border-bottom: none !important; + grid-template-columns: unset; } #game_metrics .label { font-size: 0.75rem; font-weight: bold; text-transform: uppercase; - color: var(--text-muted); + color: var(--text-muted, #6c757d); letter-spacing: 0.05em; } #game_metrics #guess_count { width: 100%; - padding: 8px; - border: 1px solid var(--border-light); + padding: 8px !important; + border: 1px solid var(--border-light, #e0e0e0) !important; border-radius: 4px; background: #fff; font-family: "Roboto Mono", monospace; font-size: 1.1rem; text-align: center; - color: var(--text-main); + color: var(--text-main, #212529); } -/* ── Game Container ─────────────────────────────────────────── */ -#game_container { - max-width: 500px; - margin: 2rem auto; - background: #fff; - border-radius: 12px; - box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); - padding: 20px; - overflow: hidden; -} - -/* ── Splash / Login ─────────────────────────────────────────── */ +/* ── Splash / login ──────────────────────────────────────────── */ #user_info_container { display: flex; } #splash_screen { - border: none; - box-shadow: none; - padding: 0; + border: none !important; + box-shadow: none !important; + padding: 0 !important; } #game_form { display: none; } -/* ── Game Footer ────────────────────────────────────────────── */ -.game-footer { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px; - border-top: 1px solid #eee; - font-size: 0.9rem; -} - /* ============================================================ SCOREBOARD OVERLAY - JS toggles display: none <-> flex — that is preserved. - Layout & visual design is a complete rewrite. + JS toggles display: none <-> flex on #scoreboard only. + + Expected HTML structure: + #scoreboard + div.sb-card > div.sb-label + div.sb-value#total_words_attempted + div.sb-card > div.sb-label + div.sb-value#total_words_completed + div.sb-card > div.sb-label + div.sb-value#total_incorrect_guesses + div.sb-card > div.sb-label + div.sb-value#average_guesses_per_word + div.sb-card > div.sb-label + div.sb-value#average_time_per_word + div.sb-actions > #play_again + #quit_game ============================================================ */ + #scoreboard { - display: none; /* JS switches this to 'flex' */ - position: fixed; - inset: 0; - z-index: 9999; + display: none; /* JS sets this to 'flex' */ + position: fixed !important; + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + z-index: 9999 !important; justify-content: center; align-items: flex-end; /* bottom-sheet on mobile */ - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(3px); - -webkit-backdrop-filter: blur(3px); + background: rgba(0, 0, 0, 0.55) !important; + padding: 0 !important; + margin: 0 !important; + border: none !important; + border-radius: 0 !important; + box-shadow: none !important; + width: 100% !important; + max-width: none !important; } -/* ── Sheet card ─────────────────────────────────────────────── */ +/* ── Sheet / card ────────────────────────────────────────────── */ #scoreboard > div { - background: #ffffff; - border-radius: 20px 20px 0 0; - width: 100%; - max-width: 500px; + position: relative !important; + width: 100% !important; + max-width: 500px !important; + margin: 0 auto !important; + padding: 0 !important; + border-radius: 20px 20px 0 0 !important; + background: #ffffff !important; + box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.2) !important; + border: none !important; overflow: hidden; - - /* Reset the default shared grid — scoreboard card is its own layout */ - display: flex !important; - flex-direction: column; - gap: 0; - box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.15); animation: sb-rise 0.3s cubic-bezier(0.34, 1.1, 0.64, 1) both; + + /* 2-column grid: 5 cards + action row */ + display: grid !important; + grid-template-columns: 1fr 1fr; + grid-template-areas: + "handle handle" + "card card" + "card card" + "actions actions"; } @keyframes sb-rise { @@ -357,272 +384,146 @@ } } -/* Drag handle strip */ +/* Drag handle */ #scoreboard > div::before { content: ""; + grid-column: 1 / -1; display: block; width: 36px; height: 4px; border-radius: 2px; - background: rgba(255, 255, 255, 0.35); - margin: 12px auto 0; - order: -2; - flex-shrink: 0; + background: rgba(44, 62, 80, 0.18); + margin: 12px auto 8px; + justify-self: center; } -/* ── Dark header band ───────────────────────────────────────── */ -#scoreboard > div > div:first-child { - /* Override shared row rules completely */ +/* ── Stat cards ─────────────────────────────────────────────── */ +#scoreboard .sb-card { display: flex !important; flex-direction: column !important; - align-items: flex-start !important; justify-content: flex-start !important; - gap: 3px !important; - padding: 14px 20px 16px !important; - border-bottom: none !important; - - background: var(--bg-header, #2c3e50); - order: -1; -} - -#scoreboard > div > div:first-child > div:first-child { - font-size: 0.68rem; - font-weight: 700; - letter-spacing: 0.09em; - text-transform: uppercase; - color: rgba(255, 255, 255, 0.5); -} - -#scoreboard > div > div:first-child > div:last-child { - /* This is the "Total words completed" label — repurpose as heading */ - font-size: 1.2rem; - font-weight: 600; - color: #ffffff; -} - -/* ── Stat rows → 2-col card grid ────────────────────────────── */ -/* - The HTML has 4 stat rows + 1 button row inside #scoreboard > div. - We target rows 2–5 (nth-child 2–5) and float them into a grid. - Rows 2–5 = total words, incorrect guesses, avg guesses, avg time. - Row 6 = the button row (play again / quit). -*/ - -/* Wrapper grid — we can't add a real wrapper div, so we use - a CSS grid hack on the parent to re-layout children 2–5 */ -#scoreboard > div { - /* Already flex column — override with grid so we can span rows */ - display: grid !important; - grid-template-areas: - "handle" - "header" - "cards" - "buttons"; - grid-template-rows: auto auto 1fr auto; -} - -#scoreboard > div::before { - grid-area: handle; -} -#scoreboard > div > div:nth-child(1) { - grid-area: header; -} -#scoreboard > div > div:nth-child(5) { - grid-area: buttons; -} - -/* Rows 2–4 sit in the "cards" area — we need a sub-grid. - Since we can't wrap them in HTML, we absolutely position a - pseudo element background and use negative-margin columns. - Simpler: just style each stat row as a half-width card - and let them wrap. */ - -#scoreboard > div > div:nth-child(n + 2):nth-child(-n + 4) { - /* Stat card styling */ - margin: 0; - padding: 14px 16px !important; - border-bottom: none !important; - - /* Stack label over value */ - display: flex !important; - flex-direction: column !important; align-items: flex-start !important; - justify-content: flex-start !important; - gap: 4px !important; - - background: var(--bg-subtle, #f5f7fa); -} - -/* Put 2 cards per row by making each exactly half the container. - We use a flex row on the parent for rows 2-4. - Since this is a grid parent we rely on the grid column trick: */ -#scoreboard > div > div:nth-child(2) { - grid-column: 1; - border-right: 5px solid #fff; - border-bottom: 5px solid #fff !important; -} -#scoreboard > div > div:nth-child(3) { - grid-column: 2; - border-bottom: 5px solid #fff !important; -} -#scoreboard > div > div:nth-child(4) { - grid-column: 1 / -1; /* avg guesses — full width row */ -} - -/* Adjust grid columns for the card pairing */ -#scoreboard > div { - grid-template-columns: 1fr 1fr; - grid-template-areas: - "handle handle" - "header header" - "c1 c2" - "c3 c3" - "buttons buttons"; -} - -#scoreboard > div > div:nth-child(1) { - grid-area: header; -} -#scoreboard > div > div:nth-child(2) { - grid-area: c1; -} -#scoreboard > div > div:nth-child(3) { - grid-area: c2; -} -#scoreboard > div > div:nth-child(4) { - grid-area: c3; -} -#scoreboard > div > div:nth-child(5) { - grid-area: buttons; -} - -/* Gaps between cards via borders acting as gutters */ -#scoreboard > div > div:nth-child(2), -#scoreboard > div > div:nth-child(3), -#scoreboard > div > div:nth-child(4) { + gap: 6px; + padding: 16px !important; + background: #f5f7fa !important; + outline: 3px solid #ffffff; /* white gutter between cards */ + margin: 0 !important; border: none !important; - outline: 4px solid #ffffff; /* gutter colour */ + box-shadow: none !important; } -/* ── Stat text inside each card ─────────────────────────────── */ -/* First child = the label text, second child = the value span */ -#scoreboard > div > div:nth-child(n + 2):nth-child(-n + 4) > div:first-child { - font-size: 0.68rem; - font-weight: 700; +#scoreboard .sb-label { + font-size: 0.68rem !important; + font-weight: 700 !important; text-transform: uppercase; letter-spacing: 0.07em; - color: var(--text-muted, #6c757d); + color: #6c757d !important; + line-height: 1.3; + margin: 0 !important; + padding: 0 !important; } -/* The value spans (id=total_*, id=average_*) */ -#scoreboard [id^="total_"], -#scoreboard [id^="average_"] { - font-size: 2rem; - font-weight: 700; +#scoreboard .sb-value { + display: block !important; + font-size: 2rem !important; + font-weight: 700 !important; font-family: "Roboto Mono", monospace; - color: var(--accent-primary, #2c3e50); - /* Remove the badge pill look from before */ - background: none; - padding: 0; - border-radius: 0; - min-width: 0; - text-align: left; + color: #2c3e50 !important; line-height: 1; + margin: 0 !important; + padding: 0 !important; + background: none !important; + border: none !important; + text-align: left !important; + min-height: 2rem; /* prevents height jump before JS populates value */ } -/* ── Button row ─────────────────────────────────────────────── */ -#scoreboard > div > div:nth-child(5) { +/* ── Action buttons ──────────────────────────────────────────── */ +#scoreboard .sb-actions { + grid-column: 1 / -1; display: flex !important; flex-direction: row !important; - align-items: center !important; - justify-content: flex-start !important; - gap: 10px !important; - padding: 12px 16px 28px !important; - border-top: 1px solid var(--border-subtle, #e9ecef) !important; + gap: 10px; + padding: 14px 16px 28px !important; + background: #ffffff !important; + border-top: 1px solid #e9ecef !important; border-bottom: none !important; - background: #ffffff; + margin: 0 !important; + box-shadow: none !important; } #scoreboard #play_again, #scoreboard #quit_game { - padding: 13px 0; - font-size: 1rem; - font-weight: 600; - border: none; + padding: 13px 0 !important; + font-size: 1rem !important; + font-weight: 600 !important; + border: none !important; border-radius: 8px; cursor: pointer; transition: opacity 0.15s, transform 0.1s; + margin: 0 !important; + box-shadow: none !important; } #scoreboard #play_again { flex: 1; - background: var(--bg-header, #2c3e50); - color: #ffffff; + background: #2c3e50 !important; + color: #ffffff !important; } #scoreboard #quit_game { width: 90px; - background: var(--bg-hover, #e9ecef); - color: var(--text-main, #212529); + background: #e9ecef !important; + color: #212529 !important; } -#scoreboard #play_again:hover { - opacity: 0.85; -} +#scoreboard #play_again:hover, #scoreboard #quit_game:hover { - opacity: 0.75; + opacity: 0.85; + transform: translateY(-1px); } -/* ── Desktop: centred modal ─────────────────────────────────── */ +/* ── Desktop: centred modal ──────────────────────────────────── */ @media (min-width: 601px) { #scoreboard { - align-items: center; + align-items: center !important; } #scoreboard > div { - border-radius: 16px; - max-width: 420px; + border-radius: 16px !important; + max-width: 440px !important; animation: sb-pop 0.25s cubic-bezier(0.34, 1.1, 0.64, 1) both; } - @keyframes sb-pop { - from { - transform: scale(0.92); - opacity: 0; - } - to { - transform: scale(1); - opacity: 1; - } - } - - #scoreboard > div > div:nth-child(5) { + #scoreboard .sb-actions { padding-bottom: 20px !important; } } -/* ── Mobile overrides ───────────────────────────────────────── */ +@keyframes sb-pop { + from { + transform: scale(0.92); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } +} + +/* ── Mobile ──────────────────────────────────────────────────── */ @media (max-width: 600px) { .form_container { padding: 1rem; margin: 0.5rem; } - #game_container { - top: 0; - left: 0; - position: fixed; - z-index: 1000; - } - #site-header, footer, #guesses, #guess_letter_container { - display: none; - position: absolute; - z-index: -9999; + display: none !important; } } diff --git a/html/word-guesser/index.html b/html/word-guesser/index.html index 12909b8..b2ed42f 100644 --- a/html/word-guesser/index.html +++ b/html/word-guesser/index.html @@ -66,23 +66,27 @@
-
-
Total words completed
-
+
+
Total words attempted
+
-
-
Total incorrect guesses
-
+
+
Total words completed
+
-
-
Average guesses per word
-
+
+
Total incorrect guesses
+
-
-
Average time per word
-
+
+
Average guesses per word
+
-
+
+
Average time per word
+
+
+
diff --git a/html/word-guesser/scripts/script.js b/html/word-guesser/scripts/script.js index 3283321..63bb171 100644 --- a/html/word-guesser/scripts/script.js +++ b/html/word-guesser/scripts/script.js @@ -26,6 +26,7 @@ class DuplicateBadGuessError extends Error {} class BadGuessError extends Error {} class WordGuesser { + static _scores = []; // -- Constants actualWord = []; @@ -114,6 +115,7 @@ return new Set(this.actualWord).size; } getMaxGesses() { + return 1; return this.getUniqueCharCount() * 3; } getTotalGuesses() { @@ -126,11 +128,12 @@ const end = this.endTime || Date.now(); return (end - this.startTime) / 1000; } - getStats() { + _getScores() { return { incorrect: this.badGuesses.length, total: this.getTotalGuesses(), time: this.getDuration(), + solved: this.wasSolved, }; } guessCount() { @@ -156,6 +159,7 @@ this.wasSolved = solved; // Store result status return true; } + WordGuesser._scores.push(this._getScores()); } validateInput(input) { const regex = /^[a-zA-Z ]$/; @@ -166,6 +170,49 @@ ); } } + static resetScores() { + WordGuesser._scores = []; + } + static getTotalGamesPlayed() { + return WordGuesser._scores.length; + } + static getScores() { + const scores = WordGuesser.calculateScores(); + return { + totalWordsAttempted: scores.attempts, + totalWordsCompleted: scores.solvedCount, + totalIncorrectGuesses: scores.incorrect, + avgGuessesPerWord: scores.avgGuesses.toFixed(2), + avgTimePerWord: scores.avgTime.toFixed(2), + }; + } + static calculateScores() { + let totals = { + incorrect: 0, + guesses: 0, + time: 0, + solvedCount: 0, + }; + + for (let i = 0; i < WordGuesser._scores.length; i++) { + const scores = WordGuesser._scores[i]; + totals.incorrect += scores.incorrect; + totals.guesses += scores.total; + totals.time += scores.time; + + if (scores.solved) { + totals.solvedCount++; + } + } + const totalGamesPlayed = WordGuesser.getTotalGamesPlayed(); + return { + attempts: totalGamesPlayed, + solvedCount: totals.solvedCount, + incorrect: totals.incorrect, + avgGuesses: totalGamesPlayed ? totals.guesses / totalGamesPlayed : 0, + avgTime: totalGamesPlayed ? totals.time / totalGamesPlayed : 0, + }; + } } class GameFields { constructor(fieldNames = {}) { @@ -194,6 +241,7 @@ // -- Scoreboard scoreboard: "scoreboard", + totalWordsAttempted: "total_words_attempted", totalWordsCompleted: "total_words_completed", totalIncorrectGuesses: "total_incorrect_guesses", avgGuessesPerWord: "average_guesses_per_word", @@ -221,12 +269,9 @@ fields.gameHowTo.style.display = "block"; } class Game { - static history = []; - constructor(wordChoices, fields) { Object.assign(this, fields); this.wordChoices = wordChoices; - console.log("test"); this.userName.addEventListener("focus", (event) => { if (event.target.value == "Guest") { @@ -240,7 +285,6 @@ }); this.userInfoForm.onsubmit = (event) => { event.preventDefault(); - console.log("Game ready"); this.newGame(); }; this.playAgainButton.onclick = (event) => this.newGame(); @@ -255,18 +299,24 @@ } }; } - resetHistory() { - Game.history = []; - } async init() { this.dialogs = await import("./dialogs.js"); } showScoreboard() { + this.updateScoreboard(); this.scoreboard.style.display = "flex"; } updateGuessButton() { this.guessButton.value = this.randomMessage(this.dialogs.guessButton); } + updateScoreboard() { + const scores = WordGuesser.getScores(); + this.totalWordsAttempted.innerText = scores.totalWordsAttempted; + this.totalWordsCompleted.innerText = scores.totalWordsCompleted; + this.totalIncorrectGuesses.innerText = scores.totalIncorrectGuesses; + this.avgGuessesPerWord.innerText = scores.avgGuessesPerWord; + this.avgTimePerWord.innerText = scores.avgTimePerWord; + } renderAlphabet() { const container = document.getElementById("alphabet_container"); this.alphabetContainer.innerHTML = ""; // Clear for new game @@ -299,10 +349,10 @@ reset(this); } handleQuit() { - Game.resetHistory(); this.userInfoForm.style.display = "block"; this.gameForm.style.display = "none"; this.scoreboard.style.display = "none"; + WordGuesser.resetScores(); this.reset(); } newGame() { @@ -352,8 +402,6 @@ this.updateNotifications("✅", message); } gameOver() { - Game.history.push(this.game); - this.updateScoreboard(); this.guessButton.value = this.randomMessage( this.dialogs.guessButtonDefaultValue, ); @@ -361,42 +409,12 @@ this.updateNotifications("🏆", message); this.showScoreboard(); } - updateScoreboard() { - const stats = this.calculateStats(); - this.totalWordsCompleted.innerText = Game.history.length; - this.totalIncorrectGuesses.innerText = stats.incorrect; - this.avgGuessesPerWord.innerText = stats.avgGuesses.toFixed(2); - this.avgTimePerWord.innerText = stats.avgTime.toFixed(2); - } - calculateStats() { - let totals = { incorrect: 0, guesses: 0, time: 0, solvedCount: 0 }; - - for (let i = 0; i < Game.history.length; i++) { - const game = Game.history[i]; - const stats = game.getStats(); - totals.incorrect += stats.incorrect; - totals.guesses += stats.total; - totals.time += stats.time; - - if (game.wasSolved) { - totals.solvedCount++; - } - } - - return { - solvedCount: totals.solvedCount, - incorrect: totals.incorrect, - avgGuesses: Game.history.length - ? totals.guesses / Game.history.length - : 0, - avgTime: Game.history.length ? totals.time / Game.history.length : 0, - }; - } changeGameIntro() { let messages = []; - if (Game.history.length == 0) { + const totalGamesPlayed = WordGuesser.getTotalGamesPlayed(); + if (totalGamesPlayed == 0) { messages = this.dialogs.gameIntroInitial; - } else if (Game.history.length >= 1) { + } else if (totalGamesPlayed >= 1) { messages = this.dialogs.gameIntro; } const message = this.randomMessage(messages);