I'm trying to code a basic hangman game. When the user guesses correctly the word then the word is uploaded to an "answer" array and displayed to the user , when the guessed word is wrong then a warning should say "try again" and the input value cleared.
The thing is even when one word is actually guessed correctly there's still all the other words that were not so I end up getting the same warning "try again"
So I think I need to loop the original word and check to see if none of the elements are equal to the letter guess and for that I'm using every() but I can't make it work and "try again" always shows...
Help please
function generate(){
pickedWord = words[Math.floor(Math.random() * words.length)];
console.log(pickedWord)
for(let i = 0; i<pickedWord.length; i++){
word[i] = "_";
}
wordGuess.textContent = word.join(" ");
}
function getInput(e){
e.preventDefault();
let guess = input.value.toLowerCase();
if(guess.length > 1){
alert("type just one letter")
input.value = ""
}
else{
for(let i=0; i < pickedWord.length; i++){
if(guess === pickedWord[i]){
word[i] = guess;
wordGuess.textContent = word.join(" ");
input.value="";
}
else {
const letter = [pickedWord[i]]
console.log(letter)
const itemGuessed = letter.every(el => el !== guess)
if(itemGuessed){
alerta.textContent = "try again"
input.value="";
}
}
}
}
}
```
You actually didn't specify what does the words array look like, so I'm gonna assume tht it's an array of strings. Something like
const words = ['applejuice', 'bananashake', 'peanutbutter'];
So first of all, I actually don't understand what is the purpose of const letter = [pickedWord[i]]. Say the picked word was 'apple', and i was 0, then letter will be equal to ['a'], which makes the line const itemGuessed = letter.every(el => el !== guess) completely meaningless.
I also think it's better to check if guess is included in the pickedWord outside of the loop, using either pickedWord.every(el => el !== guess) or pickedWord.includes(guess) (though I prefer the latter!).
Anyway, I had a little rewrite on your code:
let pickedWord;
const words = ['applejuice', 'bananashake', 'peanutbutter'];
let word = [];
function generate() {
pickedWord = words[Math.floor(Math.random() * words.length)];
word = Array(pickedWord.length).fill('_');
console.log(pickedWord, word.join(''));
}
let guessedLetters = [];
function getInput(input){
// e.preventDefault();
const guess = input.toLowerCase().replace(/\s/g, '');
if(guess.length !== 1){
alert("type one letter");
}else{
if (pickedWord.includes(guess) === -1) {
alert("letter not in word");
}else if(guessedLetters.includes(guess)) {
alert("that letter is already guessed");
}else{
guessedLetters.push(guess)
for (let i = 0; i < pickedWord.length; i++) {
if(guess === pickedWord[i]){
word[i] = guess;
}
}
}
}
}
generate();
//cases where 1: same letter guessed twice
// 2: more than 1 letters guessed at once
// 3: capital letters guessed
// 4: empty string / space guessed
for (let input of ['', ' ', 'a', 'a', 'B', 'c', 'Cc', 'd', 'E', 'f', 'g', 'h']){
getInput(input);
console.log(word.join(''));
}
Note that I removed input.value=""; line for the demonstration purposes.
Please feel free to ask anything if you had a problem with my code. cheers!
Related
I am the very begginer (only if/else, for, while, slice etc) and i ve got a problem: so i wrote Hangman game. I need to put in there code saying ‘’let’s player upper case guess letter transform to lowercase one every time he puts uppercase letter”
Did i choose the right place for this new code in existing code?
Were my thoughts about appropriate code more or less right?
If not: what s wrong then?
var words = ["fish", "monkey", "pioni", "agreable"];
var randomWord = words[Math.floor(Math.random() * words.length)];
var answerArray = [];
for (var i = 0; i < randomWord.length; i++) {
answerArray[i] = "_";
}
var ramainingLetters = randomWord.length;
//Game circle
while (ramainingLetters > 0) {
alert(answerArray.join(" "));
var guess = prompt("Guess a letter or press cancel to exit game");
if (guess === null) {
break;
} else if (guess.length !== 1) {
alert("Enter only one letter");
} else if (guess == guess.toUpperCase()) {
guess = guess.toLowerCase();
} else {
//renew game cycle
for (var j = 0; j < randomWord.length; j++) {
if (randomWord[j] === guess) {
answerArray[j] = guess;
ramainingLetters--;
}
}
}
// stop game
}
alert(answerArray.join(" "));
alert(" Cool! this word was " + randomWord);
You could easily solve your problem by converting the chosen word to uppercase and everytime the user puts in a letter, make that uppercase too.
var randomWord = words[Math.floor(Math.random() * words.length)].toUpperCase();
And convert your quess always to uppercase
guess = guess.toUpperCase();
This way everything is consistent.
If they type in a letter in lowercase its getting converted to uppercase and compared with the word also in uppercase.
So Im pretty new to javascript and coding in general. Im making a Wordle algorithm just for fun to build my skills in coding. and while making this algorithm i realized that i was going to have to kind of recreate Wordle. so i looked online for wordle recreations in java script, and all the ones I found I saw one flaw that I didn't want to have.
The flaw that I saw was in the IF statement for checking a letter in the wordle answer. Specifically when the letter is in the word but not in the right spot. The recreations that i saw had an IF statement that looked something like this.
IF (answerWord.includes(guessLetter[i])) {
guessLetter[i] = color.(yellow)
}
(this isnt exactly how they wrote it, but its the main idea)
My main focus is on the .includes. This would not work because say our guess word is "agree" and the answer word "ready". the 2 E's in "agree" would be yellow, and we dont want that because their is is only 1 E in "ready. So we only want the first E in "agree" to be yellow and not the second E.
So i decided to figure it out on my own, and i was able to come up with this and it works. At least Im pretty sure it works, base on the the many words i tested it on.
So my question is, since Im making an algorithm im going to be making alot of calculations, is this the most efficient i could write this or can i make it better?
let guessWord = "agree"; // the first word thats inputed
let answerWord = "ready"; // the answer to the wordle
/*
'letterCheck' is an array that tells what condition each letter in 'startLetter' is, based on the answer word
2 = the letter is in the word and in the correct place (GREEN)
1 = the letter is in the word but not in the correct place (YELLOW)
0 = the letter in not in the word (GREY)
*/
var letterCheck = ["0", "0", "0", "0", "0"];
var guessLetter = ["A", "A", "A", "A", "A"]; // the separated letters of 'startword' in a array
var answerLetter = ["A", "A", "A", "A", "A"]; // the separated letters of 'answord' in a array
//adds the start word and the answer world to the arrays
for (var i = 0; i < 5; i++) {
guessLetter[i] = guessWord.substring(i, i + 1);
answerLetter[i] = answerWord.substring(i, i + 1);
}
console.log(guessLetter);
console.log(letterCheck);
console.log(answerLetter);
//this loops goes though every letter one by one
for (var i = 0; i < 5; i++) {
//checks if the letter is in the right spot
if (guessLetter[i] == answerLetter[i]) {
letterCheck[i] = "2";
console.log(guessLetter[i]);
console.log(letterCheck);
} else if (answerWord.includes(guessLetter[i])) {
//checks if there is more than one letter in start word or its the first letter
if (guessWord.split(guessLetter[i]).length - 1 == 1 || i == 0) {
letterCheck[i] = "1";
console.log(guessLetter[i]);
console.log(letterCheck);
//checks if the the amount of same letters in start words is equel to the amount of same letters in answer word
} else if (guessWord.split(guessLetter[i]).length - 1 == answerWord.split(guessLetter[i]).length - 1) {
letterCheck[i] = "1";
console.log(guessLetter[i]);
console.log(letterCheck);
//opposite of above
} else if (guessWord.split(guessLetter[i]).length - 1 != answerWord.split(guessLetter[i]).length - 1) {
letterCheck[i] = "1";
console.log(guessLetter[i]);
console.log(letterCheck);
// checks if any of the letters infront of it are the same as it
for (var j = 0; j < i; j++) {
if (guessLetter[i] == guessLetter[j]) {
letterCheck[i] = "0";
console.log(guessLetter[i]);
console.log(letterCheck);
}
}
}
} else {
letterCheck[i] = "0";
console.log(guessLetter[i]);
console.log(letterCheck);
}
}
console.log(guessLetter);
console.log(letterCheck);
console.log(answerLetter);
( I will remove the console.log's later they just helped my to debug.)
Sorry if my code might be confusing, im not the best at keeping my code clean. if you have any confusion or questions, I'll try my best in clear up any confusion.
To get all of the states (in precedence order: correct, wrong-position, incorrect), you should check in that precedence order, and remove letters from contention once the state in that letter's position has been set.
function check(guess, targetWord) {
const checkStates = new Array(5).fill("incorrect");
const letters = guess.split('');
const targetLetters = targetWord.split('');
for (let i=0; i<5; i++) {
if (targetLetters[i] === letters[i]) {
checkStates[i] = "correct";
targetLetters[i] = '';
letters[i] = '';
}
}
for (let i=0; i<5; i++) {
if (!letters[i]) continue;
let fi = targetLetters.findIndex(t => t===letters[i]);
if (fi > -1) {
checkStates[i] = "contains";
targetLetters[fi] = '';
}
}
return checkStates;
}
let solution = "ready"
console.log(`solution is ${solution}`);
let guess = "agree";
console.log(`checking ${guess}... ${check(guess, solution)}`);
guess = "roars";
console.log(`checking ${guess}... ${check(guess, solution)}`);
guess = "boars";
console.log(`checking ${guess}... ${check(guess, solution)}`);
solution = "beast"
console.log(`\nsolution is ${solution}`);
guess = "treat";
console.log(`checking ${guess}... ${check(guess, solution)}`);
Well, here's something to consider in simplifying. You can use a simple MAP loop to determine which letters are incorrect, then later highlight those in the word.
let guessWord = "agree"; // the first word thats inputed
let answerWord = "ready"; // the answer to the wordle
let tmpGuess = guessWord.split('');
let incorrects = answerWord.split('').map(e => {
let i = tmpGuess.indexOf(e);
if (i > -1) { // found it!
tmpGuess.splice(i, 1); // remove
return '';
}
return e;
}).filter(f => f);
console.log(incorrects);
I am fairly new to programming and have been assigned the Hangman game on Javascript. I have the game working fairly well so far, but I'm running into a problem when the word being guessed has a letter that occurs more than once. For example, if the word is APPLE and I type 'P', the program returns _ P _ _ _, when instead I should get _ P P _ _. I've tried looking intensively for answers and cannot find anything I could implement so far. Any help is much appreciated!
// Player chooses word for other player to guess
let word = prompt('Welcome to Hangman! Player 1, please enter a word for Player 2 to guess.').toUpperCase();
console.log(word);
let underScore = [];
let rightWord = [];
let wrongWord = [];
let dUS = document.getElementsByClassName('underscore');
let dRG = document.getElementsByClassName('rightGuess');
let dWG = document.getElementsByClassName('wrongGuess');
// ***
lettersInWord = word.split('');
// ***
const maxStrikes = 6; // max number of allowed mistakes
let strikes = 0; // number of incorrect guesses so far
// Create underscores for length of word
function createUnderscore() {
for (let i = 0; i < word.length; i++) {
underScore.push('_');
}
return underScore;
}
console.log(createUnderscore());
dUS[0].innerHTML = underScore.join(' '); //Displays underscores in DOM
document.getElementById('sub-btn').addEventListener('click', processGuess);
// Sets initial image
if (strikes == 0) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-0.png"
}
function processGuess(e) {
e.preventDefault();
let guess = document.getElementById('usr-input').value.toUpperCase();
console.log(word.indexOf(guess));
// If user guess is correct,
if (word.indexOf(guess) > -1) {
for (var i = 0; i < word.length; i++) {
if (word[i] === guess) {
rightWord.push(guess); // Adds guessed letter to rightWord Array
underScore[word.indexOf(guess)] = guess; // Adds correct letter?
dUS[0].innerHTML = underScore.join(' '); // Replaces underscore with correcct letter
dRG[0].innerHTML = rightWord.join(', '); // Adds correct letter to Right Guesses box
}
}
// Check to see if user word matches guesses
if (underScore.join('') == word) {
alert('You win! The word was: ' + word);
}
} else {
// Add to wrongWord array
wrongWord.push(guess);
console.log(wrongWord);
dWG[0].innerHTML = wrongWord.join(', ');
strikes++;
console.log('Number of Strikes: ' + strikes);
// Sets correct image according to number of strikes
if (strikes == 0) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-0.png"
} else if (strikes == 1) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-1.png"
} else if (strikes == 2) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-2.png"
} else if (strikes == 3) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-3.png"
} else if (strikes == 4) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-4.png"
} else if (strikes == 5) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-5.png"
} else if (strikes == 6) {
document.getElementById('pics').src = "../Project 3 - Hangman/images/strike-6.png"
}
if (strikes == maxStrikes) {
alert('You lose. The correct word was: ' + word);
}
}
}
console.log(strikes);
The problem is in this line:
underScore[word.indexOf(guess)] = guess;
Although you have a loop over all characters, and you have the index i where found a match, you actually search again for the first index with indexOf. So you will be placing the guess at the same first spot over and over again.
Instead just do:
underScore[i] = guess;
I need to achieve something like the following code, where if a user entered for example (you are bad), it shows an alert. The below code isn't working because it alerts for the words (you are) only without reading what's in badAppend.
var badAppend= ["freak", "ugly", "bad"]
var badWords = [("you are"+badAppend)];
if((badWords)
{
alert("you cannot use this word/sentence");
return false;
}
I'm trying to ahcieve this to avoid doing like the following:
var badWords = ["you are bad", 'you are ugly", "you are freak"];
etc..
I'd really appreciate it much if anyone can help with this. regards.
A more vanilla JavaScript way, on this one you do a "blacklist" check first against an array of "Bad Words" printing only the sentences that are allowed:
var words = document.getElementById('userInput').value.split(" ");
var badWords = ['array', 'of', 'bad', 'words'];
for (i = 0; i < words.length; i++) {
for (ii = 0; ii < badWords.length; ii++) {
var exists = words.indexOf(badWords[ii]);
if (exists != -1) {
words.splice(exists, 1);
}
}
var result = document.getElementById('notInside');
result.innerHTML += words[i];
result.innerHTML += "</br>";
}
I know he's using jQuery but just as another example to do this for other people that might need it. If you need to only display words that ARE in the array just do:
var words = document.getElementById('userInput').value.split(" ");
var badWords = ['array', 'of', 'bad', 'words'];
for (ii = 0; ii < badWords.length; ii++) {
var exists = words.indexOf(badWords[ii]);
if (exists > -1) {
var result = document.getElementById('inside');
result.innerHTML += words[exists];
result.innerHTML += "</br>";
}
}
var newWords = $(badAppend).map(function(item) { return "you are " + item; });
This will give you
newWords = [ "you are freak", "you are ugly", "you are bad" ];
I would do something like this,
var match = $('div.text').text().match(/[yY]ou(('re)|(\sare))\s\w+/g);
if(match){
match = match.map(function(item){
return (item.substring(item.lastIndexOf(" ")+1)).toLowerCase();
});
var match2 = $(match).filter(badWordsArray);
if(match2.length > 0){
console.log('Bad word!');
}else{
console.log('Input is clean!');
}
}else{
console.log('Input is clean!');
}
Change the text selector in the first line to whatever you need.
This will go through all the text that user entered, matches all the words which were followed by one of these:
You are
You're
you are
You are
The match variable will be an array containing all those words, then you can filter it based on your bad word array to see if there was any bad word.
If there is non of those four "you are"s in the code it just logs the input is clean, otherwise it checks for bad words in lowercase.
If you are sure that you just need to match 'you are' exactly, you can replace the regex with this one, it will run faster too. /(you\sare)\s\w+/g
From what I understand, you have a dictionary of bad words and you are trying to prevent user from using those words. In that case, you can do the following:
var containsBadWords = function(words){
var badWords = ['bad', 'ugly', 'freak' /* ...*/];
var badWordCount = 0;
words.forEach(function(word){
if(badWords.indexOf(word)>-1) badWordCount++;
});
return badWordCount;
}
var userWords = 'i am bad you are bad';
var result = containsBadWords(userWords.split(' '));
if(result>0) alert();
I'm a newbie on Javascript and I'm trying to do some exercises. I have found other ways on here that are more efficient at solving this, but anyway, here's how I tried doing it:
var char = prompt("Give me a letter");
char = char.toLowerCase();
function isVowel(char){
var vowels = new Array('a','e','i','o','u');
for(i = 0; i < vowels.length; i++){
if(vowels[i] == char){
return "This letter is a vowel.";
}else{
return "This letter is not a vowel.";
}
}
}
alert(isVowel(char));
Now, I understand this isn't the best way to do this, but I'd like to understand what's wrong with my for loop, since "a" is the only letter it recognizes as being a vowel.
Can someone point me out the reason why it isn't running trough the whole array?
Thanks in advance
You should not return until you have a definite "yes" or "no" answer.
Try something like this instead:
var char = prompt("Give me a letter");
char = char.toLowerCase();
function isVowel(char){
var vowels = new Array('a','e','i','o','u');
for(i = 0; i < vowels.length; i++){
if(vowels[i] == char){
return "This letter is a vowel.";
}
}
return "This letter is not a vowel.";
}
alert(isVowel(char));
var char = prompt("Give me a letter");
char = char.toLowerCase();
function isVowel(char){
var vowels = new Array('a','e','i','o','u');
var isv = false;
for(i = 0; i < vowels.length; i++){
if(vowels[i] == char){
isv = true;
}
}
if( isv == true)
return "This letter is a vowel.";
else
return "This letter is not a vowel.";
}
}
alert(isVowel(char));
The reason it isn't running through the whole array is because you return a value. That stops the function after the first iteration.
Here's a simpler solution to identify vowels without having to loop through an array:
function isVowel(char) {
if (vowels.indexOf(char) >= 0) {
return "The character \""+char+"\" is a vowel.";
} else {
return "The character \""+char+"\" is NOT a vowel.";
}
}
var vowels = new Array('a','A','e','E','i','I','o','O','u','U');
alert(isVowel('e'));
alert(isVowel('f'));
The indexOf functionality is based on the answer here.
Here's a working example (jsFiddle).