Store value in a variable - javascript

I am new in Javascript. I develop a program that store the score of humun and computer guess number. I want the human score and computer score will update when I call the updateScore() functions. However, it works but the score unable to increase by last score.
Here is the code:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random()*10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humunGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humunTarget = Math.abs(humunGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humunTarget < computerTarget || humunTarget == computerTarget) {
return true;
}
else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore+=1;
case false:
computerScore+=1;
}
};
updateScore()
console.log(humanScore)
console.log(computerScore)

It is a programming language based on javascript event/trigger features. all variables are reset when you call the file again.
The variables seem to be reset every time you call the javascript file
let humanScore = 0,
computerScore = 0,
currentRoundNumber = 1;
// Write your code below:
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const compareGuesses = () => {
// Humun & Computer guess a number
const humanGuess = 1;
const computerGuess = 2;
// Call the generateTarget functions
const secretTargetNumber = generateTarget();
// Compare the difference between Target number and humun guess number
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
// Compare the difference between Target number and computer guess number
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
// Return true if humun won, false if computer won
if (humanTarget < computerTarget) {
return true;
} else {
return false;
}
};
let updateScore = () => {
switch (compareGuesses()) {
case true:
return humanScore += 1;
case false:
computerScore += 1;
}
};
let showScore = () => {
updateScore();
console.log(humanScore)
console.log(computerScore)
}
<button onclick="showScore()">Click</button>
Woking Demo : https://jsfiddle.net/6v25y9qd/
Push click and show console

Because you're new, and I think #Onur Özkır is on to something, I will give some guidelines instead.
I understand that you mostly trying out to see if things works, and will refactor afterwards, but I recommend that you create methods that does only one thing. You already done that with generateTarget(), but if I look at compareGuesses(), that method doesn't just compare guesses. It also reads and generates numbers. I would instead read the values in updateScore() and then add them as parameters in compareGuesses.
By restricting your methods to only do one thing will make your code more readable, your methods will be smaller so they are easier to grasp, and the code is easier to debug.
I would also like to suggest that you only return a value at the end of the method, and always return (unless you can fit everything on one row) using a variable.
I also don't like switches in javascript, because the forced use of return. Would rather use ifs statement or a shorthand if statements, using conditional/ternary operator.
Use method names and variables to explain the code (ex. the constant HUMAN_WON in the code below). Try to avoid comments as far as possible. Comments should, IMHO, only be used if you generate a documentation. I suggest that you get your hands on Clean Code, which was a revelation for me to read, even as an experienced programmer.
I will refactor your code as a suggestion of how it can look like:
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
};
let displayCurrentScore = () => {
updateScore();
console.log(`${humanScore} vs ${computerScore}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">
You can even go one step further refactoring readGuesses() from updateScore() and separate updating UI—displayCurrentScore()—from handling logic in updateScore().
let humanScore = 0;
let computerScore = 0;
let currentRoundNumber = 1;
const HUMAN_WON = 1, COMPUTER_WON = -1, EQUAL = 0;
const generateTarget = () => {
return Math.floor(Math.random() * 10);
};
const readHumanGuess = () => {
return 1; // replace with appropriate code
}
const generateComputerGuess = () => {
return 2; // replace with generateTarget();
}
const readGuesses = () => {
let humanGuess = readHumanGuess();
let computerGuess = generateComputerGuess();
let secretTargetNumber = generateTarget();
return [humanGuess, computerGuess, secretTargetNumber]; // returning array
}
const compareGuesses = (humanGuess, computerGuess, secretTargetNumber) => {
let result = EQUAL;
const humanTarget = Math.abs(humanGuess - secretTargetNumber);
const computerTarget = Math.abs(computerGuess - secretTargetNumber);
if (humanTarget < computerTarget) {
result = HUMAN_WON;
} else if (computerTarget < humanTarget) {
result = COMPUTER_WON;
}
return result;
};
let updateScore = (humanGuess, computerGuess, secretTargetNumber) => {
let whoWon = compareGuesses(humanGuess, computerGuess, secretTargetNumber);
if (whoWon == HUMAN_WON) {
humanScore++;
} else if (whoWon == COMPUTER_WON) {
computerScore++;
}
return {'human': humanScore, 'computer': computerScore};
};
let displayCurrentScore = () => {
let [humanGuess, computerGuess, secretTargetNumber] = readGuesses();
let score = updateScore(humanGuess, computerGuess, secretTargetNumber);
console.log(`${score.human} vs ${score.computer}`);
}
<input type="button" onclick="displayCurrentScore()" value="Display Score">

Related

Rock, paper, scissors: empty playerOne and playerTwo variables after function calls using an EventListener(click)?

Goal
My goal is to complete a game of rock, paper, scissors. I need to compare the input of two players that are behind the same computer, a simple game. The two players give their input through the buttons on an HTML page (rock, paper or scissor) that have an EventListener on them thanks to a JavaScript file I made.
Problem
Update: after feedback from others, I declared let variables outside the function. This gives me a new problem: I end up with two empty variables. Does anyone know how I solve this issue?
const options = document.querySelectorAll(".options");
var timesClicked = 0;
console.log(options);
let playerOneInput = "";
let playerTwoInput = "";
options.forEach((option) => {
option.addEventListener("click", function () {
timesClicked++;
console.log(timesClicked);
if (timesClicked == 1) {
let playerOneInput = this.textContent;
document.getElementById("player").innerHTML = "Player 2, choose your option!"
} else {
let playerTwoInput = this.textContent;
};
console.log(playerOneInput);
console.log(playerTwoInput);
if (timesClicked == 2) {
compareInputs(playerOneInput, playerTwoInput);
}
});
});
<h1 id='player'>Player 1, choose your option!</h1>
<button class="options">Rock</button>
<button class="options">Paper</button>
<button class="options">Scissors</button>
<h1>
<div id='result'><div>
</h1>
I excluded the rest of my JS code which is the compareInputs function and result printing. Please let me know if you would like to see it. Thanks in advance!
As explained here you'd better go with a game of indexes.
Use a variable to count the number of turns let turns
Use turns % 2 to detect which player played
Use buttons with value="N" where N are also indexes 0, 1, 2
The winner logic: result = PL1 === PL2 ? 2 : (PL2 + 1) % 3 === PL1 ? 0 : 1;
Show the new title only once you increment the turn turns += 1 and that piece of logic should go last!
const ELS_options = document.querySelectorAll(".options");
const EL_title = document.querySelector("#title");
const EL_result = document.querySelector("#result");
let turns = 0; // 0 to N
const cards = ["Rock", "Paper", "Scissors"]; // Values: 0,1,2
const names = ["One", "Two"];
const resultTexts = [
`Player ${names[0]} won!`,
`Player ${names[1]} won!`,
`It's a draw!`
];
const moves = [[], []]; // 0 is for PL1, 1 is for PL2
const showResult = () => {
const player = turns % 2; // 0,1,0,1,...
if (player === 0) return EL_result.textContent = "";
// Else....
const round = Math.floor(turns / 2);
// Collect both player moves
const PL1 = moves[0][round];
const PL2 = moves[1][round];
// Get the result: //stackoverflow.com/a/53983473/383904
const result = PL1 === PL2 ? 2 : (PL2 + 1) % 3 === PL1 ? 0 : 1;
EL_result.innerHTML = `
<div>Player ${names[0]} played: ${cards[PL1]}</div>
<div>Player ${names[1]} played: ${cards[PL2]}</div>
<h1>${resultTexts[result]}</h1>
`;
};
const showTitle = () => {
const player = turns % 2; // 0,1,0,1,...
EL_title.textContent = `Player ${names[player]}, choose your move!`;
};
const onSelect = (evt) => {
const player = turns % 2; // 0,1,0,1,...
const move = parseInt(evt.currentTarget.value, 10); // 0,1,2
moves[player].push(move); // Store the move
showResult();
turns += 1; // Advance turn
showTitle();
};
// INIT APP:
ELS_options.forEach(EL => EL.addEventListener("click", onSelect));
showTitle();
<h2 id='title'></h2>
<button value="0" class="options" type="button">Rock</button>
<button value="1" class="options" type="button">Paper</button>
<button value="2" class="options" type="button">Scissors</button>
<div id='result'></div>
The variable is undefined because you create it inside a function. Try declaring the variable outside the function and changing this global variable inside the function
let inputPlayer1 = "";
function onInput() {
inputPlayer1 = "rock"; // the selected type
}

How do I switch the running codes using the IF?

Bear with me, I just started learning JS yesterday trying to make a HTML clock by putting multiple tutorials' results together.
I made two looping animations using 2 arrays, with the intent of switching between arrays depending on if it's earlier or later than 8pm. I would like for my code to constantly check if it's 8pm every X amount of seconds, and only re-run the script if the IF result or output is different than what it currently is.
const now = new Date();
if (now.getHours() > 20) { // Time checker!!!!!
var hat = ['A','B','C','D'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
} else {
var hat = ['1','2','3','4'],
a = -1;
(function f(){
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
setTimeout(f, 1000);
})();
}
I have tried setInterval however it re-runs the script even if the IF result has not changed, and messes up the animation.
I.E - if it's 6pm, it tries to play the animation from the start every 1 second and the frames get messed up.
Any advice or help would be great, thanks!
I tried to save your code.
const checkTimeDelay = 1000;
let isAbove8PM = null;
let curTimeHandler = null;
let intervalId = null;
// checking if is above 8 pm
const checkTime = () => {
const now = new Date();
if (now.getHours() > 20) {
return true;
}
return false;
};
const above8PMHandler = () => {
var hat = ['A','B','C','D'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
const before8PMHandler = () => {
var hat = ['1','2','3','4'],
a = -1;
return () => {
a = (a + 1) % hat.length;
const hatformatted = `${(hat[ a ])}`;
document.querySelector(".main").textContent = hatformatted;
// setTimeout(f, 1000);
};
};
// restart clock interval on based on new handler (above8PMHandler|before8PMHandler)
const rebaseClockInterval = () => {
clearInterval(intervalId);
intervalId = setInterval(curTimeHandler, 1000);
};
// main func, checks if we should change clocks handler (above8PMHandler|before8PMHandler)
const clockTick = () => {
const curTimeChecked = checkTime();
if (curTimeChecked === isAbove8PM) { return; }
isAbove8PM = curTimeChecked;
if (isAbove8PM) {
curTimeHandler = above8PMHandler();
} else {
curTimeHandler = before8PMHandler();
}
curTimeHandler();
rebaseClockInterval();
};
// start main func
setInterval(clockTick, checkTimeDelay);
I also provide some ideas here.
function setClockInterval() {
const hat1 = ['A', 'B', 'C', 'D'];
const hat2 = ['1', '2', '3', '4'];
let prevCheck = null;
let count = 0;
const checker = () => {
return new Date().getSeconds() > 20;
};
const next = () => {
count++;
};
const reset = () => {
count = 0;
};
const render = (content) => {
// console.log(`clockInterval ${content}`); // debug output
document.querySelector(".main").textContent = content;
};
const fn = () => {
const check = checker();
const arr = check ? hat1 : hat2;
// empty arr skip
if (arr.length <= 0)
return;
// restart count to 0
if (prevCheck !== null && prevCheck !== check)
reset();
render(arr[count % arr.length]);
prevCheck = check;
next();
};
return setInterval(fn, 1000);
}
// start interval
const clock = setClockInterval();
// stop
clearInterval(clock);
You can greatly simplify your code by removing everything from inside the if block that is repeated and running it afterward. You also need to get a new Date on each iteration, otherwise the array won't change when it gets to the designated time.
I have changed the condition check to be odd/even seconds to show how it swaps between arrays without losing the index.
// Global, could be kept inside closure
let a = -1;
// Function to run each iteration
(function f() {
// OP code
// let hat = new Date().getHours() > 18? ['A','B','C','D'] : ['1','2','3','4'];
// faster iteration as example
let hat = new Date().getSeconds() % 2? ['A','B','C','D'] :['1','2','3','4'];
a = (a + 1) % hat.length;
document.querySelector(".main").textContent = hat[a];
setTimeout(f, 1000);
})();
<div class="main"></div>

Discord JS function returning undefined

I'm building a Discord bot using a collector and am trying to collect votes for rounds of a game. However, the bot keeps returning the wrong values. It will usually return either undefined or [object Object]. The stringifier() function should be returning the name of a round but it's instead returning undefined. e.g. if I input "spleef" on Discord it should output "Spleef" to console and in Discord, but it returns undefined in both or just errors.
UPDATE: i found that the variables were returning boolean values (the variables are battleBoxVotes to cTFVotes).
UPDATE A LOT LATER: so I fixed the problem but my new problem now is that I can't get variables bbv to ctfv to not return an error if they don't have a value. Console logs this: (node:8700) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'content' of undefined
const filter = m => (m.author.id != client.user.id);
const channel = message.channel;
const collector = channel.createMessageCollector(filter, { time: 5000 });
collector.on('collect', m => console.log(`Collected ${m.content}`));
collector.on('end', async collected => {
var bb = collected.find(collected => collected.content === 'battle box');
var pw = collected.find(collected => collected.content === 'spleef');
var s = collected.find(collected => collected.content === 'spleef');
var sw = collected.find(collected => collected.content === 'skywars');
var ctf = collected.find(collected => collected.content === 'capture the flag');
const bbv = bb.content || null;
const pwv = pw.content || null;
const sv = s.content || null;
const swv = sw.content || null;
const ctfv = ctf.content || null;
const stringifier = function(a, b, c, d, e) {
let results;
if (a>b&&a>c&&a>d&&a>e) {results = "Battle Box"}
else if (b>a&&b>c&&b>d&&b>e) {results = "Parkour Warrior"}
else if (c>a&&c>b&&c>d&&c>e) {results = "Spleef"}
else if (d>a&&d>b&&d>c&&d>e) {results = "SkyWars"}
else if (e>a&&e>b&&e>c&&e>c) {results = "Capture the Flag"}
return results;
}
message.channel.send(`And the winner is... ${stringifier(bbv, pwv, sv, swv, ctfv)}!`),
console.log(stringifier(bbv, pwv, sv, swv, ctfv))
});
The logic of that comparison absolutely breaks my brain and is a pain to read in the first place. Here's an adapted version that should work a bit better.
This solution iterates through the recieved messages and increments a counter for each gamemode depending on a switch-case expression. (bear in mind this doesn't stop a user from simply spamming whichever gamemode they want...)
Credit for the getAllIndexes function (used to determine ties)
const filter = m => (m.author.id != client.user.id);
const channel = message.channel;
const collector = channel.createMessageCollector(filter, { time: 5000 });
collector.on('collect', m => console.log(`Collected ${m.content}`));
collector.on('end', async collected => {
let msgs = Array.from(collected.keys()).map(m=>m?.content.toLowerCase().trim());
let modes = [ "Battle Box", "Parkour Warrior", "Spleef", "SkyWars", "Capture the Flag" ] // Define the names of the GameModes
let scores = [ 0, 0, 0, 0, 0 ] // Set up the default scores
msgs.forEach(m => {
switch(m) {
case "bb": // Fallthrough case for aliases
case "battlebox":
case "battle box":
scores[0]++; // Increment BattleBox (0) Counter
break;
case "pw":
case "parkour":
case "parkour warrior":
scores[1]++; // Increment ParkourWarrior (1) counter
break;
case "spleef":
scores[2]++; // Increment Spleef (2) counter
break;
case "sw":
case "sky":
case "skywars":
scores[3]++; // Increment SkyWars (3) counter
break;
case "ctf":
case "capture the flag":
scores[4]++; // Increment CaptureTheFlag (4) counter
break;
});
// Now to find who won...
let winningCount = Math.max(scores);
let winningIndexes = getAllIndexes(scores, winningCount);
if(winningIndexes.length = 1) { // Single Winner
message.channel.send(`And the winner is... ${modes[winningIndexes[0]]}!`);
} else { // tie!
message.channel.send(`It's a tie! There were ${winningIndexes.length} winners. (${winningIndexes.map(i=>modes[i]).join(", ")})`);
}
j});
// Get All Indexes function...
function getAllIndexes(arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val) indexes.push(i);
return indexes;
}

Problem with Animating Number Counter on Javascript

I was hoping to create a counter which would increment to the eventual number of followers. I have other code, but I just included the part that would affect the incrementation. Currently, when I run the program the HTML file only displays the final number of followers, and the word "Followers" showing it is able to get the proper number, but it isn't able to have an incrementation animation as I would like. How would I go about fixing this?
var text_field = document.getElementById('followers');
fetch(api)
.then((response) => {
return response.json();
})
.then((data) => {
var number = data['Count'][0][0];
const updateCount = () => {
const target = number;
const count = text_field.innerText;
const increment = target / speed;
if (count < target) {
text_field.innerText = count + increment;
setTimeout(updateCount, 5);
} else {
text_field.innerText = target + ' Followers';
}
};
updateCount();
});
The innerText property returns a string value. Use the parseInt function before any calculations.
var text_field = document.getElementById("followers");
function counter(){
var number = 100;
const updateCount = () => {
const target = number;
const count = parseInt(text_field.innerText); //parsing
const speed=number;
const increment = target / speed;
if (count < target) {
text_field.innerText = count + increment;
setTimeout(updateCount, 5);
} else {
text_field.innerText = target;
}
};
updateCount();
}
counter();
<div id="followers">1</div> Followers!!!

How do I implement a random number for my guessing game that doesn't keep changing until the user guesses it?

Every time I click "Confirm," it generates a new random number, so you can't actually guess it. And how do I display the number of tries the user has attempted guessing the number? Please help as I have been stuck on this for hours. Thanks!
const Home = () => {
const [enteredValue, setEnteredValue] = useState("");
const [confirmed, setConfirmed] = useState(false);
const [selectedNumber, setSelectedNumber] = useState();
const input = inputText => {
setEnteredValue(inputText.replace(/[^0-9]/g, ""));
};
const reset = () => {
setEnteredValue("");
setConfirmed(false);
};
const confirm = () => {
const chosenNum = parseInt(enteredValue);
setConfirmed(true);
setSelectedNumber(chosenNum);
setEnteredValue("");
let x = Math.floor(Math.random() * 100) + 1;
let count = 0;
if (!enteredValue) {
Alert.alert("Please Enter a Number");
} else if (chosenNum > x) {
Alert.alert("Guess Lower");
count+=1
} else if (chosenNum < x) {
Alert.alert("Guess Higher");
count+=1
} else if (chosenNum == x) {
Alert.alert("You Guessed Correctly");
}
};
let confirmedOutput;
if (confirmed) {
confirmedOutput = (
<View>
<Text style={styles.output}>Chosen Number: {selectedNumber}</Text>
<Text>Tries: </Text>
</View>
);
}
You're generating the x number inside the confirm function. So each time user guess (correct or not) x will be changed.
You should bring this:
let x = Math.floor(Math.random() * 100) + 1;
let count = 0;
out the function, somewhere when the game start, it'll be called.
And re-gen new x and reset count, when user guesses correct:
// ...
} else if (chosenNum == x) {
Alert.alert("You Guessed Correctly");
x = Math.floor(Math.random() * 100) + 1;
count = 0;
}
count is the user tries atempt, show it in view.

Categories

Resources