I'm trying to understand why my code works well on Firefox and not on Chrome.
Basically what happens is that on Firefox the loop works and it prints the outputs on the page at every iteration and at the end.
On Chrome it only prints some of the outputs at the end of the loop.
I read that it might have to do with the way I'm asking the code to print the output on the page, which is .textContent, but I also tried to use .innerHtml and the problem persists.
The code is a bit long and I'm sure there is a shorter cleaner way to write, but it is my first project and this is the best I could do at this stage.
Thank you for your help :)
Here is what the html looks like:
const forma = document.querySelector('form');
const out0 = document.getElementById('user-choice');
const out1 = document.getElementById('computer-choice');
const out2 = document.getElementById('game-result');
const out3 = document.getElementById('user-score');
const out4 = document.getElementById('computer-score');
const out5 = document.getElementById('final-result');
// get a ramdom choice between Rock-paper-scissor from Computer
let choices = ['rock', 'paper', 'scissors'];
let randomValue = function computerPlay() {
let randomChoice = choices[Math.floor(Math.random() * choices.length)];
out1.textContent = randomChoice;
return randomChoice;
};
function game() {
let userScore = 0;
let computerScore = 0;
// iterate the function playRound 5 times with a for loop
for (let i = 0; i < 5; i++) {
// prompt an initial message "Rock, paper, scissor" to ask the user to input one of the 3
let sign = prompt("Rock, paper or scissors?");
// use a function to compare the random choice from computer with what the user has input in the prompt and return a result
function playRound(playerSelection, computerSelection) {
if (playerSelection == "rock" && computerSelection == choices[0]) {
i = i -1;
return "It's a tie! Play again!";
} else if (playerSelection == "rock" && computerSelection == choices[1]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
// this is when the computer wins
if(computerScore == 3) {
i = 5; // so that it practically breaks out of the loop
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Paper beats rock.";
} else if (playerSelection == "rock" && computerSelection == choices[2]) {
userScore = userScore + 1;
out3.textContent = userScore;
if(userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Rock beats scissors.";
} else if (playerSelection == "paper" && computerSelection == choices[0]) {
userScore = userScore + 1;
out3.textContent = userScore;
if(userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Paper beats rock.";
} else if (playerSelection == "paper" && computerSelection == choices[1]) {
i = i -1;
return "It's a tie! Play again!";
} else if (playerSelection == "paper" && computerSelection == choices[2]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
if (computerScore == 3) {
i = 5;
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Scissors beat paper.";
} else if (playerSelection == "scissors" && computerSelection == choices[0]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
if (computerScore == 3) {
i = 5;
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Rock beats scissors.";
} else if (playerSelection == "scissors" && computerSelection == choices[1]) {
userScore = userScore + 1;
out3.textContent = userScore;
if(userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Scissors beat paper.";
} else if (playerSelection == "scissors" && computerSelection == choices[2]) {
i = i -1;
return "It's a tie! Play again!";
// this currently doesn't work as it tries to convert the playerSelection toLowerCase, as requested in the let playerSelection = sign.toLowerCase(), but it cannot because the sign is null and so it returns an error that sign is null
} else if(playerSelection === '' || playerSelection === null) {
i = 0;
} else {
i = i -1;
return "I think you forgot how to play this game!";
}
}
// store the playerSelection argument value (equal to user input made lower case) in a variable
let playerSelection = sign.toLowerCase();
// store the computerSelection argument value (equal to radom choice determined by function randomValue) in a variable
let computerSelection = randomValue();
// print the user input made to lower case in the paragraph tag
out0.textContent = sign;
// print the return statement from the function in the out2 tag
out2.textContent= playRound(playerSelection, computerSelection);
}
}
// run the function
game();
And this is my Html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<form>
<strong>Your choice:</strong>
<output type="text" id="user-choice"></output>
</form>
</div>
<div>
<form>
<strong>Computer choice:</strong>
<output type="text" id="computer-choice"></output>
</form>
</div>
<div>
<form>
<strong>Result of this round:</strong>
<output type="text" id="game-result"></output>
</form>
</div>
<div>
<form>
<strong>User score:</strong>
<output type="number" id="user-score"></output>
</form>
</div>
<div>
<form>
<strong>Computer score:</strong>
<output type="number" id="computer-score"></output>
</form>
</div>
<div>
<form>
<strong>Game result:</strong>
<output type="text" id="final-result"></output>
</form>
</div>
<script src="script.js"></script>
</body>
</html>
You can use window.requestAnimationFrame to force the browser to render something. You will need to promisify it however, because requestAnimationFrame has a callback, and does not directly return a promise.
After doing that, your code should look like this:
const forma = document.querySelector('form');
const out0 = document.getElementById('user-choice');
const out1 = document.getElementById('computer-choice');
const out2 = document.getElementById('game-result');
const out3 = document.getElementById('user-score');
const out4 = document.getElementById('computer-score');
const out5 = document.getElementById('final-result');
// get a ramdom choice between Rock-paper-scissor from Computer
let choices = ['rock', 'paper', 'scissors'];
let userScore = 0;
let computerScore = 0;
let randomValue = function computerPlay() {
let randomChoice = choices[Math.floor(Math.random() * choices.length)];
out1.textContent = randomChoice;
return randomChoice;
};
async function game() {
// iterate the function playRound 5 times with a for loop
for (let i = 0; i < 5; i++) {
// prompt an initial message "Rock, paper, scissor" to ask the user to input one of the 3
let sign = prompt("Rock, paper or scissors?");
// use a function to compare the random choice from computer with what the user has input in the prompt and return a result
function playRound(playerSelection, computerSelection) {
if (playerSelection == "rock" && computerSelection == choices[0]) {
i = i - 1;
return "It's a tie! Play again!";
} else if (playerSelection == "rock" && computerSelection == choices[1]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
// this is when the computer wins
if (computerScore == 3) {
i = 5; // so that it practically breaks out of the loop
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Paper beats rock.";
} else if (playerSelection == "rock" && computerSelection == choices[2]) {
userScore = userScore + 1;
out3.textContent = userScore;
if (userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Rock beats scissors.";
} else if (playerSelection == "paper" && computerSelection == choices[0]) {
userScore = userScore + 1;
out3.textContent = userScore;
if (userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Paper beats rock.";
} else if (playerSelection == "paper" && computerSelection == choices[1]) {
i = i - 1;
return "It's a tie! Play again!";
} else if (playerSelection == "paper" && computerSelection == choices[2]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
if (computerScore == 3) {
i = 5;
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Scissors beat paper.";
} else if (playerSelection == "scissors" && computerSelection == choices[0]) {
computerScore = computerScore + 1;
out4.textContent = computerScore;
if (computerScore == 3) {
i = 5;
out5.textContent = "Unfortunately you lost the game :("
} else return "You lose this round! Rock beats scissors.";
} else if (playerSelection == "scissors" && computerSelection == choices[1]) {
userScore = userScore + 1;
out3.textContent = userScore;
if (userScore == 3) {
i = 5;
out5.textContent = "Congratulations, you won the game!"
} else return "You win this round! Scissors beat paper.";
} else if (playerSelection == "scissors" && computerSelection == choices[2]) {
i = i - 1;
return "It's a tie! Play again!";
// this currently doesn't work as it tries to convert the playerSelection toLowerCase, as requested in the let playerSelection = sign.toLowerCase(), but it cannot because the sign is null and so it returns an error that sign is null
} else if (playerSelection === '' || playerSelection === null) {
i = 0;
} else {
i = i - 1;
return "I think you forgot how to play this game!";
}
}
// store the playerSelection argument value (equal to user input made lower case) in a variable
let playerSelection = sign.toLowerCase();
// store the computerSelection argument value (equal to radom choice determined by function randomValue) in a variable
let computerSelection = randomValue();
// print the user input made to lower case in the paragraph tag
out0.textContent = sign;
// print the return statement from the function in the out2 tag
out2.textContent = playRound(playerSelection, computerSelection);
await promisifiedRequestAnimationFrame();
}
}
function promisifiedRequestAnimationFrame() {
return new Promise((resolve, reject) => {
window.requestAnimationFrame(() => {resolve()});
})
}
// run the function
game();
So what exactly changed?
We added a function, that returns a promise that resolves when the requestAnimationFrame is finished executing.
We made game() asynchronous. This allows us to use "await"
But why does it work?
Well, alerts, prompts and confirms are supposed to halt the code until a user does something. Firefox does not allow direct spamming of them, so there is a small time frame between your prompts on FF, but Chrome doesn't really care about that. You want a lot of prompts? Fine! By using window.requestAnimationFrame combined with await we will force chrome to wait until a frame has been drawn.
Related
I am trying to call a function with a specific parameter when button is clicked but it just won't work. Functions playRock and playRound work when tested in console but not with event listener. Please let me know what the problem is, I spent 8h trying to make it work.
It may have something to do with my lack of understanding how callback functions work. I could really use an example on how to call function playRound('rock') when button is pressed.
All examples I found online would have functions without parameters in them or a confusing callback functions.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="rockbtn">Rock</button>
<button id="papertn">Paper</button>
<button id="scissorsbtn">Scissors</button>
<script>
// Call PlayRock upon clicking button #rockbtn
const rockbtn = document.querySelector('#rockbtn');
rockbtn.addEventListener('click', playRock);
// Call function playRound with propery 'rock'
function playRock() {
result = playRound('rock');
return result
}
// Randomly selects computer's choice out of rock, paper or scissors
function computerPlay() {
const choices = ['rock', 'paper', 'scissors'];
let choice = choices[Math.floor(Math.random()*choices.length)];
return choice
}
// Plays round of rock, paper, scissors between computer and player
function playRound(playerSelection) {
playerSelection = playerSelection.toLowerCase();
computerSelection = computerPlay();
let result;
if (playerSelection !== 'rock' & playerSelection !== 'paper' & playerSelection !== 'scissors'){
result = 'There is no such choice. Please choose either rock, paper or scissors.';
} else if (playerSelection === computerSelection) {
result = 'It is a draw!';
} else if (playerSelection === 'rock' & computerSelection === 'paper') {
result = 'You lost! Paper beats rock.';
} else if (playerSelection === 'rock' & computerSelection === 'scissors') {
result = 'You won! Rock beats scissors.';
} else if (playerSelection === 'paper' & computerSelection === 'scissors') {
result = 'You lost! Scissors beat paper.';
} else if (playerSelection === 'paper' & computerSelection === 'rock') {
result = 'You won! Paper beats rock.';
} else if (playerSelection === 'scissors' & computerSelection === 'paper') {
result = 'You won! Scissors beat paper.';
} else if (playerSelection === 'scissors' & computerSelection === 'rock') {
result = 'You lost! Rock beats scissors.';
}
return result
}
/* function game() {
let playerScore = 0;
let computerScore = 0;
let finalResult;
for (let i = 0; i < 5; i++) {
let outcome = playRound();
if (roundResult = outcome.includes('won')) {
playerScore += 1;
console.log('You won this round!');
} else if (roundResult = outcome.includes('lost')) {
computerScore += 1;
console.log('You won this round!');
} else {
console.log('This round ended in a draw!');
}
}
if (playerScore > computerScore) {
finalResult = `Congratulations! You won ${playerScore} to ${computerScore}!`;
} else {
finalResult = `You lost ${playerScore} to ${computerScore}`;
}
return finalResult;
}
*/
</script>
</body>
</html>
// Call PlayRock upon clicking button #rockbtn
const rockbtn = document.querySelector('#rockbtn');
rockbtn.addEventListener('click', playRock);
// Call function playRound with propery 'rock'
function playRock() {
result = playRound('rock');
return result
}
// Randomly selects computer's choice out of rock, paper or scissors
function computerPlay() {
const choices = ['rock', 'paper', 'scissors'];
let choice = choices[Math.floor(Math.random() * choices.length)];
return choice
}
// Plays round of rock, paper, scissors between computer and player
function playRound(playerSelection) {
playerSelection = playerSelection.toLowerCase();
computerSelection = computerPlay();
let result;
if (playerSelection !== 'rock' & playerSelection !== 'paper' & playerSelection !== 'scissors') {
result = 'There is no such choice. Please choose either rock, paper or scissors.';
} else if (playerSelection === computerSelection) {
result = 'It is a draw!';
} else if (playerSelection === 'rock' & computerSelection === 'paper') {
result = 'You lost! Paper beats rock.';
} else if (playerSelection === 'rock' & computerSelection === 'scissors') {
result = 'You won! Rock beats scissors.';
} else if (playerSelection === 'paper' & computerSelection === 'scissors') {
result = 'You lost! Scissors beat paper.';
} else if (playerSelection === 'paper' & computerSelection === 'rock') {
result = 'You won! Paper beats rock.';
} else if (playerSelection === 'scissors' & computerSelection === 'paper') {
result = 'You won! Scissors beat paper.';
} else if (playerSelection === 'scissors' & computerSelection === 'rock') {
result = 'You lost! Rock beats scissors.';
}
return result
}
/* function game() {
let playerScore = 0;
let computerScore = 0;
let finalResult;
for (let i = 0; i < 5; i++) {
let outcome = playRound();
if (roundResult = outcome.includes('won')) {
playerScore += 1;
console.log('You won this round!');
} else if (roundResult = outcome.includes('lost')) {
computerScore += 1;
console.log('You won this round!');
} else {
console.log('This round ended in a draw!');
}
}
if (playerScore > computerScore) {
finalResult = `Congratulations! You won ${playerScore} to ${computerScore}!`;
} else {
finalResult = `You lost ${playerScore} to ${computerScore}`;
}
return finalResult;
}
*/
<button id="rockbtn">Rock</button>
<button id="papertn">Paper</button>
<button id="scissorsbtn">Scissors</button>
In functions, when you return something, that is just passing that data to the caller of that function. It doesn't show it to the user.
In the below example, the user will not have any clue that aa was returned as it isn't being shown or alerted in anyway.
function test(){
return test2("aa");
}
function test2(str){
return str;
}
For learning, at the end of function playRound(playerSelection) {
just add alert(result);
That will just popup a message to the user telling them the result. There are many other ways to do this, this is just the easiest for learning.
you can also use console.log(result); to show the results in the console.
In the below code, I add a class to all of the buttons, and use a data attribute to hold the button's action (ie rock, paper, scissors).
Then in the javascript I loop through the buttons and add an event handler to each that grabs that data attribute and passes it to playRound.
For testing, I didn't use your for playRound function, mine is for demo purposes only.
let btns = document.querySelectorAll(".btn");
function playRound(action){
console.log(action)
}
btns.forEach(function(el){
el.addEventListener("click",function(e){
playRound(e.target.getAttribute("data-action"));
});
});
<button class="btn" data-action="rock">Rock</button>
<button class="btn" data-action="paper">Paper</button>
<button class="btn" data-action="scissors">Scissors</button>
As you can tell by my messy code, I am still a beginner at JavaScript so I'm really sorry If this will hurt your eyes.
I am working on this Rock, Paper, Scissors project from The Odin Project where we would add a simple UI to it by applying DOM Methods. To be honest, I really don't know if I'm doing this right. I feel like the if statements shouldn't be inside the event listener but this is the only way I have found to make the tallying of scores work. By putting the code here I made it playable, but not quite right:
let playerScore = 0;
let computerScore = 0;
let scores = document.createElement('p');
let body = document.querySelector('body');
const results = document.createElement('div');
body.appendChild(results);
const buttons = document.querySelectorAll('button');
buttons.forEach((button) => {
button.addEventListener('click', () => {
let playerSelection = button.className;
let computerSelection = computerPlay();
let roundResult = playRound(playerSelection, computerSelection);
console.log(roundResult);
score();
gameEnd();
if (roundResult === 'playerWin') {
playerScore++;
} else if (roundResult === 'computerWin') {
computerScore++;
}
})
})
//computer pick
function computerPlay() {
const pick = ['rock', 'paper', 'scissors'];
return pick[Math.floor(Math.random() * pick.length)];
}
// Round Play
function playRound(playerSelection, computerSelection) {
//message that specifies the winner
let tie = `It's a tie you both picked ${playerSelection}`;
let playerWin = `You win this round! ${playerSelection} beats ${computerSelection}`;
let computerWin = `You lose this round! ${computerSelection} beats
${playerSelection}`;
if(playerSelection === computerSelection) {
results.innerHTML = tie;
return 'tie';
} else if (playerSelection === 'rock' && computerSelection === 'scisors') {
results.innerHTML = playerWin;
return 'playerWin';
} else if (playerSelection === 'paper' && computerSelection === 'rock') {
results.innerHTML = playerWin;
return 'playerWin';
} else if (playerSelection === 'scissors' && computerSelection === 'paper') {
results.innerHTML = playerWin;
return 'playerWin';
} else {
results.innerHTML = computerWin;
return 'computerWin';
}
}
function score() {
//new element where score would be seen
scores.innerHTML = `player: ${playerScore} | computer: ${computerScore}`;
body.appendChild(scores);
}
function gameEnd() {
if(playerScore === 5 || computerScore === 5) {
document.querySelector('.rock').disabled = true;
document.querySelector('.paper').disabled = true;
document.querySelector('.scissors').disabled = true;
if (playerScore > computerScore) {
alert('You win the game');
} else if (computerScore > playerScore) {
alert('Aww you lose');
}
}
}
<button class="rock">Rock</button>
<button class="paper">Paper</button>
<button class="scissors">Scissors</button>
Here's the problem, scores remain both at 0 after the first round. It would show who the winner is but it won't tally its score until I have picked for the next round. Where exactly did I go wrong with this one? (feels like in everything I'm genuinely sorry if my explanation sounds as confusing as my code.)
Anyways this is what the initial code looks like, before applying the DOM Methods.
I was initially trying to use this code but I cant even tally the scores with this one because I can't seem to get the return value of of the function playRound().
function computerPlay() {
const pick = ['rock', 'paper', 'scissors'];
return pick[Math.floor(Math.random() * pick.length)];
}
function playRound(playerSelection, computerSelection) {
if (playerSelection === computerSelection) {
alert(`It's a tie! you both picked ${playerSelection}`);
return "tie";
} else if (playerSelection !== "rock" && playerSelection !== "paper" &&
playerSelection !== "scissors"){
alert(`You sure about using ${playerSelection} on a game of "Rock, Paper,
Scissors"?`)
} else if (playerSelection === "rock" && computerSelection === "scissors") {
alert(`You win this round! ${playerSelection} beats ${computerSelection}`);
return "playerWin";
} else if (playerSelection === "paper" && computerSelection === "rock") {
alert(`You win this round! ${playerSelection} beats ${computerSelection}`);
return "playerWin";
} else if (playerSelection === "scissors" && computerSelection === "paper") {
alert(`You win this! ${playerSelection} beats ${computerSelection}`);
return "playerWin";
} else {
alert(`You lose this round! ${computerSelection} beats ${playerSelection}`);
return "botWin";
}
}
const computerSelection = computerPlay();
// to loop the game until 5 rounds
function game() {
let playerScore = 0;
let botScore = 0;
let gameWinner = '';
for (let i = 0; i < 5; i++) {
let playerSelection = prompt(`Round ${i+1}: Choose among "Rock, Paper, Scissors"
as your weapon`).toLowerCase();
let roundResult = playRound(playerSelection, computerPlay());
if (roundResult === "playerWin" ) {
playerScore++;
} else if (roundResult === "botWin" ) {
botScore++;
}
}
if (playerScore > botScore) {
gameWinner = 'You win!';
} else if (botScore > playerScore) {
gameWinner = 'You lose, Computer wins!';
} else {
gameWinner = 'Draw';
}
alert(`Player: ${playerScore} | Bot: ${botScore}`);
if (gameWinner === 'Draw') {
alert("There is no match winner, draw!");
} else {
alert(`${gameWinner}`);
}
}
game();
between these codes which is more likely to be fixed? or would it be better to completely throw this code and just start anew?
The problem is in this part of the code:
score();
gameEnd();
if (roundResult === 'playerWin') {
playerScore++;
} else if (roundResult === 'computerWin') {
computerScore++;
}
score() will update the score in the HTML page, but at that moment the scores have not been updated yet. That only happens later in that if ... else if block.
So the solution is to first update the score, and then to call score():
score();
gameEnd();
if (roundResult === 'playerWin') {
playerScore++;
} else if (roundResult === 'computerWin') {
computerScore++;
}
There is another issue related to this: at the end of the game (when a player reaches 5 points), gameEnd() will call alert. But alert does not allow the page to actually display the latest changes. Instead it blocks any update to it. I would display the game-over message in an HTML element instead of in an alert, just like you already do for the scores. Alternatively, you could delay the execution of alert with a timer, but I would just avoid using alert.
Here is what you can do in the function gameEnd where you currently use alert:
if (playerScore > computerScore) {
results.innerHTML += '<p><b>You win the game</b>';
} else if (computerScore > playerScore) {
results.innerHTML += '<p><b>Aww you lose</b>';
}
I am working on the Odin RPS game that determines the winner based on the first to 5 wins. I have a function that declares the winner via an alert after they hit 5 wins, however, the alert message pops up first and declares the winner before the score increments to its final display of 5 wins. Can anyone explain why? I have the gameEnd function after the keepScore function. I also tried adding the keepScore function within each result of the gamePlay function but the alert always displays first declaring the winner before the score increments to 5. I also have to click the game again to get the counter to reset the scores to 0 when the function tells it to reset to 0 when the gameEnd function runs. JS code below (also I know the winner is always declared the computer. I will change this after I get the function working...)
let playerScore = 0;
let computerScore = 0;
const computerChoice = document.getElementById("computerChoice")
const playerChoice = document.getElementById("playerChoice")
const result = document.getElementById("result")
const playerScoreCum = document.getElementById("playerScore")
const computerScoreCum = document.getElementById("computerScore")
let playerSelection
let computerSelection
let results
const possibleChoices = document.querySelectorAll('button.btn[data-selection]')
possibleChoices.forEach(possibleChoice => possibleChoice.addEventListener('click', (e) => {
playerSelection = e.target.getAttribute('data-selection');
playerChoice.textContent = playerSelection;
computerPlay();
gamePlay();
keepScore();
gameEnd();
}))
function computerPlay () {
let computerOptions = ["rock", "paper", "scissors"];
computerSelection = computerOptions [Math.floor(Math.random() * computerOptions.length)];
computerChoice.textContent = computerSelection
}
function gamePlay () {
if (playerSelection == "rock" && computerSelection == "scissors")
{
results = "You won!";
++playerScore;
}
else if (playerSelection == "rock" && computerSelection == "paper")
{
results = "You lost!";
++computerScore;
}
else if (playerSelection == "paper" && computerSelection == "scissors")
{
results = "You lost!";
++computerScore;
}
else if (playerSelection == "paper" && computerSelection == "rock")
{
results = "You won!";
++playerScore;
}
else if (playerSelection == "scissors" && computerSelection == "paper")
{
results = "You won!";
++playerScore;
}
else if (playerSelection == "scissors" && computerSelection == "rock")
{
results = "You lost!";
++computerScore;
}
else {results = "It's a tie!!!"}
}
function keepScore () {
result.textContent = results
playerScoreCum.textContent = playerScore
computerScoreCum.textContent = computerScore
}
function gameEnd () {
if (playerScore === 5 || computerScore === 5) {
playerScore = 0;
computerScore = 0
alert("Computer won the game!!!")
}
}
There's a hacky workaround for that - you could use setTimeout(gameEnd, 0) where you are calling the gameEnd function. This is because setTimeout() itself gets called synchronously, and placed on the callstack right after keepScore().
I haven't myself tried this yet though.
Goal is to play five rounds.
For each round, player chooses action by clicking one of three buttons (rock, paper, or scissors), the computer chooses an action randomly, and the outcome of that round is logged.
However, my code ends up taking the player's first action, and then simulating five rounds against computer using the same player action for all five rounds.
let playerScore = 0;
let computerScore = 0;
let i = 0;
while (i < 5) {
document.querySelectorAll('.action').forEach(button => {
button.addEventListener('click', e => {
const outcome = game(e.target.id);
if (outcome === -1)
computerScore += 1;
if (outcome === 1)
playerScore += 1;
});
});
i += 1;
}
if (i == 4) {
console.log("Player score: ", playerScore);
console.log("Computer score: ", computerScore);
}
function computerPlay() {
const turnOutcome = Math.floor(Math.random() * 3);
switch (turnOutcome) {
case 0:
return "rock";
break;
case 1:
return "paper";
break;
case 2:
return "scissors";
break;
}
}
function playRound(playerSelection, computerSelection) {
playerSelection = playerSelection.toLowerCase();
computerSelection = computerSelection.toLowerCase();
if (playerSelection === "rock" && computerSelection === "paper")
return -1;
if (playerSelection === "paper" && computerSelection === "scissors")
return -1;
if (playerSelection === "scissors" && computerSelection === "rock")
return -1;
if (playerSelection === "rock" && computerSelection === "scissors")
return 1;
if (playerSelection === "paper" && computerSelection === "rock")
return 1;
if (playerSelection === "scissors" && computerSelection === "paper")
return 1;
if (playerSelection === computerSelection)
return 0;
}
function game(playerSelection) {
console.log(playerSelection);
computerSelection = computerPlay();
const outcome = playRound(playerSelection, computerSelection);
console.log(outcome);
return outcome;
}
<div class="container">
<div class="action-row">
<button class="action" id="rock">Rock</button>
<button class="action" id="paper">Paper</button>
<button class="action" id="scissors">Scissors</button>
</div>
</div>
Any hints/suggestions?
Also, am not sure why it's printing out final score before finishing the for loop.
Relevant portion of the code:
let playerScore = 0;
let computerScore = 0;
let i = 0;
while (i < 5) {
document.querySelectorAll('.action').forEach(button => {
button.addEventListener('click', e => {
const outcome = game(e.target.id);
if (outcome === -1)
computerScore += 1;
if (outcome === 1)
playerScore += 1;
});
});
i += 1;
}
if (i == 4) {
console.log("Player score: ", playerScore);
console.log("Computer score: ", computerScore);
}
You shouldn't have the while loop. That's not running 5 rounds of the game, it's adding 5 listeners to each button. When you click a button, it will run all the listeners.
And the code that displays the scores is not running after they play all the games, it's running immediately after you add the listeners.
Event listeners are asynchronous, they're not like prompting for input. They don't wait for a click, they just save a function to run later when the click happens.
Add a listener to each button, and the listener should increment a global variable containing the round number. When the round goes past 5, end the game and display the score.
let playerScore = 0;
let computerScore = 0;
let round = 1;
const max_rounds = 5;
document.querySelectorAll('.action').forEach(button => {
button.addEventListener('click', e => {
if (round <= max_rounds) {
const outcome = game(e.target.id);
if (outcome === -1)
computerScore += 1;
else if (outcome === 1)
playerScore += 1;
round++;
if (round == max_rounds) {
console.log("Player score: ", playerScore);
console.log("Computer score: ", computerScore);
}
}
});
});
Sometimes when I enter "rock" in the prompt and hit OK, the console will say "Please type Rock, Paper, or Scissors" even in case I had actually done that. I believe this is due to the else clause, I'm just not sure what I did wrong.
Also, other times when I enter "rock" in the prompt and hit OK, nothing happens in the console (no score is added). Below is the screenshot
const playerSelection = ''
const computerSelection = computerPlay()
let computerScore = 0;
let playerScore = 0;
console.log(playRound(playerSelection, computerSelection))
function computerPlay(){
let values = ['rock', 'paper', 'scissors'],
valueToUse = values [Math.floor(Math.random()* values.length)];
return valueToUse;
};
function playRound(playerSelection, computerSelection) {
while(true){
playerSelection = prompt ('Pick your poison');
if (playerSelection.toLowerCase() === 'rock' && computerPlay() === 'paper'){
computerScore += 1
console.log('Sorry! Paper beats Rock')
}
else if (playerSelection.toLowerCase() === 'rock'.toLowerCase() && computerPlay() === 'scissors'){
playerScore += 1
console.log('Good job! Rock beats Scissors');
}
else
{
console.log('Please type Rock, Paper, or Scissors')
}
console.log (`User Selection: ${playerSelection.toUpperCase()} | Player Score: ${playerScore}
Computer Selection: ${computerSelection.toUpperCase()} | Computer Score: ${computerScore}`);
}
}
You only call computerSelection once, at the beginning of pageload:
const computerSelection = computerPlay()
It then proceeds to only get used in the log:
Computer Selection: ${computerSelection.toUpperCase()} |
But your tests call computerPlay again, creating new strings for the computer every time:
if (playerSelection.toLowerCase() === 'rock' && computerPlay() === 'paper'){
// function invocation ^^^^^^^^^^^^^^
computerScore += 1
console.log('Sorry! Paper beats Rock')
}
else if (playerSelection.toLowerCase() === 'rock'.toLowerCase() && computerPlay() === 'scissors'){
// function invocation ^^^^^^^^^^^^^^
In addition to that, you aren't exhaustively testing each possibility for rock-paper-scissors (like when the player picks something other than 'rock').
To start with, call computerPlay only once, then use the computerSelection variable:
if (playerSelection.toLowerCase() === 'rock' && computerSelection === 'paper') {
computerScore += 1
console.log('Sorry! Paper beats Rock')
} else if (playerSelection.toLowerCase() === 'rock' && computerSelection === 'scissors') {
Also note that there isn't much point calling toLowerCase on something that's already a lower-cased string literal - just use the plain string.
You can update the code as following
Remove all unnecessary global variable declarations.
Remove unnecessary arguments of playRound function.
Add more logic for other player selection cases.
Nest condition for computer selection cases.
playRound();
function computerPlay(){
let values = ['rock', 'paper', 'scissors'],
valueToUse = values [Math.floor(Math.random()* values.length)];
return valueToUse;
};
function playRound() {
let playerSelection;
let computerSelection;
let playerScore = 0;
let computerScore = 0;
while(true){
playerSelection = prompt('Pick your poison').toLowerCase();
computerSelection = computerPlay();
if (playerSelection === 'rock') {
if (computerSelection === 'paper') {
computerScore += 1;
} else if (computerSelection === 'scissors') {
playerScore += 1;
}
} else if (playerSelection === 'paper') {
if (computerSelection === 'scissors') {
computerScore += 1;
} else if (computerSelection === 'rock') {
playerScore += 1;
}
} else if (playerSelection === 'scissors') {
if (computerSelection === 'rock') {
computerScore += 1;
} else if (computerSelection === 'paper') {
playerScore += 1;
}
} else {
console.log('Please type Rock, Paper, or Scissors');
continue;
}
console.log (`User Selection: ${playerSelection.toUpperCase()} | Player Score: ${playerScore}
Computer Selection: ${computerSelection.toUpperCase()} | Computer Score: ${computerScore}`);
}
}
Here is a minimalist version of the game as a complete rewrite:
function game(){
var usr, u, c, g, score=[0,0],last="";
const words=["rock","paper","scissors"];
while(usr=prompt(last+"\nScore (you:computer): "+score.join(":")+"\nYour choice:")) {
while((u=words.indexOf(usr.toLowerCase()))<0) usr=prompt("invalid choice, please enter again,\none of: "+words.join(", "));
c=Math.floor(Math.random()*3);
g=(3+u-c)%3; // who wins?
if(g) score[g-1]++;
last="you: "+words[u]+", computer: "+words[c]+" --> "
+["draw","you win!!!","you lost - sorry."][g];
}
}
game()