1
console.log("Start file 1 =========================================");
function Letter (letter) {

    this.letter = letter;
    this.guess = false;
    this.answer = function () {
        if (!this.guess) {
            return "_";
        }
        else if (this.guess === true) {
            return this.letter;
        }
    }
    this.letterTest = function (guessed) {
        if (guessed === this.letter) {
            this.guess = true;
            // this.letter = guessed;
        } else {
            this.letter = "_";
        }
    }
};

module.exports = Letter;
console.log("End file 1 =========================================");


console.log("Start file 2 =========================================");
var Letter = require("./letter.js");

function Word (word) { 

    this.splitWord = [];
    for (var i = 0; i < word.length; i++) { 
        var eachLetter = new Letter (word[i]);
        this.splitWord.push(eachLetter);
    }

    this.stringRep = function () {
        var testedWord = [];
        for (var i = 0; i < this.splitWord.length; i++) {
            testedWord.push(eachLetter.answer());
        }

        testedWord = testedWord.join(" ");

        // console.log(testedWord);
        return testedWord;

};

    this.eachGuess = function (input) {
        for (var i = 0; i < this.splitWord.length; i++) {

            this.splitWord[i].letterTest(input);
        }
        }    
}

module.exports = Word;
console.log("End file 2 =========================================");


console.log("Start file 3 =========================================");
var Word = require("./word.js");
var inquirer = require('inquirer');

var remainingGuesses = 10;
var mainGame;
var currentWord;
var liveWord = [];
completeWord = null;
let countryPicker;
let testedWord;

var europe = ["Albania", "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Denmark", "England", "France", "Greece", "Germany",
"Hungary", "Iceland", "Italy", "Lithuania", "Monaco", "Norway", "Poland", "Portugal", "Romania", "Serbia", "Slovakia", "Spain", "Sweden",
"Switzerland", "Ukraine"];

// Function that picks a random country
function pickCountry () {
    countryPicker = europe[Math.floor((Math.random() * europe.length) + 1)];
    var mainGame2 = new Word (countryPicker);
    mainGame = mainGame2;
    // Display word

    currentWord = mainGame.stringRep();
    currentWord = JSON.stringify(currentWord);
    console.log("Word: " + currentWord);
};

pickCountry();
// Delete this after
console.log("1: " + countryPicker);
console.log("2: " + currentWord);

inquirer.prompt([
    {
        type: "input",
        name: "game",
        message: "Guess a letter!"
    }
]).then(function(inquirerResponse) {
        liveWord = mainGame.splitWord;
        mainGame.eachGuess(inquirerResponse.game);

    for (let i = 0; i < liveWord.length; i++) {

        console.log(mainGame.splitWord[i].letter);

    }
});

I built a hangman game using constructor functions. I have set it up so when a random word is chosen, each letter will be displayed as an underscore.
I used the inquirer package to ask for a letter. When the first letter is guessed correctly it successfully replaces the the underscore with the letter in the liveWord array. The problem is, it only works for one letter. I need to make it work until the full word is guessed. FYI File 1 and 2 are only there for reference, my problem is only in file 3. No need to look at the first 2. Any tips?

4

2 回答 2

1

I'll not help You with code in Your question, it's annoying to debug, rewrite somebody's code (especially when it's long).

But I'll give You an example:

const words = [
  'Azerbaijan', 'America', 'blablabla', 'Argentina', 'lambada', 'Australia', 'schmetterling', 'krankenwagen', 'kugelschreiber'
];

let word, result, charIndexes;

const start = () => {
  word = words[parseInt(Math.random()*words.length)];
  charIndexes = {};
  result = new Array(word.length+1).join('_');

  word.split('').forEach((char, i) => {
    char = char.toLowerCase();
    if (!charIndexes[char]) charIndexes[char] = []
    charIndexes[char].push(i);
  });
  
  info.innerHTML = '';
  output.innerHTML = result;
  input.focus();
};

const checkChar = (char) => {
  result = result.split('');
  if (charIndexes[char]) {
    const indexes = charIndexes[char];
    indexes.forEach(i => {
      result[i] = word.charAt(i);
    });
    delete charIndexes[char];
  }
  result = result.join('');
  output.innerHTML = result;
  if (Object.keys(charIndexes).length === 0) {
    info.innerHTML = 'Congratulations!';
  }
};

const input = document.getElementById('letter');
const output = document.getElementById('word');
const info = document.getElementById('info');

input.onkeyup = (e) => {
  const char = e.key.toLowerCase();
  input.value = '';
  checkChar(char);
};

start();
<input type="text" id="letter" value=""> 
<button onclick="start()">reset</button>
<br/><br/>
<div id="word"></div>
<div id="info"></div>

于 2018-11-18T21:01:59.040 回答
1

There are several issues in your code:

  1. In the letterTest method you set the letter property to underscore when the guess is different from the letter. This is wrong, because then you'll never know again what the correct letter is. Remove this. It is enough to have the right value for the guess property

  2. In the stringRep method you refer to the variable eachLetter in the loop, which has nothing to do there. Instead you should use this.splitWord[i].

  3. There is no loop that allows the user to make a second guess, so it is only normal it only works once. There needs to be a loop that decreases the value of your variable remainingGuesses, which you didn't use so far.

  4. You should not display splitWord. This is related to point 1. Instead you should display stringRep() which takes into account whether or not the letter was already guessed based on the guessed property. And that is exactly what you need to output.

  5. Logic is missing that detects whether the word was found completely. In that case a message would be appropriate and the guessing cycle (which was not implemented) should be interrupted.

To facilitate the looping, I would suggest to use the async/await syntax for dealing with the promise returned by inquirer.

Here is your code with the above-listed points corrected. For the purpose of making it runnable in this snippet widget, I did not split it into modules as you did nor included inquirer (I put a simplified replacement for it inline).

I also did not attempt to make many other improvements, so that you could still recognise your own work. All changes are commented:

function Letter (letter) {
    this.letter = letter;
    this.guess = false;
    this.answer = function () {
        if (!this.guess) {
            return "_";
        }
        else { // No need to check whether this.guess is true here. It is the logical consequence...
            return this.letter;
        }
    }
    this.letterTest = function (guessed) {
        if (guessed === this.letter) {
            this.guess = true;
        }
        // Don't change this.letter, as you will forever forget what the correct letter is!
        // (code was deleted from here)
    }
}

function Word (word) { 
    this.splitWord = [];
    for (var i = 0; i < word.length; i++) { 
        var eachLetter = new Letter (word[i]);
        this.splitWord.push(eachLetter);
    }
    this.stringRep = function () {
        var testedWord = [];
        for (var i = 0; i < this.splitWord.length; i++) {
            // Don't push eachLetter, but use the i-variable as index! 
            testedWord.push(this.splitWord[i].answer());
        }
        testedWord = testedWord.join(" ");
        return testedWord;
    }

    this.eachGuess = function (input) {
        for (var i = 0; i < this.splitWord.length; i++) {
            this.splitWord[i].letterTest(input);
        }
    }    
}

// Simplified implementation of inquirer for this snippet only:
var inquirer = {
    prompt([{type, name, message}]) {
        return new Promise((resolve) => {
            const input = document.querySelector(`[name=${name}]`);
            input.value = "";
            input.placeholder = message;
            input.onchange = e => resolve({ [name]: input.value });
        });
    }
}

var remainingGuesses = 10;
var mainGame;
var currentWord;
var liveWord = [];
completeWord = null;
let countryPicker;
let testedWord;

var europe = ["Albania", "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Denmark", "England", "France", "Greece", "Germany",
"Hungary", "Iceland", "Italy", "Lithuania", "Monaco", "Norway", "Poland", "Portugal", "Romania", "Serbia", "Slovakia", "Spain", "Sweden",
"Switzerland", "Ukraine"];

function pickCountry () {
    countryPicker = europe[Math.floor((Math.random() * europe.length) + 1)];
    var mainGame2 = new Word (countryPicker);
    mainGame = mainGame2;
    currentWord = mainGame.stringRep();
    currentWord = JSON.stringify(currentWord);
    console.log("Word: " + currentWord);
}

pickCountry();
// Delete this after
console.log("1: " + countryPicker);
console.log("2: " + currentWord);

(async function () { // Use an async function to allow the use of AWAIT
    while (remainingGuesses--) { // You need a loop to repeat guess/response cycle
        // Use AWAIT -- simpler to use than THEN
        const inquirerResponse = await inquirer.prompt([{
            type: "input",
            name: "game",
            message: "Guess a letter!"
        }]);
        const liveWord = mainGame.splitWord;
        mainGame.eachGuess(inquirerResponse.game);
        // Don't display splitWord here, but stringRep:
        const output = mainGame.stringRep();
        console.log(output);
        // Detect that the word has been found, and exit if so
        if (!output.includes("_")) {
            console.log("You found it!");
            return;
        }
    }
    // The maximum number of guesses was not enough to find the word
    console.log('What a pity. You ran out of guesses.');
})();
Letter: 
<input name="game">
<button>Guess</button>

于 2018-11-18T22:07:55.653 回答