HTML与JavaScript单词记忆游戏BUG原因排查及修复方法咨询
Word Memory Game: Fixing Life Deduction That Relies on Unseen Next Word
The Problem
I'm building a word memory game with HTML and JavaScript. The rules are simple: a word (either new or previously shown) appears on screen, and players click "Seen" or "New" to indicate if they've encountered it before. Wrong answers cost a life.
Right now, the game is unplayable because the life deduction logic checks against the next word generated after clicking the button—not the word the player actually just judged. Players can't possibly know the next word in advance!
Here's my current code:
JavaScript
var word_bank = ["test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test14", "test15"]; var old_words = []; var dec = word_bank; var lives = 3; function updateLives() { document.getElementById("lives").innerHTML = "Lives: " + lives; } function thing(v) { var rndn = Math.floor(Math.random() * (1 - 0 + 1)) + 0; if (rndn == 1) { var dec = word_bank } else { var dec = old_words } var word = dec[Math.floor(Math.random() * dec.length)]; document.getElementById("word").textContent = word; if (v == 1) { if (old_words.includes(word)) { } else { --lives updateLives(); } } else { if (old_words.includes(word)) { --lives updateLives(); } } old_words.push(word); var forDeletion = [word]; word_bank = word_bank.filter(item => !forDeletion.includes(item)) }; var word = dec[Math.floor(Math.random() * dec.length)]; document.getElementById("word").textContent = word; updateLives(); old_words.push(word); var forDeletion = [word]; word_bank = word_bank.filter(item => !forDeletion.includes(item))
HTML
<span id="lives"></span> <div id="center"> <span id="word"></span> </div> <div> <div> <button name="submit" class="action_btn_left seen" type="submit" value="seen" onclick="thing(1)">Seen</button> <button name="submit" class="action_btn_right new" type="submit" value="new" onclick="thing(0)">New</button> </div> </div>
Why This Is Happening
Let's break down the key issues:
- Backwards Logic Flow: Your
thing()function first generates a new word and updates the screen, then checks if the player's choice matches this new word. But the player clicked the button based on the previous word that was on screen—you're judging their choice against a word they haven't even seen yet! - Variable Scope Bug: Inside
thing(), you're usingvar decwhich re-declares the variable locally, overriding the globaldecyou set initially. This breaks your intended word source selection. - Syntax Error: Lines like
--lives updateLives();are missing a semicolon between the life deduction and function call, which can cause unexpected behavior. - No Reference to Current Word: You don't store the currently displayed word in a persistent variable, so when the player clicks a button, you have no way to check their choice against the word they actually saw.
Fixed Code & Explanation
Here's the corrected version, with comments explaining the changes:
Fixed JavaScript
var word_bank = ["test1", "test2", "test3", "test4", "test5", "test6", "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test14", "test15"]; var old_words = []; var lives = 3; var currentWord = ""; // New: Store the word currently displayed on screen function updateLives() { document.getElementById("lives").innerHTML = "Lives: " + lives; } // Helper function to generate the next random word (either new or old) function getNextWord() { // 50% chance to pick a new word or an old one const useNewWord = Math.random() > 0.5; let wordSource = useNewWord ? word_bank : old_words; // If word source is empty (e.g., no new words left), fall back to the other source if (wordSource.length === 0) { wordSource = useNewWord ? old_words : word_bank; } return wordSource[Math.floor(Math.random() * wordSource.length)]; } // Initialize the first word function initGame() { currentWord = getNextWord(); document.getElementById("word").textContent = currentWord; // Move initial word to old_words and remove from word_bank old_words.push(currentWord); word_bank = word_bank.filter(item => item !== currentWord); updateLives(); } function handlePlayerChoice(isSeen) { // First: Check if the player's choice is correct against the CURRENT word if (isSeen) { // Player said "Seen" - if it's NOT in old_words (before we add it now), they were wrong if (!old_words.includes(currentWord)) { lives--; updateLives(); } } else { // Player said "New" - if it IS in old_words, they were wrong if (old_words.includes(currentWord)) { lives--; updateLives(); } } // Second: Generate and display the next word currentWord = getNextWord(); document.getElementById("word").textContent = currentWord; // Third: Update word banks (move current word to old_words, remove from word_bank if needed) old_words.push(currentWord); word_bank = word_bank.filter(item => item !== currentWord); } // Start the game when it loads initGame();
Fixed HTML
<span id="lives"></span> <div id="center"> <span id="word"></span> </div> <div> <div> <!-- Updated onclick to use the new function with clear intent --> <button name="submit" class="action_btn_left seen" type="button" onclick="handlePlayerChoice(true)">Seen</button> <button name="submit" class="action_btn_right new" type="button" onclick="handlePlayerChoice(false)">New</button> </div> </div>
Key improvements:
- Separated Logic: Split into helper functions (
getNextWord,initGame,handlePlayerChoice) for better readability and maintainability. - Current Word Tracking: The
currentWordvariable keeps track of what's on screen, so we always judge the player's choice against the word they actually interacted with. - Fixed Flow: First check the player's choice against the current word, then generate the next one.
- Removed Scope Bugs: No more local variable overriding global ones.
- Fallback for Empty Word Banks: If all new words are used up, the game will keep using old words, and vice versa.
- Clearer Function Names:
handlePlayerChoiceis much more descriptive thanthing().
内容的提问来源于stack exchange,提问作者ShaunY




