Javascript number guesser behaving oddly with "0" values - javascript

I'm completing a JavaScript Codecademy course and am having trouble with one of the independent projects that requires you to design a number guessing game. For some reason, when "0" is involved, it returns incorrectly.
JavaScript and I aren't best friends as is, but I had a hard time with what's a relatively simple project and decided to try out one of the "challenge yourself" sections and I just can't make it work at all, or work out what's going wrong.
function generateTarget() {
return Math.floor(Math.random() * 10);
};
function compareGuesses(userGuess, computerGuess, targetNumber) {
function getAbsoluteDistance() {
const uGuess = Math.abs(generateTarget() - userGuess);
const cGuess = Math.abs(generateTarget() - computerGuess);
return uGuess - cGuess
};
if (getAbsoluteDistance() <= 0) {
return true
} else {
return false
};
};
// 'human' is input when return is true; 'computer' when return is false
function updateScore(winner) {
if (winner === 'human') {
humanScore ++;
} else if (winner === 'computer') {
computerScore ++;
};
};
function advanceRound() {
currentRoundNumber +=1;
};
It's essentially a game where the computer generates a random "target" number, you enter a guess number and the computer generates a guess number. Depending on which guess number is closer, you or the computer wins. If you guess the same number, or your guesses are equidistant, the human is meant to win.
This is (just about) working now, except in cases when:
the "target" number is 0. (The computer always wins)
you and the computer guess the same number. (The computer always wins)
you and the computer guess different but equidistant numbers from the target number (The computer always wins)
I'd like to try and get my head around some basic JavaScript so I can move on to something else for a bit, but can't work out what's wrong at all or how to fix it. The only thing that I can identify that these cases have in common is the fact that there's always a "0" somewhere in the absolute distance calculation.
Any help would be massively appreciated!

Kind of made it interactive. From what you say the user wins in the event of a tie or when you guess the same number (a tie). I think the comments indicated why it was failing initially, or at least what is what I see. You were comparing to two different targets, and you can see that in a Fiddle because the results were not consistent.
const userinput = document.getElementById("user");
const computerinput = document.getElementById("computer");
const targetvalue = document.getElementById("target");
const roundcount = document.getElementById("round");
var humanScore = 0;
var computerScore = 0;
var rounds = 0;
document.getElementById("generate").addEventListener("click", function(e) {
targetvalue.value = generateTarget();
});
document.getElementById("calc").addEventListener("click", function(e) {
let result = compareGuesses(userinput.value, computerinput.value, targetvalue.value);
if(result) humanScore++
else computerScore++
rounds++
roundcount.innerHTML = rounds;
alert("Score: Human: " + humanScore + ", Computer: " + computerScore );
});
function generateTarget() {
return Math.floor(Math.random() * 10);
}
function compareGuesses(userGuess, computerGuess, targetNumber) {
const uGuess = Math.abs(targetNumber - userGuess);
const cGuess = Math.abs(targetNumber - computerGuess);
if (uGuess - cGuess <= 0) {
return true
} else {
return false
}
}
<input id = "user" value="" placeholder ="user">
<input id = "computer" value="" placeholder ="computer"><br>
<input id = "target" value="" placeholder ="target">
<button id ="calc" type = "submit">
Submit
</button>
<button id ="generate" type = "submit">
Generate Number
</button><br>
Round: <span id = "round"></span>
The Snippet should allow testing easily. Did not add a thing to generate the computer guess, but that would be similar to generating a target.

I would do like:
function NumGuessGame(){
this.computerScore = this.score = 0;
this.guess = function(num){
if(num === Math.floor(Math.random()*10)){
this.score++;
}
else{
this.computerScore++;
}
return this;
}
}
var gg = new NumGuessGame;
gg.guess(9).guess(11).guess(7).guess(7);
if(gg.computerScore >= gg.score){
console.log('Computer Wins');
}
else{
console.log('You Win');
}
Of course, you should notice that the computer will almost always win under this scenario. You should notice the odds go up here:
function NumGuessGame(){
this.computerScore = this.score = 0;
this.guess = function(num){
if(num === Math.floor(Math.random()*10)){
this.score++;
}
else{
this.computerScore++;
}
return this;
}
}
var gg = new NumGuessGame;
gg.guess(4);
if(gg.computerScore >= gg.score){
console.log('Computer Wins');
}
else{
console.log('You Win');
}
Note that the examples above expect a 0-9 guess or you lose no matter what.

Related

Calculating the average of several function invocations using closures

I am doing a coding challenge that reads like this:
Create a function runningAverage() that returns a callable function object. Update the series with each given value and calculate the current average.
rAvg = runningAverage();
rAvg(10) = 10.0;
rAvg(11) = 10.5;
rAvg(12) = 11;
I got a working solution, yet they also want the results to be rounded like this:
rAvg(13) = 13.50678; => 13.50
rAvg(13) = 13.50; => 13.50
rAvg(13) = 13.5; => 13.5
rAvg(13) = 13; => 13
Here is my code:
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let averageArray = average.toString().split('.');
//to get the number of decimal places
//e.g 11.543 ==> ['11', '543']
if ((Array.from(averageArray[1]).length) >= 2) {
return average.toPrecision(2);
}
else if ((Array.from(averageArray[1]).length) = 1) {
return average.toPrecision(1);
}
else {
return average;
}
}
}
I tested parts of the function separately and it seems to work, yet when I invoke it I get the message 'cannot convert undefined or null to object'.
This sounds like a fun coding challenge!
In this case, you want toFixed(), not toPrecision(). toPrecision() essentially allows you determine how many digits TOTAL (including those on the left of the decimal point) should appear, whereas toFixed() focuses on the number of digits to the right of the decimal point. Feel free to look these two methods up on MDN. When you read that toPrecision() may return exponential notation, this should make you pause and think, "That's weird. Why does this happen? When does this happen?", rather than "this detail is unimportant."
Your .length = 1 comparison needs to be modified to a ===.
Your code currently fails if an integer is the first number provided to rAvg(). In your first conditional, Array.from(undefined) may run, which is not permissible in JavaScript. You should consider ways to only work with "the digits to the right of the decimal" only if "there are digits to the right of the decimal."
Here is a working solution including all the suggestions, in case someone is interested:
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let numIsDecimal = average.toString().includes('.');
if (numIsDecimal) {
let averageArray = average.toString().split('.');
//to get the number of decimal places
//e.g 11.543 ==> ['11', '543']
if ((Array.from(averageArray[1]).length) >= 2) {
return Number(average.toFixed(2));
}
if ((Array.from(averageArray[1]).length) === 1) {
return Number(average.toFixed(1));
}
}
else {
return Number(average);
}
}
}
Not sure if this works but try it
function runningAverage() {
let number = 0;
let numbOfFunctionCalls = 0;
return function (y) {
number += y;
numbOfFunctionCalls ++;
let average = (number/numbOfFunctionCalls);
let averageArray = average.toString().split('.');
if ((Array.from(averageArray[1]).length) >= 2) {
return Math.round(average.toPrecision(2) * 2) / 2;
} else if ((Array.from(averageArray[1]).length) == 1) {
return Math.round(average.toPrecision(1) * 2) / 2;
} else {
return Math.round(average * 2) / 2;
};
};
};

Simple number guessing game using Javascript

I'm trying to make a number guessing game on JS for a web dev training I'm on. The problem is that it always prints the keyInYNStrict without giving an another chance for the user. Ignore the fact that the strings and variables are not in English. Basically I want the keyInYNStrict to only come after the arvaus == arvattava is true and the game has ended.
const minLuku = 1;
const maxLuku = 30;
const readlineSync = require('readline-sync');
let arvaus, arvattava, arvaustenLkm
do {
arvaus = readlineSync.question('Ajattelen numeroa 1 ja 30 välillä. Arvaapa vaan');
arvaustenLkm = 1;
arvattava = Math.floor(Math.random() * (maxLuku + 1 - minLuku)) + minLuku
kelvollinen = !isNaN(arvaus) && arvaus > 0 && arvaus < 31;
if (!kelvollinen) {
console.log('Elä viitsi! Laita nyt jokin oikea numero.');
}
else if (arvaus < arvattava){
arvaustenLkm++;
console.log('Kokeile suurempaa lukua.');
} else if (arvaus > arvattava){
arvaustenLkm++;
console.log('Kokeile pienempää lukua.');
} else if (arvaus == arvattava){
console.log('Hienoa. arvasit oikein ' + arvaustenLkm + ' arvauksella.')
}
} while (readlineSync.keyInYNStrict('Haluatko arvata uudestaan?'))
You'll need two while loops nested. The first is to repeat the guessing until the number has been found, the second to ask if the user wished to play again. This becomes clearer if you break a single game into a function, and then wrap "Play again?" around that function.
The following is untested. Notice I also pulled out the "Invalid guess" check to separate it from the game logic. I think that also improves readability, and allows for the option of checking for some other exit condition should the user wish to end early.
EDIT: As I'm thinking about it, there's another problem: Do you want to reset the hidden number each guess? That's probably not consistent with expectations. I've modified the code to reflect.
const minLuku = 1; // Lower bound
const maxLuku = 30; // Upper bound
const readlineSync = require('readline-sync');
let arvaus, arvattava, arvaustenLkm
do {
// Number of guesses
arvaustenLkm = 1;
//Target number
arvattava = Math.floor(Math.random() * (maxLuku + 1 - minLuku)) + minLuku
do {
// User's guess
arvaus = readlineSync.question('Ajattelen numeroa 1 ja 30 välillä. Arvaapa vaan');
// Bad guess test
if (isNaN(arvaus) || arvaus < minLuku || arvaus > maxLuku) {
console.log('Elä viitsi! Laita nyt jokin oikea numero.');
continue;
}
if (arvaus < arvattava){
arvaustenLkm++;
console.log('Kokeile suurempaa lukua.');
} else if (arvaus > arvattava){
arvaustenLkm++;
console.log('Kokeile pienempää lukua.');
} else if (arvaus == arvattava){
console.log('Hienoa. arvasit oikein ' + arvaustenLkm + ' arvauksella.')
}
} while (arvaus != arvattava)
} while (readlineSync.keyInYNStrict('Play again?'))

See if a number is within range of 10 or 30 in hot or cold game

I'm working on a game where you have to guess a number, and if it matches the number that is randomly generated then you win. I've got most of the game completed apart from the part where you have to check if the guessed number is within the range of 30 or 10 of the randomly generated number. To give an example, if the random number is 50 and the guessed number is 60 then this is within a range of 10 of the random number and this should therefore cause the screen to turn to the colour red, because they are 'hot' but iv'e been having trouble working out the calculation for it. Any ideas?
This is the code I'm using to calculate if the number is correct or not.
function guessFunction() {
counter++;
document.getElementById("guessNumber").innerHTML = counter;
if (!checkEqual(document.getElementById("randomNumber"), random)) {
document.body.style.background = "orange";
} else {
document.body.style.background = "green";
document.getElementById("another").style.visibility = "hidden";
}
if (!checkHigher(document.getElementById("randomNumber"), random)) {
return true;
} else {
return false;
}
if (!checkGreater(document.getElementById("randomNumber"),
random)) {
return true;
} else {
return false;
}
}
function checkHigher(element1, element2) {
if (element1.value > element2) {
document.getElementById("highOrLow").innerHTML = "Too High";
} else if (element1.value == element2) {
document.getElementById("highOrLow").innerHTML = "got it";
} else {
document.getElementById("highOrLow").innerHTML = "Too low";
}
}
Basically subtract the two and get the absolute value to find the difference. On another note I see you have multiple functions for testing different cases. You could write one function to handle all cases and only pass the generated number and guess in instead of the elements themselves. Then it is more stand alone. Something like this:
function checkNumber(number, guess) {
// Gets difference by subtracting and finding absolute value
var diff = Math.abs(number - guess);
// Assumes guess is too low and checks if its higher
var highlow = " and too low";
if (guess > number) {
highlow = " and too high";
}
// Checks range for hot and cold while adding in high or lowness, else its exact so ignores adding high or lowness
// Off by more than 20 cold, off by under 20 hot.
if (diff >= 21) {
document.getElementById("highOrLow").innerHTML = "Cold" + highlow;
} else if (diff >= 1 && diff <= 20) {
document.getElementById("highOrLow").innerHTML = "Hot" + highlow;
} else {
document.getElementById("highOrLow").innerHTML = "Got it";
}
}
Fiddle: https://jsfiddle.net/bohxapdw/2/

Creating a random number generator game in JavaScript and cannot get the While loop to keep looping

I am trying to create a number generator game where the user has 5 guesses to guess the correct number (between 1 and 10). My code is:
/* Random number generator that compares itself with the user input */
var randomGenerator = Math.floor(Math.random() * 10) + 1;
var turns = 5;
while (turns > 0); {
var user = prompt("Pick a number between one through ten");
var userInput = parseInt(user);
if(userInput === randomGenerator) {
alert("You got it!");
turns = 0;
} else if (userInput > randomGenerator) {
alert("Guess lower!");
--turns;
} else if (userInput < randomGenerator) {
alert("Guess higher!");
--turns;
}
}
alert("The number was " + randomGenerator);
The code runs once and stops. I want it to run over and over until they run out of guesses or they guess the correct number.
you have the semicolon after while
remove that and it will work just fine
I would do something like this for the browser....
// browser with jquery
(function() {
var guesses = 5;
var myRandomNumber = random; // Get random number however you choose
$('#guessInput').on('submit', function (e) {
var guess = $(this).val();
if( guess == myRandomNumber ) {
// show user congratulations
} else {
guesses -= 1;
}
if (guesses === 0) {
// say sorry you are out of guesses
$(this).prop("disabled", true);
}
});
}());
You will have to link this to a button that actually submits and then test the input rather than what I have given you.

Why is my Javascript not adding data on submit?

I am building a hot and Cold App in JS and jQuery.
My issue is on form submit that user input inserts a number and the game tells them if its hold or cold or hotter or holder based on how close or far from the number.
Issue is that It only works the first time. After that it does nothing.
How do I made it so that when the user input on submit it generates a new secretNumber and based on the checker I have setup outputs either hot or cold or hotter or colder.
Seems its not generating a new secret number or it is just not inputing it.
Code here http://codepen.io/mackenzieabby/pen/qOXNLg
JS
$(document).ready(function(){
// Global Variables.
var theSecret = Math.floor((Math.random() * 100) + 0); // Creates Secret Number
var userGuess = $('#userGuess').val(); // User Inut Guess
var count = 0;
var addList = document.createElement("li")
// Display information modal box
$(".what").click(function(){
$(".overlay").fadeIn(1000);
});
// Hide information modal box
$("a.close").click(function(){
$(".overlay").fadeOut(1000);
});
// Functions
// New Game
function newGame() {
// new gama data here
}
// Add To List
function addtoList() {
}
function preventRefresh() {
$("form").submit(function(event) {
event.preventDefault();
theSecret();
veryHotGuess();
hotGuess();
veryColdGuess();
coldGuess()
correctAnswer();
});
}
preventRefresh();
function addGuess() {
$("ul#guessList").append("<li>" + userGuess + "</li>");
}
// Checks if hot or cold or correct
function veryHotGuess() {
if (userGuess < 25 && theSecret < 25) {
document.getElementById('feedback').innerHTML = "Very Hot";
}
}
function hotGuess() {
if (userGuess < 50 && theSecret < 50) {
document.getElementById('feedback').innerHTML = "Hot";
}
}
function veryColdGuess() {
if (userGuess < 100 && theSecret < 100) {
document.getElementById('feedback').innerHTML = "Very Cold";
}
}
function coldGuess() {
if (userGuess < 75 && theSecret < 75) {
document.getElementById('feedback').innerHTML = "Cold";
}
}
function correctAnswer() {
if (userGuess == theSecret) {
document.getElementById('feedback').innerHTML = "You Got It";
}
}
});
Calling theSecret(); causes a JavaScript error. You are calling the variable as a function, which it isn’t obviously.
BTW, I think your calculation of guess "temperature" might be quite wrong.
You have to redefine your definition of Global variable in javascript:
$(document).ready(function(){
// Global Variables.
var theSecret = Math.floor((Math.random() * 100) + 0); // Creates Secret Number
var userGuess = $('#userGuess').val(); // User Inut Guess
var count = 0;
var addList = document.createElement("li")
...
those ARE NOT global variables, because you made then in a scope, the document.ready scope... a Global Variable must be defined outside any scope, so it's available in all scopes, including inside the document.ready as well inside any function method you wrote.
Secondly, you need to rethink what you are doing, as a rule, you are repeating yourself over and over with
document.getElementById('feedback').innerHTML = xxxx;
one day you need to change the feedback to something else, or also write something else, can you see in how many places you need to change your code? When you see several lines of almost the same code: You're doing it wrong...
And you need to simplify your calculations, you make it hard to code and see what's going on...
Third, as Alexander pointed out, you need to re-think how you're calculating, what you want to calculate if not the userGuess or the theSecret, but give an answer based on how close/far the user guess is from the correct value ... that I would call it the difference between 2 numbers.
something like: Math.abs(theSecret - userGuess)
Here's my approach:
http://codepen.io/anon/pen/wKqzvg?editors=001
(irrelevant code removed)
var theSecret = 0,
guesses = [];
$(document).ready(function() {
// Creates Secret Number
theSecret = Math.floor((Math.random() * 100) + 0);
$("form").submit(function(evt) {
evt.preventDefault();
checkTemperature();
});
});
// Functions
// Add To List
function addToList(txt) {
guesses.push(txt);
$("#count").text(guesses.length);
$("ul#guessList").append("<li>" + txt + "</li>");
}
function write(txt) {
document.getElementById('feedback').innerHTML = txt;
}
function checkTemperature() {
var userGuess = parseInt($('#userGuess').val()),
dif = Math.abs(theSecret - userGuess);
// for debug only
console.log("theSecret:" + theSecret);
console.log("userGuess:" + userGuess);
console.log("dif:" + dif);
addToList(userGuess);
if (dif < 5)
write("Vulcan Hot");
else if (dif < 25)
write("Very Hot");
else if (dif < 50)
write("Hot");
else if (dif < 75)
write("Cold");
else if (dif < 100)
write("Very Cold");
else if (dif === 0)
write("You Got It");
}
The problem isn't with theSecret but with userGuess. You were not grabbing the value on submit so it was empty. I suggest to always console.log or inspect variables to make sure they are getting populated correctly. In your submit I added this: userGuess = $('#userGuess').val(); and it will now check correctly.
However, as Alexander mentioned the math is wrong. The value will always be under 100 and so it will always be Very Cold. You have to get the absolute difference of both numbers and then do your guess check:
var difference = Math.abs(theSecret - userGuess);
if (difference < 100) {
document.getElementById('feedback').innerHTML = "Very Cold";
}
if (difference < 75) {
document.getElementById('feedback').innerHTML = "Cold";
}
if (difference < 50) {
document.getElementById('feedback').innerHTML = "Hot";
}
if (difference < 25) {
document.getElementById('feedback').innerHTML = "Very Hot";
}
if (difference == 0) {
document.getElementById('feedback').innerHTML = "You Got It";
}
I forked your project here: http://codepen.io/paulmg/pen/xwLExM

Categories

Resources