diff --git a/html/word-guesser/css/styles.css b/html/word-guesser/css/styles.css index 6da9243..3833171 100644 --- a/html/word-guesser/css/styles.css +++ b/html/word-guesser/css/styles.css @@ -1,7 +1,11 @@ -/* Game Container Styling */ +/* ============================================================ + WORD GUESSING GAME — STYLESHEET + ============================================================ */ + +/* ── Game Container ────────────────────────────────────────── */ .form_container { background-color: #ffffff; - border: 1px solid #dee2e6; + border: 1px solid var(--border-medium); border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05); max-width: 500px; @@ -21,22 +25,37 @@ padding-bottom: 0.2rem; } -.game-instructions { - text-align: center; - margin: 1.5rem 0; - font-size: 0.95rem; - color: #6c757d; -} #game_intro { font-size: 0.85rem; opacity: 0.7; } -/* Word Board (Wheel of Fortune Style) */ +/* ── Notifications — fixed height, no layout shift ──────────── */ +#notifications { + min-height: 1.5em; + line-height: 1.5em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + font-weight: 600; + font-size: 0.9rem; + font-style: italic; + color: var(--status-error, #d33333); + margin: 0; + padding: 0; +} + +.success-msg { + color: var(--status-success, #28a745); +} +.error-msg { + color: var(--status-error, #d33333); +} + +/* ── Word Board ─────────────────────────────────────────────── */ #current_word { display: flex; - flex-direction: row !important; - display: flex; flex-wrap: wrap; justify-content: center; align-items: center; @@ -47,36 +66,33 @@ font-weight: bold; letter-spacing: 5px; font-size: 1.5rem; - list-style: none; - padding: 10px 0; } #current_word li { background-color: var(--bg-body); border: 2px solid var(--accent-primary); border-radius: 4px; + border-bottom: 3px solid var(--border-medium); display: flex; align-items: center; justify-content: center; color: var(--accent-primary); - box-shadow: 2px 2px 0px rgba(44, 62, 80, 0.2); + box-shadow: 2px 2px 0 rgba(44, 62, 80, 0.2); text-transform: uppercase; - width: 32px; height: 42px; - display: flex; - border-bottom: 3px solid var(--border-medium); font-weight: bold; font-size: 1.4rem; } + .word-display-field { - display: block !important; /* Break out of the 2-column grid */ + display: block !important; text-align: center; padding: 2rem 0; border-bottom: 2px solid #f1f3f5; } -/* Form Layout */ +/* ── Form Layout ────────────────────────────────────────────── */ .formField { display: grid; grid-template-columns: 120px 1fr; @@ -96,14 +112,14 @@ font-size: 0.9rem; } -/* Inputs & Buttons */ +/* ── Inputs & Buttons ───────────────────────────────────────── */ #guess_letter { width: 50px; padding: 10px; text-align: center; font-size: 1.2rem; font-weight: bold; - border: 2px solid #dee2e6; + border: 2px solid var(--border-medium); border-radius: 4px; transition: border-color 0.2s; } @@ -148,121 +164,35 @@ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } -/* Guess History Pills */ +/* ── Guess History Pills ────────────────────────────────────── */ #guesses { display: flex; - flex-wrap: nowrap; /* Keep them on one line */ - overflow-x: auto; /* Scroll if there are too many */ + flex-wrap: nowrap; + overflow-x: auto; gap: 5px; padding: 5px 0; margin: 0; list-style: none; - scrollbar-width: none; /* Hide scrollbar for clean UI */ + scrollbar-width: none; } #guesses::-webkit-scrollbar { - display: none; /* Hide scrollbar for Chrome/Safari */ + display: none; } #guesses li { -} -#guesses li { - background: var(--accent-secondary, #e9ecef); - color: #1976d2; + background: var(--bg-tag, #e3f2fd); + color: var(--accent-tag, #1976d2); padding: 2px 8px; - border-radius: 20px; + border-radius: 3px; font-size: 0.85rem; font-family: "Roboto Mono", monospace; - /* font-family: "Courier New", Courier, monospace; */ font-weight: bold; flex-shrink: 0; - border: 1px solid #bbdefb; - border-radius: 3px; + border: 1px solid var(--border-tag, #bbdefb); } -/* Notifications */ -#notifications { - text-align: center; - font-weight: 600; - margin-bottom: 1rem; - min-height: 1.2em; - color: #d9534f; - font-style: italic; - text-align: center; -} - -.success-msg { - color: #2e7d32; -} -.error-msg { - color: #c62828; -} - -/* Mobile Optimizations */ -@media (max-width: 600px) { - .form_container { - padding: 1rem; - margin: 0.5rem; - } - #game_container { - top: 0px; - left: 0px; - position: fixed; - z-index: 1000; - } - #site-header, - footer, - #guesses, - #guess_letter_container { - display: none; - position: absolute; - z-index: -9999; - } - - /* /1* Shrink the tiles so long words don't wrap awkwardly *1/ */ - /* #current_word { */ - /* gap: 4px; */ - /* padding: 0.5rem 0; */ - /* } */ - - /* #current_word li { */ - /* width: 30px; /1* Reduced from 45px *1/ */ - /* height: 40px; /1* Reduced from 60px *1/ */ - /* font-size: 1.2rem; /1* Reduced from 2rem *1/ */ - /* border-width: 1px; */ - /* } */ - - /* /1* Stack the form fields vertically instead of 2-columns *1/ */ - /* .formField { */ - /* grid-template-columns: 1fr; */ - /* gap: 5px; */ - /* text-align: center; */ - /* } */ - - /* /1* Make the Alphabet Grid look like a keypad *1/ */ - /* .alphabet-grid { */ - /* display: grid; */ - /* grid-template-columns: repeat(auto-fill, minmax(35px, 1fr)); */ - /* gap: 5px; */ - /* margin-top: 1.5rem; */ - /* } */ - - /* .letter-btn { */ - /* padding: 10px 0; */ - /* font-family: "Roboto Mono", monospace; */ - /* font-weight: bold; */ - /* background: var(--bg-tag); */ - /* border: 1px solid var(--border-medium); */ - /* border-radius: 4px; */ - /* cursor: pointer; */ - /* } */ - - /* .letter-btn:disabled { */ - /* opacity: 0.4; */ - /* cursor: not-allowed; */ - /* } */ -} - +/* ── Alphabet Grid ──────────────────────────────────────────── */ .alphabet-grid { display: grid; grid-template-columns: repeat(9, 1fr); @@ -284,6 +214,7 @@ transition: transform 0.1s, background 0.1s; + cursor: pointer; } .letter-btn:active { @@ -292,75 +223,63 @@ background: #dee2e6; } +.letter-btn.selected { + background: var(--bg-header); + color: #fff; + border-color: var(--bg-header); + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25); +} + .letter-btn:disabled { background: #e9ecef; color: #adb5bd; box-shadow: none; border-color: transparent; + cursor: not-allowed; } -.game-footer { - display: flex; - justify-content: space-between; - align-items: center; - padding: 10px; - border-top: 1px solid #eee; - font-size: 0.9rem; -} - -#notifications { - min-height: 1.2em; - color: #d9534f; - font-style: italic; - text-align: center; -} - +/* ── Game Metrics ───────────────────────────────────────────── */ #game_metrics { display: flex; justify-content: space-between; align-items: flex-start; gap: 15px; padding: 10px; - background: var( - --bg-secondary, - #f8f9fa - ); /* Light background to define the area */ + background: var(--bg-subtle, #f5f7fa); border-radius: 8px; margin: 10px 0; } -/* Individual Metric Groups */ .formField.metric_group, #game_metrics .formField { flex: 1; display: flex; flex-direction: column; gap: 4px; - min-width: 0; /* Critical for preventing flex items from overflowing */ + min-width: 0; } -/* Labels */ #game_metrics .label { font-size: 0.75rem; font-weight: bold; text-transform: uppercase; - color: var(--text-muted, #6c757d); + color: var(--text-muted); letter-spacing: 0.05em; } -/* Attempts Input Styling */ -#guess_count { +#game_metrics #guess_count { width: 100%; padding: 8px; - border: 1px solid var(--border-light, #dee2e6); + border: 1px solid var(--border-light); border-radius: 4px; background: #fff; font-family: "Roboto Mono", monospace; font-size: 1.1rem; text-align: center; - color: var(--text-primary, #212529); + color: var(--text-main); } +/* ── Game Container ─────────────────────────────────────────── */ #game_container { max-width: 500px; margin: 2rem auto; @@ -371,9 +290,9 @@ overflow: hidden; } -/* Splash Screen (Login) specific styling */ +/* ── Splash / Login ─────────────────────────────────────────── */ #user_info_container { - display: flex; /* Show by default */ + display: flex; } #splash_screen { @@ -382,55 +301,328 @@ padding: 0; } -/* Hide the game form properly via CSS instead of inline styles */ #game_form { - display: none; /* Changed from visibility:hidden to display:none */ + display: none; } -/* Scoreboard Overlay */ -#scoreboard_overlay { - display: none; /* Toggle to 'flex' via JS */ - position: fixed; - inset: 0; /* Shorthand for top/bottom/left/right: 0 */ - background: rgba(15, 23, 42, 0.9); /* Darker slate backdrop */ - backdrop-filter: blur(8px); - z-index: 9999; - justify-content: center; - align-items: center; - color: #f8fafc; -} - -#scoreboard_overlay > div { - /* The wrapper inside the overlay */ - background: #1e293b; - border: 2px solid #38bdf8; - border-radius: 16px; - padding: 2rem; - width: 90%; - max-width: 400px; - display: grid; - grid-template-columns: 1fr; - gap: 1rem; - box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); -} - -/* Individual Stat Rows */ -#scoreboard_overlay > div > div { +/* ── Game Footer ────────────────────────────────────────────── */ +.game-footer { display: flex; justify-content: space-between; align-items: center; - padding-bottom: 0.5rem; - border-bottom: 1px solid #334155; + padding: 10px; + border-top: 1px solid #eee; + font-size: 0.9rem; } -#scoreboard_overlay > div > div:last-child { - border-bottom: none; +/* ============================================================ + SCOREBOARD OVERLAY + JS toggles display: none <-> flex — that is preserved. + Layout & visual design is a complete rewrite. + ============================================================ */ +#scoreboard { + display: none; /* JS switches this to 'flex' */ + position: fixed; + inset: 0; + z-index: 9999; + 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); } -#scoreboard_overlay [id^="total_"], -#scoreboard_overlay [id^="average_"] { - font-family: "Roboto Mono", monospace; - font-weight: bold; - color: #38bdf8; +/* ── Sheet card ─────────────────────────────────────────────── */ +#scoreboard > div { + background: #ffffff; + border-radius: 20px 20px 0 0; + width: 100%; + max-width: 500px; + 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; +} + +@keyframes sb-rise { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +/* Drag handle strip */ +#scoreboard > div::before { + content: ""; + 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; +} + +/* ── Dark header band ───────────────────────────────────────── */ +#scoreboard > div > div:first-child { + /* Override shared row rules completely */ + 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) { + border: none !important; + outline: 4px solid #ffffff; /* gutter colour */ +} + +/* ── 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; + text-transform: uppercase; + letter-spacing: 0.07em; + color: var(--text-muted, #6c757d); +} + +/* The value spans (id=total_*, id=average_*) */ +#scoreboard [id^="total_"], +#scoreboard [id^="average_"] { + font-size: 2rem; + font-weight: 700; + 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; + line-height: 1; +} + +/* ── Button row ─────────────────────────────────────────────── */ +#scoreboard > div > div:nth-child(5) { + 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; + border-bottom: none !important; + background: #ffffff; +} + +#scoreboard #play_again, +#scoreboard #quit_game { + padding: 13px 0; + font-size: 1rem; + font-weight: 600; + border: none; + border-radius: 8px; + cursor: pointer; + transition: + opacity 0.15s, + transform 0.1s; +} + +#scoreboard #play_again { + flex: 1; + background: var(--bg-header, #2c3e50); + color: #ffffff; +} + +#scoreboard #quit_game { + width: 90px; + background: var(--bg-hover, #e9ecef); + color: var(--text-main, #212529); +} + +#scoreboard #play_again:hover { + opacity: 0.85; +} +#scoreboard #quit_game:hover { + opacity: 0.75; +} + +/* ── Desktop: centred modal ─────────────────────────────────── */ +@media (min-width: 601px) { + #scoreboard { + align-items: center; + } + + #scoreboard > div { + border-radius: 16px; + max-width: 420px; + 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) { + padding-bottom: 20px !important; + } +} + +/* ── Mobile overrides ───────────────────────────────────────── */ +@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; + } } diff --git a/html/word-guesser/index.html b/html/word-guesser/index.html index 755af7b..12909b8 100644 --- a/html/word-guesser/index.html +++ b/html/word-guesser/index.html @@ -10,7 +10,7 @@
- +
@@ -20,7 +20,7 @@

Please enter a single alphabetical character (A-Z) into the input - box belowand and click "Guess" to see if the letter + box below and and click "Guess" to see if the letter exists in the hidden word.

@@ -42,6 +42,7 @@ value="" required placeholder="?" + autocomplete="off" />
@@ -64,7 +65,7 @@
-
+
Total words completed
@@ -81,5 +82,9 @@
Average time per word
+
+ + +
diff --git a/html/word-guesser/scripts/script.js b/html/word-guesser/scripts/script.js index 3cf715d..3283321 100644 --- a/html/word-guesser/scripts/script.js +++ b/html/word-guesser/scripts/script.js @@ -35,6 +35,9 @@ lettersLeft = []; currentWord = []; + startTime = null; + endTime = null; + constructor(wordChoices) { this.wordChoices = wordChoices; this.newGame(); @@ -52,6 +55,7 @@ for (let i = 0; i < this.actualWord.length; i++) { this.currentWord[i] = "_"; } + this.startTime = Date.now(); } // -- Determines if a letter is in a list of letters @@ -106,20 +110,55 @@ } this.currentWord = currentWord; } + getUniqueCharCount() { + return new Set(this.actualWord).size; + } + getMaxGesses() { + return this.getUniqueCharCount() * 3; + } + getTotalGuesses() { + return this.badGuesses.length + this.goodGuesses.length; + } getGuesses() { return this.badGuesses; } + getDuration() { + const end = this.endTime || Date.now(); + return (end - this.startTime) / 1000; + } + getStats() { + return { + incorrect: this.badGuesses.length, + total: this.getTotalGuesses(), + time: this.getDuration(), + }; + } guessCount() { return this.badGuesses.length + this.goodGuesses.length; } - gameOver() { + checkWordCompletion() { for (let i = 0; i < this.actualWord.length; i++) { if (this.currentWord[i] != this.actualWord[i]) return false; } return true; } + gameOver() { + // -- Check if game end has already been declared + if (this.endTime != null) { + return true; + } + + const solved = this.checkWordCompletion(); + const failed = this.getTotalGuesses() >= this.getMaxGesses(); + + if (solved || failed) { + this.endTime = Date.now(); + this.wasSolved = solved; // Store result status + return true; + } + } validateInput(input) { - const regex = /^[a-zA-Z]$/; + const regex = /^[a-zA-Z ]$/; const result = regex.test(input); if (!result) { throw new InvalidGuessError( @@ -146,7 +185,10 @@ currentWord: "current_word", notifications: "notifications", - // Game sprites + playAgainButton: "play_again", + quitButton: "quit_game", + + // Game dialogs gameIntro: "game_intro", gameHowTo: "game-howto", @@ -176,21 +218,15 @@ // fields.guessLetter.value = ""; fields.guesses.replaceChildren(); fields.currentWord.replaceChildren(); - if (fields.gameHowTo) { - fields.gameHowTo.style.display = "block"; - } -} -class Scoreboard { - gamesPlayed = 0; + fields.gameHowTo.style.display = "block"; } class Game { - static scoreboard = new Scoreboard(); - static gamesPlayed = 0; + static history = []; constructor(wordChoices, fields) { Object.assign(this, fields); this.wordChoices = wordChoices; - this.newGame(); + console.log("test"); this.userName.addEventListener("focus", (event) => { if (event.target.value == "Guest") { @@ -202,37 +238,31 @@ this.userName.value = "Guest"; } }); - const userInfoHandler = (event) => { + this.userInfoForm.onsubmit = (event) => { event.preventDefault(); - this.userInfoForm.style.display = "none"; - this.gameForm.style.display = "block"; console.log("Game ready"); + this.newGame(); }; - this.userInfoForm.onsubmit = userInfoHandler; - - // Use onclick to prevent stacking event listeners across multiple test initializations - const eventHandler = (event) => { + this.playAgainButton.onclick = (event) => this.newGame(); + this.quitButton.onclick = (event) => this.handleQuit(); + this.gameForm.onsubmit = (event) => { event.preventDefault(); - if (this.game.gameOver()) { - // reset(this); - // this.gameIntro.innerText = - // "The game that insults you, whether you win or lose!"; - // this.guessButton.value = "Guess"; - // this.game = new WordGuesser(this.wordChoices); - this.newGame(); - } else { + if (!this.game.gameOver()) { this.updateGuessButton(); this.handleGuessedLetter(event); + } else { + this.newGame(); } }; - this.gameForm.onsubmit = eventHandler; + } + resetHistory() { + Game.history = []; } async init() { this.dialogs = await import("./dialogs.js"); } showScoreboard() { - const overlay = document.getElementById("scoreboard_overlay"); - overlay.style.display = "flex"; + this.scoreboard.style.display = "flex"; } updateGuessButton() { this.guessButton.value = this.randomMessage(this.dialogs.guessButton); @@ -259,11 +289,8 @@ this.guessLetter.value = char; this.selectedButton = btn; btn.classList.add("selected"); - // this.handleGuessedLetter(event); this.guessLetter; - // this.updateGuessButton(); - // btn.disabled = true; }; container.appendChild(btn); }); @@ -271,10 +298,20 @@ reset() { reset(this); } + handleQuit() { + Game.resetHistory(); + this.userInfoForm.style.display = "block"; + this.gameForm.style.display = "none"; + this.scoreboard.style.display = "none"; + this.reset(); + } newGame() { this.reset(); this.game = new WordGuesser(this.wordChoices); this.renderAlphabet(); + this.userInfoForm.style.display = "none"; + this.gameForm.style.display = "block"; + this.scoreboard.style.display = "none"; } // -- Getters getGuess() { @@ -315,18 +352,51 @@ this.updateNotifications("✅", message); } gameOver() { + Game.history.push(this.game); + this.updateScoreboard(); this.guessButton.value = this.randomMessage( this.dialogs.guessButtonDefaultValue, ); const message = this.randomMessage(this.dialogs.gameOver); this.updateNotifications("🏆", message); - Game.gamesPlayed++; + 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.gamesPlayed == 0) { + if (Game.history.length == 0) { messages = this.dialogs.gameIntroInitial; - } else if (Game.gamesPlayed >= 1) { + } else if (Game.history.length >= 1) { messages = this.dialogs.gameIntro; } const message = this.randomMessage(messages); @@ -352,9 +422,7 @@ if (game.guessCount() == 0) { this.changeGameIntro(); - if (this.gameHowTo) { - this.gameHowTo.style.display = "none"; - } + this.gameHowTo.style.display = "none"; } try { @@ -366,7 +434,6 @@ this.selectedButton.disabled = true; this.selectedButton.classList.remove("selected"); } - this.selectedButton.btn.disabled = true; } catch (e) { if (e instanceof BadGuessError) { this.badGuessError();