diff --git a/html/word-guesser/index.html b/html/word-guesser/index.html index b2ed42f..3154f1f 100644 --- a/html/word-guesser/index.html +++ b/html/word-guesser/index.html @@ -10,6 +10,10 @@
+ + +
+
@@ -66,29 +70,50 @@
-
-
Total words attempted
-
+
+

Current Game Results

+
+
Result
+
+
+
+
Incorrect Guesses
+
+
+
+
Time Spent (s)
+
+
-
-
Total words completed
-
-
-
-
Total incorrect guesses
-
-
-
-
Average guesses per word
-
-
-
-
Average time per word
-
-
-
- - + +
+ +
+

Overall Performance

+
+
Total words attempted
+
+
+
+
Total words completed
+
+
+
+
Total incorrect guesses
+
+
+
+
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 863d2e8..e399c52 100644 --- a/html/word-guesser/scripts/script.js +++ b/html/word-guesser/scripts/script.js @@ -161,7 +161,7 @@ } const solved = this.checkWordCompletion(); - const failed = this.getTotalGuesses() >= this.getMaxGesses(); + const failed = this.getTotalGuesses() >= this.getMaxGuesses(); if (solved || failed) { this.endTime = Date.now(); @@ -240,6 +240,7 @@ guessButton: "guess_button", currentWord: "current_word", notifications: "notifications", + wordlistFile: "wordlist_file", playAgainButton: "play_again", quitButton: "quit_game", @@ -255,6 +256,9 @@ totalIncorrectGuesses: "total_incorrect_guesses", avgGuessesPerWord: "average_guesses_per_word", avgTimePerWord: "average_time_per_word", + currentGameResult: "current_game_result", + currentGameIncorrect: "current_game_incorrect", + currentGameTime: "current_game_time", }; // Merge provided names with defaults @@ -280,7 +284,8 @@ class Game { constructor(wordChoices, fields) { Object.assign(this, fields); - this.wordChoices = wordChoices; + this.defaultWordChoices = wordChoices; + this.activeWordChoices = wordChoices; this.userName.addEventListener("focus", (event) => { if (event.target.value == "Guest") { @@ -292,9 +297,15 @@ this.userName.value = "Guest"; } }); - this.userInfoForm.onsubmit = (event) => { + this.userInfoForm.onsubmit = async (event) => { event.preventDefault(); - this.newGame(); + const file = this.wordlistFile.files[0]; + if (file) { + this.startGameFromFile(file); + } else { + this.activeWordChoices = this.defaultWordChoices; + this.newGame(); + } }; this.playAgainButton.onclick = (event) => this.newGame(); this.quitButton.onclick = (event) => this.handleQuit(); @@ -308,23 +319,57 @@ } }; } + startGameFromFile(file) { + try { + const reader = new FileReader(); + + reader.onload = (event) => { + try { + const words = processWordList(event.target.result); + validateWordList(words); + this.activeWordChoices = words; + this.updateNotifications("📁", "Custom word list loaded!"); + this.newGame(); + } catch (e) { + window.alert(e); + } + }; + + reader.onerror = () => { + window.alert(new Error("File reading failed.")); + }; + + return reader.readAsText(file); + } catch (e) { + this.updateNotifications("⚠️", e.message); + return; // Stop if the file is invalid + } + } async init() { this.dialogs = await import("./dialogs.js"); } showScoreboard() { - this.updateScoreboard(); + this.updateScoreboard(this.game); 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; + updateScoreboard(currentGame) { + // 1. Update Current Game Section + const currentStats = currentGame._getScores(); + this.currentGameResult.innerText = currentStats.solved ? "WON" : "LOST"; + this.currentGameResult.className = `sb-value ${currentStats.solved ? "success-msg" : "error-msg"}`; + this.currentGameIncorrect.innerText = currentStats.incorrect; + this.currentGameTime.innerText = currentStats.time.toFixed(2); + + // 2. Update Cumulative Section + const overallScores = WordGuesser.getScores(); + this.totalWordsAttempted.innerText = overallScores.totalWordsAttempted; + this.totalWordsCompleted.innerText = overallScores.totalWordsCompleted; + this.totalIncorrectGuesses.innerText = overallScores.totalIncorrectGuesses; + this.avgGuessesPerWord.innerText = overallScores.avgGuessesPerWord; + this.avgTimePerWord.innerText = overallScores.avgTimePerWord; } renderAlphabet() { const container = document.getElementById("alphabet_container"); @@ -366,8 +411,11 @@ } newGame() { this.reset(); - this.game = new WordGuesser(this.wordChoices); + this.game = new WordGuesser(this.activeWordChoices); this.renderAlphabet(); + this.updateCurrentWord(this.game.getCurrentWord()); + this.updateGuesses(this.game.getGuesses()); + this.updateGuessCount(this.game.guessCount()); this.userInfoForm.style.display = "none"; this.gameForm.style.display = "block"; this.scoreboard.style.display = "none"; @@ -496,6 +544,28 @@ return messages[randomChoice]; } } + +function processWordList(text) { + const lines = text.split(/\r?\n/); + const processedWords = []; + + for (let i = 0; i < lines.length; i++) { + const word = lines[i].trim(); + if (word.length >= 5) { + processedWords.push(word); + } + } + + return processedWords; +} + +function validateWordList(words) { + if (words.length < 25) { + throw new Error( + "File must contain at least 25 words/phrases of 5+ characters.", + ); + } +} document.addEventListener("DOMContentLoaded", async (_) => { const wordChoices = (await import("./wordlist.js")).default; const fields = new GameFields();