Limit incorrect guess attempts in Hangman Javascript - javascript

I'm trying to code a hangman game where a user only has three incorrect guess attempts.
i.e. if they guess the correct letter they continue playing. If they guess incorrectly three times then the game ends.
I've seen some other solutions where functions are used but I'm not at that point in my JS journey yet, so I'm hoping someone can use some basic syntax.
I'm guessing it's a general no-no to further nest 'if', 'else if' and 'else' statements in an 'else' statement. I've also tried to add another 'for loop' in the 'while loop' but this just breaks as well.
As the code stands now, when I enter a correct OR incorrect letter, the game terminates and shows me the final alert. Could someone pls explain to me what's happening?
Thanks :)
var words = [
"javascript",
"monkey",
"amazing",
"pancake",
"discipline",
"integrity",
"enjoy"
]
var word = words[Math.floor(Math.random() * words.length)];
console.log(word);
var answerArray = [];
for (var i = 0; i < word.length; i++) {
answerArray[i] = "_";
}
console.log(answerArray);
var remainingLetters = word.length;
console.log(remainingLetters);
var maxTries = 3;
var guessedWrong = [];
while (remainingLetters > 0 && guessedWords.length < maxTries) {
alert(answerArray.join(" "));
var guess = prompt("Guess a letter, or click Cancel to stop playing.");
guess = guess.toLowerCase();
if (guess === null) {
break;
} else if (guess.length !== 1) {
alert("please enter a single letter.");
} else {
for (var j = 0; j < word.length; j++) {
if (guess === word[j]) {
answerArray[j] = guess;
remainingLetters--;
// if incorrect letter guessed, then push to guessedWrong array;
// have tried another 'if', 'else if', and 'else' here but luck;
} else if (guess !== word[j]) {
guessedWrong.push(guess);
}
}
}
}
alert(answerArray.join(" "));
alert("Good job! The answer was " + word);

The problem was that the if clause that was incrementing guessedWrong was being called for each character in the word, and regardless of the input character. That means that at the end of one while iteration, guessedWrong.length would've been close to word.length, ending the game.
I've added a check to customize the end game message depending on whether the word was found or not
also wrapped everything in a function to demonstrate how to use functions.
have added comment blocks to detail the changes, most of them are towards the end of the code
I hope this helps
This implementation is great and you're doing a great job. Good luck on your journey!
function startGame() {
var words = [
"javascript",
"monkey",
"amazing",
"pancake",
"discipline",
"integrity",
"enjoy"
]
var word = words[Math.floor(Math.random() * words.length)];
console.log(word);
var answerArray = [];
for (var i = 0; i < word.length; i++) {
answerArray[i] = "_";
}
console.log(answerArray);
var remainingLetters = word.length;
console.log(remainingLetters);
var maxTries = 3;
var guessedWrong = [];
while (remainingLetters > 0 && guessedWrong.length < maxTries) {
alert(answerArray.join(" "));
var guess = prompt("Guess a letter, or click Cancel to stop playing.");
guess = guess.toLowerCase();
if (guess === null) {
break;
} else if (guess.length !== 1) {
alert("please enter a single letter.");
} else {
for (var j = 0; j < word.length; j++) {
if (guess === word[j]) {
answerArray[j] = guess;
remainingLetters--;
// if incorrect letter guessed, then push to guessedWrong array;
// have tried another 'if', 'else if', and 'else' here but luck;
}
// if we add the if check here inside the for loop, then with each iteration we wrongfully increment
// the guessedWrong array, and game will be over on next while iteration.
// so we've moved it outside the for loop
}
// String.indexOf() returns -1 if a specific character is not found inside that string. otherwise it will return
// the position at which that character is first found inside the string. we can also use lastIndexOf() which checks
// for the same thing, except it starts looking from the end of the array.
if (word.indexOf(guess) === -1) {
guessedWrong.push(guess);
}
}
}
// here we've customized the alert depending on whether the game was won or not
if (guessedWrong.length == maxTries) {
alert('Sorry, you have exhausted all attempts. The correct answer was ' + word);
} else {
alert("Good job! The answer was " + word);
}
// we've wrapped the whole thing in a function so that we can call it and start the game again.
if (confirm('Do you want to play again?')) {
startGame()
}
}
// since it's a function, we have to call it to start the game
startGame()

I slightly modified your implementation and it seems to work well
take a look
var words = [
"javascript",
"monkey",
"amazing",
"pancake",
"discipline",
"integrity",
"enjoy"
]
const word = words[Math.floor(Math.random() * words.length)];
console.log(word);
let answerArray = word.split('').map(_ => '_');
const letters = new Set(word.split(''))
console.log(letters);
let errors = 0;
const maxRetry = 3
while (true) {
alert(answerArray.join(" "));
let guess = prompt("Guess a letter, or click Cancel to stop playing.");
if (guess === null) {
continue;
} else if (guess.length !== 1) {
alert("please enter a single letter.");
continue;
}
guess = guess.toLowerCase().trim()
if (!letters.has(guess)) {
errors++
if (errors === maxRetry) {
alert('you lose the answer was ' + word)
break;
}
}
word.split('').forEach((l, i) => {
if (l === guess) {
answerArray[i] = l
letters.delete(l)
}
})
if (letters.size === 0) {
alert(answerArray.join(" "));
alert("Good job! The answer was " + word);
break;
}
}

Related

Why doesn't the second code work the same as the first code?

The First Code works correctly and displays the right answer which is 19.
function findLongestWordLength(str) {
let high = 0;
let word = str.split(" ");
for(let i = 0; i < word.length; i++)
{
if (word[i].length > high)
high = word[i].length;
}
console.log(high)
}
findLongestWordLength("What if we try a super-long word such as otorhinolaryngology");
The second code below, only works until the word "super-long" and logs 10 as the final output, which is incorrect. I'm trying to figure out what goes wrong here. It works fine with other sentences,
FOR REFERENCE
The str.length in the sentence is 60(spaces included), and there are 9 spaces in between the entire sentence
function findLongestWordLength(str) {
let high = 0;
let count = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] != " ") {
count++;
} else {
if (count >= high)
high = count;
count = 0;
}
}
return high;
}
findLongestWordLength("What if we try a super-long word such as otorhinolaryngology");
count could be holding a non-zero value at the end of the loop, which will get ignored. Just add a check at the end of the loop as well to update that value.
for(let i = 0; i < str.length; i++)
{
if (str[i] != " ") count++;
else
{
if(count >= high) high = count;
count = 0;
}
}
if(count >= high) high = count;
In order to get 19, you have to end your string with a space. Because the last character of "otorhinolaryngology" is a 'y', you simply increment count at the very end and you never hit your else condition which will update high. Put a space at the end, add an extra condition checking if i == str.length -1 Or simply use the length algorithm, or, as I would prefer, use a reducer like so:
const findLongestWordLength = str => str.split(' ').reduce((acc, word) => word.length > acc ? word.length : acc, 0)

Assistance with javascript palindrome

I am trying to solve a palindrome using a for loop in JavaScript (my code is below).
I cannot figure out what I am doing wrong. If someone can please correct and explain, it will be much appreciated. I am fairly new to coding.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
On for loop inside palindrome, you have looped from 0 ~ a.length and the item on length index in a string is undefined so reversed will always be undefined.
You need to loop from 0 ~ a.length - 1 as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i < a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
console.log(reversed);
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
You can reverse string simply as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
const reversed = a.split('').reverse().join('');
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
your loop:
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
you just need remove -1 and start the loop with 1 because when you reached the end of the iteration you will have the length of the word -1 and this will try to access a negative position.
after changing:
for (let i = 1; i <= a.length; i++) {
// you can use reversed += a[a.length - i] instead of;
reversed = reversed + a[a.length - i];
}
You can also reverse a string using the reverse method like this:
reversed = a.split('').reverse().join('');
Finally if you want to validata sentences you need to remove blank spaces and convert it in lower or upper case(usually converted in lowercase) because compare is case sensitive ("Party trap" != "part ytraP").
This code compares the first character to the last character, then advances to compare the second character to the next to last character until it runs out of characters.
As soon as it finds an inequality, it returns false because there is no reason to continue comparing.
let word = window.prompt("Enter a word");
const palindrome = a => {
let last = a.length - 1;
// loop, comparing the values until you find something that doesn't match
for (let first = 0; first <= last; first++, last--) {
if (a[first] !== a[last]) {
return "false";
}
}
// everything matched
return "true";
}
document.getElementById("output").textContent = palindrome(word);
<output id="output"></output>

Javascript function keeps on returning null

So I have been working on a game project where if a player clicks on a letter that if it matches in a phrase to guess, it displays the letter. If the player clicks on a letter without any matches (which is represented by null) then a blue heart turns to a lost heart and the missed counter goes up. For some reason, Even though the player clicks on a matching letter, my code still displays a lost heart. Can anyone help? Here is the github link to the whole project:
https://github.com/santanaquan/Techdegree-Project-6
here is the javascript code snippet.
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
}
else {
letter = null;
}
}
return letter;
}
Since your code iterates over all letters, even if the player guesses a correct letter, your code will find it but will then continue to loop after that, this making letter null.
You only need to remove the else and initialize letter to null. You should not break in the if because that way you'll miss duplicated letters.
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter = null;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
}
}
return letter;
}
The checkLetter function is faulty. I quote the original below for reference:
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
}
else {
letter = null;
}
}
return letter;
}
The problem here is that letter is updated every single time through the loop. This means it ends with whatever value it gets on the last iteration, which will always be null unless the last letter was clicked - throwing away any match found on the way.
One very simple fix is to initialise letter as null, then only change it when a match is found. This guarantees it will have the correct value at the end. So here is a working version:
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter = null;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
}
}
return letter;
}
As pointed by others your checkLetter function is broken. You have to stop after you get the match. If you iterate further the letters won't match and the letter variable will be set to null. Modify it to this.
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter = null;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
break;
}
}
return letter;
}
Now you have one other problem that is if the letter was already guessed correctly, the loop will not work if there are duplicate characters in the phrase as the first match will set the letter variable. So you will have to add a check in the loop to see if the letter is already matched.
function checkLetter(button) {
const getLetter = document.getElementsByClassName('letter');
let letter = null;
for (let i = 0; i < getLetter.length; i++) {
if (button.textContent === getLetter[i].textContent) {
if(/*letter is not already guessed*/) {
getLetter[i].className += ' show';
letter = getLetter[i].textContent;
}
}
}
return letter;
}

Why is my while loop not iterating through completely?

So this is my code below, the goal is for this program is to check to see if the letters of the second string can be found in the first string. However I found the problem that i isn't, increasing in value. So the loop is only going through once. So this program ends at the first letter that it finds and returns true. How do I get i to increase so that it's iterating through every character of the string?
function mutation(arr) {
var str = arr[1];
str = str.toLowerCase().split("");
var i = 0;
while (i < arr.length) {
if (arr[0].indexOf(str[i]) > -1) {
//return arr[i].indexOf(str[i], i);
return true;
} else {
return false;
}
i++;
}
}
mutation(["hello", "hey"]);
This maybe?
function mutation(arr) {
var str = arr[1];
str = str.toLowerCase().split("");
// iterating an array screams "for loop"
for (var i=0; i < str.length; i++) {
// if the letter was not found exit immediately
if (arr[0].indexOf(str[i]) == -1) return false;
}
// since it didn't exit before, all the letters must have been found.
return true;
}
function mutation(arr) {
var base = arr[0],
str = arr[1].toLowerCase().split(''),
i = 0,
match = true;
while (i < str.length) {
// if any target letter is not in base, return false
if(base.indexOf(str[i]) === -1){
return false;
}
}
// otherwise they were all in, so return true
return true;
}
mutation(["hello", "hey"]);
Totally different technique.
This function replaces, in the second string, all letters from the first string with empty space. If the length is zero all letters were found.
function mutation(arr) {
return arr[1].replace(new RegExp("[" + arr[0] + "]", "g"), "").length == 0;
}

Why does my program skip the game part?

i wrote a very basic hangman game but it skips the actual hangman part. It will show the alert for how long the word is you press ok then it show the finish message no game part and i can't find out why
please tell me what is wrong
Hangman
<body>
<h1>Hangman!</h1>
<script>
var words = [
"javascript",
"monkey",
"amazing",
"pancake",
];
var word = words[Math.floor(Math.random() * words.length)];
var answerArray = [];
for (var i = 0; i < word.length; i++) {
answerArray[i] = "_"
}
var remainingLetters = word.length
while (remainingLetters < 0) {
alert(answerArray.join(" "));
var guess = prompt("Guess a letter, or click Cancel to stop playing>");
if (guess === null) {
break;
} else if (guess.length !== 1) {
alert("Please enter a single letter.");
} else {
//update the game state with a guess
for (var j = 0; j < word.length; j++) {
if (word[j] === guess) {
answerArray[j] = guess;
remainingLetters--;
}
}
}
}
alert(answerArray.join(" "));
alert("Good Job! The answer was " + word);
</script>
</body>
</html>
while (remainingLetters < 0) { should be while (remainingLetters > 0) {.
Also, as Pluto mentioned it (good catch!), you can cheat by entering the same letter over and over. To solve that, you could store the guessed letters in a string and check if it was guessed before (and not increment the score).
Another adjustment, if the user hits cancel (wants to quit), I added an if statement at the end so that no more alerts are displayed.
var words = ["javascript", "monkey", "amazing", "pancake"];
var word = words[Math.floor(Math.random() * words.length)];
var answerArray = [];
// Storing the letters already guessed
var guessedLetters = "";
for (var i = 0; i < word.length; i++) {
answerArray[i] = "_"
}
var remainingLetters = word.length;
while (remainingLetters > 0) {
alert(answerArray.join(" "));
var guess = prompt("Guess a letter, or click Cancel to stop playing>");
if (guess === null) {
break;
} else if (guess.length !== 1) {
alert("Please enter a single letter.");
} else {
// if the letter was already guessed
if (guessedLetters.indexOf(guess) > -1) {
// skip
continue;
}
//update the game state with a guess
for (var j = 0; j < word.length; j++) {
if (word[j] === guess) {
answerArray[j] = guess;
// add the letter to the guessed letters
guessedLetters += guess;
remainingLetters--;
}
}
}
}
// if there are no remaining letters (if the user cancelled,
// no need to show these).
if( !remainingLetters) {
alert(answerArray.join(" "));
alert("Good Job! The answer was " + word);
}
JS Fiddle Demo

Categories

Resources