Javascript function keeps on returning null - javascript

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;
}

Related

Palindrome checker does not function properly with "almostomla"

function palindrome(str) {
const forward = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
const reversed = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
for (let i = 0; i < forward.length; i++) {
for (let k = reversed.length - 1; k >= 0; k--) {
if (forward[i] === reversed[k]) {
return true
} else {
return false
}
}
}
}
console.log(palindrome("almostomla"));
Why is this not working??
does my loop just creates a new "s"?
You don't need nested loops, that will compare every character with every other character. You just want to compare the first character with the last character, 2nd character with 2nd-to-last character, and so on. So there should just be a single loop that increments i and decrements k in lock step.
You shouldn't return true when you find a match, because there could be later characters that don't match. Return false when you find a mismatch, and return true if you make it through the loop without returning.
You don't need both forward and reversed variables, since they're the same. Just convert the input string to uppercase once, and use that for both.
You don't need to iterate through the whole string, you can stop when you get to the middle.
function palindrome(str) {
const upper = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
for (let i = 0, k = upper.length - 1; i < upper.length/2; i++, k--) {
if (upper[i] !== upper[k]) {
return false
}
}
return true;
}
console.log(palindrome("almostomla"));
console.log(palindrome("almotomla"));
console.log(palindrome("almottomla"));
You might want this:
function palindrome(str) {
const forward = str.replace(/[^a-zA-Z ]/g, "").toUpperCase()
var n = forward.length
for (let i = 0; i < n; i++) {
if (forward[i] !== forward[n-i-1]) {
return false;
}
}
return true;
}

Limit incorrect guess attempts in Hangman 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;
}
}

Why does my code not work out well replacing strings characters?

The exercise:
The goal of this exercise is to convert a string to a new string where each character in the new string is "(" if that character appears only once in the original string, or ")" if that character appears more than once in the original string. Ignore capitalization when determining if a character is a duplicate.
Examples
"din" => "((("
"recede" => "()()()"
"Success" => ")())())"
"(( #" => "))(("
My code was like that:
function duplicateEncode(word) {
let str = "";
for (let i = 0; i < word.length; i++) { //This iteration is to examine every character in the string;
for (let j = 0; j < word.length; j++) { //This iteration is to compare every character to every other inside the string, in order to check if there is any repetition
if (j === i) { //This first conditon was selected because a character is not supposed to be compared to itself
continue;
} else if (word[i] === word[j]) {
str = str + ")";
break;
} else if (j !== word.length - 1) {
continue;
} else if (j === word.length - 1) {
str = str + "(";
}
}
}
return str;
}
Does anyone can help me figure out why it doesn't work for all cases?
For example:
console.log(duplicateEncode("abc"));
It should return ((( instead of ((
But,
console.log(duplicateEncode("mulherm"));
returns exacly what it supposed to: )((((()
Apparently, whenever a string does not have a character that repeats,the function returns a string without the first element. But whenerver the string has at least one element that repeats it returns exacly what it's supposed to.
What is going on with my code?
I think the issue is that when you use your snippet below, you prevent yourself from entering the last loop.
if (j === i) {
continue;
}
The issue is present whenever a word with a non duplicated letter is last. i.e.
This works
console.log(duplicateEncode("aba")); //returns )()
This does not
console.log(duplicateEncode("aab")); //returns ))
What you could do is add a statement that when
i === word.length - 1
and no
"(" are in your
str variable, you can append another ")" to your str.
In other words, if you have found no duplicated characters after checking the before last position while iterating over your entire word, the last is guaranteed to be unique as well.
Console logs below
function duplicateEncode(word) {
let str = "";
for (let i = 0; i < word.length; i++) { //This iteration is to examine every character in the string;
for (let j = 0; j < word.length; j++) { //This iteration is to compare every character to every other inside the string, in order to check if there is any repetition
console.log(i);
console.log(j);
console.log(str);
if (j === i) { //This first conditon was selected because a character is not supposed to be compared to itself
console.log("continue")
continue;
} else if (word[i] === word[j]) {
console.log("append )")
str = str + ")";
break;
} else if (j !== word.length - 1) {
console.log("j !== length")
continue;
} else if (j === word.length - 1) {
console.log("append (")
str = str + "(";
}
}
}
return str;
}
Use a debugger to step through your code line by line. There are cases where the inner loop completes without ever meeting one of the conditions for a adding a character to the string.
Instead, use a boolean flag to denote whether the letter is duplicated, set that inside the loop (much simpler logic), then after the loop do str += (found ? ')' : '(');. This ensures you add exactly one character to the output string per iteration of the outer loop.

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>

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;
}

Categories

Resources