Rock Paper Scissors game with JavaScript - javascript

I have recently got into coding with JavaScript and decided to make a game, to test my knowledge. Nothing happens when I press on the objects supposed to start the game, and when I send information through the console, (most of the time) nothing happens.
const paper = document.getElementById('paper');
const scissor = document.getElementById('scissor');
const result_in = document.getElementById("result")
let computer;
let computer_pick;
let result;
//Player choice
rock.onclick = play('rock');
paper.onclick = play('paper');
scissor.onclick = play('scissor');
function play(userinput) {
computer_pick = Math.floor(Math.random() * 3);
console.log(computer_pick);
if (computer_pick === 0) {
computer = 'rock'
} else if (computer_pick === 1) {
computer = 'paper';
} else if (computer_pick === 2) {
computer = 'scissor';
} else { console.log('error') };
console.log(computer);
//
if (computer == userinput) { //tie
result = 'tie';
} else if (computer == 'rock' && userinput == 'paper' || computer == 'paper' && userinput == 'scissor' || computer == 'scissor' && userinput == "rock") {
console.log(win);
result = 'win';
} else if (computer == 'rock' && userinput == 'scissor' || computer == 'paper' && userinput == 'scissor' || computer == 'scissor' && userinput == 'paper') {
console.log(loss);
result = 'lost';
}
//output
document.getElementById('result').innerHTML = You ${result}! The computer threw ${computer}.;
}

Are you waiting until the DOM is loaded?
Where are you inject this file to DOM? in head tag or body tag!
If you inject this code in head tag you need to wait until the DOM become loaded
something like this:
window.onload = function() {
// Your script
}

There are some errors in your code:
rock.onclick is not correct - rock.addEventlistener('click', function(e) {}) is correct
console.log(win) (or loss) is not correct - you try to console.log() a variable that doesn't exist - to output a string in console.log() you should put it in quotes console.log('win')
document.getElementById('result').innerHTML = You ${result}! The computer threw ${computer}.; is not correct - you should use backticks for string interpolation
You didn't define rock as you did paper and scissor
This is not an coding error, but a simple logic problem: you have three result ALTERNATIVES: tie, win, lost. If it's not a tie and user hasn't win (won), then user lost. You don't need the last else if, only else
The same is true for the computer_pick variable - there's no room for error (the random value can only be 0, 1 or 2), so you don't need the else for error. And if computer_pick is not 0 or 1, then it has to be 2 (no need for the else if, only for else).
const rock = document.getElementById('rock');
const paper = document.getElementById('paper');
const scissor = document.getElementById('scissor');
const result_in = document.getElementById("result");
let computer;
let computer_pick;
let result;
//Player choice
rock.addEventListener('click', function(e) {
play('rock')
})
paper.addEventListener('click', function(e) {
play('paper')
})
scissor.addEventListener('click', function(e) {
play('scissor')
})
function play(userinput) {
computer_pick = Math.floor(Math.random() * 3);
console.log('computer_pick:', computer_pick);
if (computer_pick === 0) {
computer = 'rock'
} else if (computer_pick === 1) {
computer = 'paper';
} else {
computer = 'scissor';
}
console.log('computer:', computer);
//
if (computer == userinput) { //tie
result = 'tie';
} else if (computer == 'rock' && userinput == 'paper' || computer == 'paper' && userinput == 'scissor' || computer == 'scissor' && userinput == "rock") {
console.log('win');
result = 'win';
} else {
console.log('lost');
result = 'lost';
}
//output
document.getElementById('result').innerHTML = `You ${result}! The computer threw ${computer}.`;
}
<div id="rock">ROCK</div><br />
<div id="paper">PAPER</div><br />
<div id="scissor">SCISSORS</div><br />
<div>RESULT: <span id="result"></span></div>
And you could go a bit further by thinking through the logic:
// you can use a query selector with a class
const btns = document.querySelectorAll('.btn')
// gameRulesObj to define what beats what
const gameRulesObj = {
"rock": "paper",
"paper": "scissor",
"scissor": "rock"
}
btns.forEach(e => {
e.addEventListener('click', function(e) {
appendToDOMElement('result', play(this.getAttribute('id'), computerPick(gameRulesObj), gameRulesObj))
})
})
// this function decides if player wins, loses or ties
function play(userinput, computer, obj) {
let result;
if (computer === userinput) {
result = 'tie';
} else if (obj[computer] === userinput) {
result = 'win';
} else {
result = 'lost';
}
return {
result,
computer
};
}
// this function controls what the computer picks
const computerPick = (obj) => {
return Object.keys(obj)[Math.floor(Math.random() * Object.keys(obj).length)]
}
// this function adds the result to the DOM
const appendToDOMElement = (container, {
result,
computer
}) => {
document.getElementById(container).textContent = `You ${result}! The computer threw ${computer}.`
}
<div id="rock" class="btn">ROCK</div><br />
<div id="paper" class="btn">PAPER</div><br />
<div id="scissor" class="btn">SCISSORS</div><br />
<div>RESULT: <span id="result"></span></div>
The second snippet above gives a bit of a structure to the code:
every function has one and only one purpose (they can be described with one line of comment); this means that it's easier to change parts of your app
a lot of variables are eliminated, so you don't have to keep track of them
one variable added (gameRulesObj), so you can define your base rules in one place; the functions now work with any number and set of rules
I know that this structure may be overkill for a simple game like this, but it's good for practicing :)

try < button onClick=play('rock')> and so on
and you need " " for the line document.getElementById('result').innerHTML = " "

Related

Rock Paper Scissors assigning points each round

newbie here! Just starting learning week and a half ago. Creating the rock paper scissors game. The goal is to play 5 rounds against the computer to determine the overall winner. I'm a little stumped when it comes to how I can award the player a point if they win or the computer a point if it wins. Also all critiques of code are welcome as well.
Thanks a ton!
code so far...
let array = ['rock', 'paper', 'scissor'];
const getComputerChoice = () => {
let random = Math.floor((Math.random() * 3));
let randomNames = array[random];
return randomNames;
}
const game = () => {
for (let i = 0; i < 5; i++) {
let input = prompt('Choose rock, paper or scissor');
const playerSelection = input.toLowerCase();
const computerChoice = getComputerChoice();
const computerWins = `Computer Wins! ${computerChoice} beats ${playerSelection}.`;
const playerWins = `Player wins! ${playerSelection} beats ${computerChoice}.`;
const tie = `It's a tie, ${playerSelection} is equal to ${computerChoice}.`;
if (playerSelection !== 'rock' && playerSelection !== 'paper' && playerSelection !== 'scissor') {
i = i - 1;
console.log("Nice try! Please enter a valid input.");
}
if (playerSelection === 'rock' && computerChoice === 'paper' || playerSelection === 'paper' && computerChoice === 'scissor' || playerSelection === 'scissor' && computerChoice === 'rock') {
console.log(computerWins);
}
if (playerSelection === 'paper' && computerChoice === 'rock' || playerSelection === 'scissor' && computerChoice === 'paper' || playerSelection === 'rock' && computerChoice === 'scissor') {
console.log(playerWins);
} else {
if (playerSelection === computerChoice) {
console.log(tie);
}
}
}
}
game();
just add variable of score and increment after each win
let array = ['rock', 'paper', 'scissor'];
let player_score=0;
let computer_score=0;
const getComputerChoice = () => {
let random = Math.floor((Math.random() * 3));
let randomNames = array[random];
return randomNames;
}
const game = () => {
for (let i = 0; i < 5; i++) {
let input = prompt('Choose rock, paper or scissor');
const playerSelection = input.toLowerCase();
const computerChoice = getComputerChoice();
const computerWins = `Computer Wins! ${computerChoice} beats ${playerSelection}.`;
const playerWins = `Player wins! ${playerSelection} beats ${computerChoice}.`;
const tie = `It's a tie, ${playerSelection} is equal to ${computerChoice}.`;
if (playerSelection !== 'rock' && playerSelection !== 'paper' && playerSelection !== 'scissor') {
i = i - 1;
console.log("Nice try! Please enter a valid input.");
}
if (playerSelection === 'rock' && computerChoice === 'paper' || playerSelection === 'paper' && computerChoice === 'scissor' || playerSelection === 'scissor' && computerChoice === 'rock') {
computer_score+=1;
console.log(computerWins);
}
if (playerSelection === 'paper' && computerChoice === 'rock' || playerSelection === 'scissor' && computerChoice === 'paper' || playerSelection === 'rock' && computerChoice === 'scissor') {
player_score+=1;
console.log(playerWins);
} else {
if (playerSelection === computerChoice) {
console.log(tie);
}
}
}
console.log("Computer:"+computer_score+' vs '+'Player:'+player_score);
}
game();
Like Wiktor said in his comment, you can store the victories in variables, that you increment every time someone wins.
Before your for loop, you you'd initialize two variables, one for Computer wins, and one for Human wins:
var compWins = 0;
var humanWins = 0;
Then, when someone wins, you would increment the appropriate variable:
compWins++;
or
humanWins++;
You can add 2 variables like.
let playerPoints = 0;
let computerPoints = 0;
then, where you console.log the winner of a round you can add 1 at their counter.
if (playerSelection === 'rock' && computerChoice === 'paper' || playerSelection === 'paper' && computerChoice === 'scissor' || playerSelection === 'scissor' && computerChoice === 'rock') {
computerPoints += 1
console.log(computerWins);
}
if (playerSelection === 'paper' && computerChoice === 'rock' || playerSelection === 'scissor' && computerChoice === 'paper' || playerSelection === 'rock' && computerChoice === 'scissor') {
playerPoints += 1
console.log(playerWins)
Then you have the points. With them you can add another if to control if someone has won (when reach 3 points for example).
Do not use prompt(), confirm(), or alert(), they are horrible for UX. You need to use HTML if you are interacting with the user preferably <form> and form controls which are designed specifically for user interaction.
Details are commented in example
// Define the scores outside of event handler
let w = 0,
l = 0,
d = 0,
turns = 5;
// Reference the <form>
const rps = document.forms.rps;
// Event handler passes event object by default
const game = (e) => {
// Reference the tag user clicked
const clicked = e.target;
// If the user clicked a <button>...
if (clicked.matches('button')) {
// Decrement turn counter
turns--;
// Get a random number in the range of 0 to 2
const opponent = 3 * Math.random() << 0;
// Get the value of the <button> user clicked (will be 0 to 2)
const player = +clicked.value;
/*
Index number of the array is determined by the number of the player
and opponent
*/
const icon = ['🪨', '🧻', '✂️'];
const playerIcon = icon[player];
const opponentIcon = icon[opponent];
// Message is determined by outcome
const L = `Opponent wins! ${opponentIcon} beats ${playerIcon}.`;
const W = `You win! ${playerIcon} beats ${opponentIcon}.`;
const D = `It's a tie, ${playerIcon} does nothing to ${opponentIcon}.`;
/*
Outcome is determined by player and opponent numbers, the syntax is a chained
ternary -- it's an abbreviated "if/else if/else" statement:
¹If player equals opponent return D(raw)
²Else if player equals opponent +1 return W(ins)
³Else if player is 0 and opponent is 2 return W(ins)
⁴Else return L(ost)
*/
let outcome = player === opponent ? D : // ¹
player === opponent + 1 ? W : // ²
player === 0 && opponent === 2 ? W : L; // ³ : ⁴
// Reference all form controls (everything except the <label>s)
const fc = e.currentTarget.elements;
// Reference each <output>
const msg = fc.msg;
const wins = fc.wins;
const lost = fc.lost;
const draw = fc.draw;
const btns = Array.from(fc.btn);
const start = fc.start;
/*
Pass in the outcome (it's either D, W, or L)
Each case basically increments the associated score and shows the
associated message.
*/
switch (outcome) {
case D:
draw.value = ++d;
msg.value = D;
break;
case W:
wins.value = ++w;
msg.value = W;
break;
case L:
lost.value = ++l;
msg.value = L;
break;
default:
break;
}
/*
If turns is less than 1...
...display game over message...
...show reset <button>...
...hide the RPS <button>s...
...reset the turns counter scores
*/
if (turns < 1) {
msg.value = `5 turns, game over.`;
start.style.display = 'inline-block';
btns.forEach(b => b.style.display = 'none');
turns = 5, w = 0, l = 0, d = 0;
}
}
}
// Bind the click event to <form>
rps.onclick = game;
// Bind the reset event to <form>
rps.onreset = e => {
// Reference all form controls hide reset <button> show RPS <button>s
const fc = e.currentTarget.elements;
fc.start.style.display = 'none';
Array.from(fc.btn).forEach(b => b.style.display = 'inline-block');
}
html {
font: 300 3ch/1.25 'Segoe UI';
}
form {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
min-height: 100vh;
}
fieldset {
display: flex;
justify-content: space-evenly;
align-items: center;
min-width: 350px;
}
output {
font-family: Consolas
}
#msg {
font-family: 'Segoe UI';
}
button {
font: inherit;
cursor: pointer;
}
[type="reset"] {
display: none
}
<form id='rps'>
<fieldset>
<legend>Roshambo</legend>
<button name='btn' type='button' value='0'>🪨</button>
<button name='btn' type='button' value='1'>🧻</button>
<button name='btn' type='button' value='2'>✂️</button>
<button id='start' type='reset'>Play Again</button>
</fieldset>
<fieldset>
<output id='msg'> </output>
</fieldset>
<fieldset>
<label>Wins: <output id='wins'>0</output></label>
<label>Lost: <output id='lost'>0</output></label>
<label>Draw: <output id='draw'>0</output></label>
</fieldset>
</form>

For loop works well on Firefox but not on Chrome

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.

Syncing a random variable

I am currently making simple UI for my rock paper scissors game. I am using a random number for my getComputerChoice function which then is used to display an image and decide the outcome of the game. I tried setting the outcome of getComputerChoice to a variable but then I ran into the issue that the computer's choice would remain the same each time I ran a new game.
const model = {
wins: 0,
losses: 0,
draws: 0,
getCompChoice: function() {
var num = Math.floor(Math.random() * 3);
var choices = ["rock", "paper", "scissors"];
var choice = choices[num];
return choice;
},
gameLogic: function(player, computer) {
if (player === false) {
return alert("Please enter a valid guess");
} else if (player === computer) {
this.draws++;
return "draw";
} else if (
(player === "rock" && computer === "paper") ||
(player === "paper" && computer === "scissors") ||
(player === "scissors" && computer === "rock")
) {
this.losses++;
return "lose";
} else {
this.wins++;
return "win";
}
}
};
const view = {
updateScore: function() {
document.getElementById("wins").textContent = "Wins:" + " " + model.wins;
document.getElementById("losses").textContent =
"Losses:" + " " + model.losses;
document.getElementById("draws").textContent = "Draws:" + " " + model.draws;
return;
},
displayRollComputer: function() {
var computer = document.getElementById("computer");
computer.classList.remove("rock", "paper", "scissors");
computer.classList.add(controller.compChoice);
console.log(controller.compChoice);
},
displayRollUser: function() {
var user = document.getElementById("user");
user.classList.remove("rock", "paper", "scissors");
user.classList.add(processPlayer());
}
};
const controller = {
compChoice: model.getCompChoice(),
play: function() {
model.gameLogic(processPlayer(), this.compChoice);
view.updateScore();
view.displayRollComputer();
view.displayRollUser();
}
};
// Helper Functions
function processPlayer() {
const player = document.getElementById("guess").value;
if (player === "rock" || player === "paper" || player === "scissors") {
return player;
} else {
return false;
}
}
That's because the controller.compChoice is not computed every time you call gameLogic(), but only once, during initialization. Change it to:
const controller = {
compChoice: model.getCompChoice(),
play: function() {
this.compChoice = model.getCompChoice(); <
model.gameLogic(processPlayer(), this.compChoice);
view.updateScore();
view.displayRollComputer();
view.displayRollUser();
}
};
and everything should work as expected.

Testing if the user input value is in a given array (JavaScript)

I just created a five rounds rock-paper-scissors game using vanilla JavaScript. The program runs just fine so far except for the fact every time I start the game for the very first time it will take any user input as invalid no matter what and won't count that round.
This is my code:
// Global variables
let playerWins = 0;
let computerWins = 0;
let array = [];
let validInput = 0;
let newRound = "";
// This function generates a computer selection
const computerPlay = () => {
array = ["rock", "paper", "scissors"]
return array[Math.floor(Math.random() * array.length)];
}
// This function stores player selection
const playerSelection = (selection) => {
selection = prompt("Enter: 'Rock', 'Paper' or 'Scissors'").toLowerCase();
validInput = array.indexOf(selection);
console.log(validInput);
// This loop will validate user input is correct
while (validInput === -1) {
alert("Invalid input, try again");
selection = prompt("Enter 'Rock', 'Paper' or 'Scissors'").toLowerCase();
validInput = array.includes(selection);
}
return selection;
}
// This function plays a single round of Rock-Paper-Scissors
const playRound = (playerSelection, computerPlay) => {
// If both players select the same item
if (playerSelection === computerPlay) {
return alert("It's a tie!");
}
// If player selects "Rock"
if (playerSelection === "rock") {
if (computerPlay === "scissors") {
playerWins += 1;
return alert("Rock crushes scissors: YOU WIN!!!");
} else {
computerWins += 1;
return alert("Paper covers rock: YOU LOOSE!!!");
}
}
// If player selects "Paper"
if (playerSelection === "paper") {
if (computerPlay === "rock") {
playerWins += 1;
return alert("Paper covers rock: YOU WIN!!!");
} else {
computerWins += 1;
return alert("Scissors cuts paper: YOU LOOSE!!!");
}
}
// If player selects "Scissors"
if (playerSelection === "scissors") {
if (computerPlay === "rock") {
computerWins += 1;
return alert("Rock crushes scissors: YOU LOOSE!!!");
} else {
playerWins += 1;
return alert("Scissors cuts paper: YOU WIN!!!");
}
}
}
// This function keeps score and reports a winner or loser at the end
const trackWins = (pw, cw) => {
alert("COMPUTER WINS: " + cw + "\nPLAYER WINS: " + pw)
if (pw > cw) {
alert("YOU WIN THIS ROUND, CONGRAX!!!")
} else if (cw > pw) {
alert("YOU LOOSE THIS ROUND, SO BEST LUCK FOR THE NEXT TIME :_(")
} else {
alert("IT'S A TIE")
}
}
// This function creates a 5 round game
const game = () => {
for (let i = 0; i < 5; i++) {
playRound(playerSelection(), computerPlay());
}
trackWins(playerWins, computerWins);
}
do {
game();
newRound = prompt("Do yo want to play another round? Type 'y' to continue or any other key to exit").toLowerCase();
} while (newRound === "y");
alert("It was a good game, bye for now!")
I will appreciate any ideas to fix this problem or improve my script, thank you in advance!
Your posted code can be simplified to better reflect question - say, you have an array, and a variable that stores user input. How do you test if the input value is in the array?
var arr=['Rock','Paper','Scissors'];
var inp='Rock'; //user input
You could use a while loop, but there's a much faster way:
var options={'rock':0,'paper':1,'scissors':2}
var inp='Rock'; //user input
var ninp=inp.toLowerCase().trim(); //normalize input
var pick=(options[ninp]);
if (pick==null) // invalid selection
if (pick==0) //rock
if (pick==1) //paper
if (pick==2) //scissors
The code can be further cleaned up with a switch:
switch (pick){
case 0: ... break; //rock
case 1: ... break; //paper
case 2: ... break; //scissors
default: //invalid
}

error defining computerChoice in the function getComputerChoice - javascript program

I am doing a simple rock, paper, scissors program in the codeacademy javascript course. This first one is very simple and much of what is here is the way they guided me. I know the entire thing can be written better but that comes later. Program works partially but never seems to define the computerChoice variable. I think the issue is in lines 15-18 but not sure. I did try changing the strings to integers in lines 42, 49 & 58 but that did not solve the issue.
Can anyone look at my code and offer guidance.
//function to get the user's choice
const getUserChoice = userInput => {
userInput =
userInput.toLowerCase();
//if stmt to make sure input is valid
if (userInput === 'rock' || 'scissors' || 'paper') {
return userInput;
} else {
console.log('Invalid selection');
}//end else
}//end getUserChoice function
//function to get computer choice
const getComputerChoice = () => {
Math.floor(Math.random() * 3);
//switch case to verify & return result
switch (getComputerChoice) {
case 0:
return 'rock';
break;
case 1:
return 'paper';
break;
case 2:
return 'scissors';
break;
default:
console.log('Invalid');
break;
}//end switch
}//end getComputerChoice
//function to determine the winner
const determineWinner = (userChoice, computerChoice) => {
if (userChoice === computerChoice) {
return 'The game is a tie';
}
if (userChoice === 'rock') {
if (computerChoice === 'paper') { return 'You Won!'; }
} // end userchoice is rock
if (userChoice === 'paper') {
if (computerChoice === 'scissors') {
return 'The computer won!';
} else {
return 'You won!';
}
} // end userchoice is paper
if (userChoice === 'scissors') {
if (computerChoice === 'rock') {
return 'The computer won!';
} else {
return 'You won!';
}
} //end userchoice is scissors
}//end winner function
//function to play the game
const playGame = () => {
const userChoice = getUserChoice('rock');
const computerChoice = getComputerChoice();
console.log('You threw: ' + userChoice);
console.log('The computer threw: ' + computerChoice);
//call funtion to determine winner
console.log(determineWinner(userChoice, computerChoice));
}//end playGame
//function calls
playGame();
Problem
After a more thorough examination, there were a few errors. Demo 1 addresses each of these errors. Details are commented in the demo. There is a Plunker of Demo 1 as well.
At first, I had started on a working demo without the benefit of your updated post. Demo 2 is functioning as well and is helpful if you want to consider an alternative way to meet your objective.
Plunker
Demo 1
const getUserChoice = userInput => {
userInput = userInput.toLowerCase();
//if stmt to make sure input is valid
if (userInput === 'rock' || 'scissors' || 'paper') {
return userInput;
} else {
console.log('Invalid selection');
} //end else
}; //end getUserChoice function
//function to get computer choice
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On each case there was a return before every break
A return statement always ends the block so break
was useless and in the process the switch useless.
Changed getComputerChoice into a declared function
Saved the results of switch in a variable
Returned the value as expected
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
function getComputerChoice() {
let compPick = Math.floor(Math.random() * 3);
console.log('compPick: ' + compPick);
var psr;
//switch case to verify & return result
switch (compPick) {
case 0:
psr = 'rock';
break;
case 1:
psr = 'paper';
break;
case 2:
psr = 'scissors';
break;
default:
console.log('Invalid');
break;
} //end switch
return psr;
}
//function to determine the winner
const determineWinner = (userChoice, computerChoice) => {
if (userChoice === computerChoice) {
return 'The game is a tie';
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Missing the else portion of conditional statement,
Whenever user threw a rock and computer threw a
scissor, the result was undefined.
Added the else portion, now all 7 condition are met. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if (userChoice === 'rock') {
if (computerChoice === 'paper') {
return 'You Lost!';
} else {
return "You Won!"
}
} // end userchoice is rock
if (userChoice === 'paper') {
if (computerChoice === 'scissors') {
return 'You Lost!';
} else {
return 'You won!';
}
} // end userchoice is paper
if (userChoice === 'scissors') {
if (computerChoice === 'rock') {
return 'You Lost!';
} else {
return 'You won!';
}
} //end userchoice is scissors
}; //end winner function
//function to play the game
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Added a <select> element so testing is properly done
Changed playGame() to a declared function and the
callback function for the change event listener
Note that playGame is passing a value. This value is from the <select>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
function playGame(psr) {
const userChoice = getUserChoice(psr);
const computerChoice = getComputerChoice();
console.log('You threw: ' + userChoice);
console.log('The computer threw: ' + computerChoice);
//call funtion to determine winner
console.log(determineWinner(userChoice, computerChoice));
} //end playGame
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Reference the <select> tag
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
var sel = document.getElementById('psr');
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Register the change event on the <select> tag
When change event occurs on select#psr, playGame() is
called and it passes the value of select#psr thru
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
sel.addEventListener('change', function(e) {
playGame(this.value);
});
select,
option {
font: inherit
}
#psr {
margin: 30px 0 0 30px
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<select id='psr'>
<option>---</option>
<option value='paper'>Paper</option>
<option value='scissors'>Scissors</option>
<option value='rock'>Rock</option>
</select>
</body>
</html>
Demo 2
/* Using HTMLFormControlsCollection
\ Reference the form and...
*/
var game = document.forms.psrGame;
/* reference the form's form controls
*/
var ctrl = game.elements;
/* This is an Object Literal.
\ It's storing data for easy reuse
*/
var PSR = {
player: 0,
opponent: 0,
action: ['📃Paper', '✂️Scissors', '🗿Rock'],
outcome: ['Tied', 'Player Won', 'Player Lost'],
won: 0,
lost: 0,
tied: 0
};
/* Register the click event on fieldset#set
\ Callback function is choice()
*/
ctrl.set.addEventListener('click', choice);
// Callback function
function choice(e) {
/* if the clicked button (e.target) is NOT
|| the registered node (e.currentTarget)...
|| if the clicked node is a BUTTON...
*/
if (e.target !== e.currentTarget) {
if (e.target.tagName === 'BUTTON') {
// Get clicked button's id
var z = parseInt(e.target.id, 10);
PSR.player = z;
//console.log('z: ' + z);
// Get a randomly generated number 0-2
var x = rand(0, 2);
PSR.opponent = x;
//console.log('x: ' + x);
// Determine P.S.R. for player
var pick = PSR.action[z];
//console.log('Picked: ' + pick);
// Determine P.S.R. for opponent
var verse = PSR.action[x];
//console.log('Verses: ' + verse);
// Display P.S.R of player and opponent
ctrl.choice.value = pick;
ctrl.against.value = verse;
}
// Get the outcome and display it
var us = determine(PSR);
ctrl.view.value = us;
return us;
}
/* Prevent event bubbling thereby isolating the
|| the click events from the rest of the form
*/
e.stopPropagation();
}
/* Through a gauntlet of conditions
|| it is determined whether player
|| lost, won, or tied.
*/
function determine(PSR) {
var Z = PSR.player;
var X = PSR.opponent;
var msg;
if (Z === X) {
msg = PSR.outcome[0];
++PSR.tied;
} else if (Z === 0 && X === 2) {
msg = PSR.outcome[1];
++PSR.won;
} else if (Z === 1 && X === 0) {
msg = PSR.outcome[1];
++PSR.won;
} else if (Z === 2 && X === 1) {
msg = PSR.outcome[1];
++PSR.won;
} else {
msg = PSR.outcome[2];
++PSR.lost;
}
/* This is a Template Literal which will
|| display the player's wins, losses, and ties
*/
var totals = `Won: ${PSR.won} Lost: ${PSR.lost} Tied: ${PSR.tied} `;
ctrl.score.innerHTML = totals;
return msg;
}
// Utility to generate random integers
function rand(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
body {
font-size: 16px;
}
#set {
margin-bottom: 10px;
}
input,
button,
output,
label {
font: inherit;
display: inline-block
}
button {
width: 9ch
}
.as-console-wrapper {
max-width: 30%;
margin-left: 70%
}
#view {
font-weight: 900;
color: crimson
}
legend {
font-variant: small-caps;
font-size: 1.2em;
}
<form id='psrGame'>
<fieldset id='set'>
<legend>Paper, Scissors, Rock</legend>
<button id='0' type='button'>Paper</button>
<button id='1' type='button'>Scissors</button>
<button id='2' type='button'>Rock</button>
</fieldset>
<label><b>Player: </b>
<output id='choice'></output>
</label>
<hr>
<label><output id='view'></output></label>
<label style='float:right'><output id='score'></output></label>
<hr>
<label><b>Opponent:</b>
<output id='against'></output>
</label>
Line 18 should be
switch (Math.floor(Math.random() * 3)) {
Whatever value you pass to switch is what's compared against the values of the cases. The switch cases check a random integer from 0 to 2, so pass that generated random number to switch.

Categories