Help with Rock Paper Scissors JavaScript game

Hello all,

I’m new to all of this so thank you in advance for your time and patience! I’m working on the Javascript game “Rock, Paper, Scissors” and am having trouble with one element. For the record, I’m trying to write the code myself prior to watching the help video. The bellow snippet of code is supposed to randomly generate a number for the computer that corresponds to Rock, Paper or Scissor and it works some the time. It will log one of the three choices to the console but periodically it will also just say “undefined.” Why is this happening?

const getComputerChoice= () => {
  
  if (Math.floor(Math.random() * 3) === 0){
    return 'Rock';
  }
  else if (Math.floor(Math.random() * 3) === 1){
    return 'Paper';
  }
  else if (Math.floor(Math.random() * 3) === 2) {
  return 'Scissor';
  }
    }
console.log(getComputerChoice());

Recall that each time we invoke a function that returns random results, we get a new value. Should we be comparing new values in the if statement clauses, or the same value each time?

1 Like

Thanks! I rewrote the code as this:

const getComputerChoice= () => {
  const randomNumber = (Math.floor(Math.random() * 3))
  if (randomNumber === 0){
    return 'Rock';
  }
  else if (randomNumber === 1){
    return 'Paper';
  }
  else if (randomNumber === 2){
  return 'Scissor';
  }
    }
console.log(getComputerChoice());

and it works fine. My takeaway is that by putting the calculation in the variable we lock down one value for every call to action. Another question: is there a particular virtue of declaring a function one way versus another? For example, does one declaration style handle strings better while another declaration style is more suited to numbers?

Crystal clear.

Functions are special objects, but they do not possess any magic sauce. That comes from the code we write into them. Whether working with data, numeric, text, boolean, or otherwise, the same mechanics is available to all as inherited from the Function object.

Number, String and Boolean are themselves special objects that act as wrappers for any primitives that turn up in the source code. What is inherited comes from those objects’ prototype.


Aside

There is no such noun as scissor that I am aware of. They are written as a pluralscissors.

https://www.google.com/search?q=scissor

We see that it is a verb when written in singular form.

1 Like

Notice that you’re repeating code a lot, what actually changes?

['Rock', 'Paper', 'Scissors']

What if you made a function for selecting a random element from an array? You could then write:

const getComputerChoice = () => choice(['Rock', 'Paper', 'Scissors'])

The choice function is a one-liner as well, because all it does is pick a random index based on the length.

they are same when it comes to data types. the difference comes from 1) personal preference and 2) in object programming when ‘this’ gets messed up if you use wrong declaration

I don’t know if this is the right thread, but I have a doubt. During the course we learn the correct structure of the switch flow control, but the expert doesn’t use breaks or the default statement. Why? I can see his code works, it’s just it kind of broke the mold for me.

Those are optional. Breaks are so it does not continue to check cases after a match is found. Default is just used to execute something when no cases match. Often when we know in scope all cases we don’t use a default other than maybe to send an error message to warn us we are out of bounds of cases we tested.

1 Like

Hello, @juenel.

Welcome to the forums!

As @psmilliorn said, breaks and default: are optional. After the switch() statement determines which of the case labels matches the value passed to it, control is passed to that label, and every line of executable code from that point to the end of the switch()'s code block will be executed in order unless something changes the flow. Something like a break, or return. If there is no matching case, and no default: is included, then nothing inside of the switch()'s code block will be executed. The switch() only makes one check for a match. Consider this rather silly example:

const saySomething = name => {
  switch(name) { //comparison is only made once here
    case 'Pam':
      console.log('Hi, Jim!');
    case 'Michael':
      console.log('That\'s what she said!');
    case 'Dwight':
      console.log('Michael! Jim put my stuff in jello again!');
    default:
      console.log('Get out of here, Toby!');
  }
}

['Pam', 'Michael', 'Dwight', 'Kevin'].forEach(person => {
  console.log(`${person}:`)
  saySomething(person); 
  console.log(); //add blank line
});

Output:

Pam:
Hi, Jim!
That’s what she said!
Michael! Jim put my stuff in jello again!
Get out of here, Toby!

Michael:
That’s what she said!
Michael! Jim put my stuff in jello again!
Get out of here, Toby!

Dwight:
Michael! Jim put my stuff in jello again!
Get out of here, Toby!

Kevin:
Get out of here, Toby!

Since there are no breaks, each line of code beginning with the matching case is executed. If we add breaks:

const saySomething = name => {
  switch(name) { //beginning of code block
    case 'Pam':
      console.log('Hi, Jim!');
      break;
    case 'Michael':
      console.log('That\'s what she said!');
      break;
    case 'Dwight':
      console.log('Michael! Jim put my stuff in jello again!');
      break;
    default:
      console.log('Get out of here, Toby!');
  } //end of code block
}

['Pam', 'Michael', 'Dwight', 'Kevin'].forEach(person => {
  console.log(`${person}:`)
  saySomething(person); 
  console.log(); //add blank line
});

Output:

Pam:
Hi, Jim!

Michael:
That’s what she said!

Dwight:
Michael! Jim put my stuff in jello again!

Kevin:
Get out of here, Toby!

There is no need for a break with the default: case since it is at the end of the code block already. break kicks the control flow out of the code block it is included in. In this example the code block is everything following switch(name) between the { }'s.

1 Like

Hi Folks,

Thanks for all the responses! I’ve hit another bump in the road and as much as I’ve tried, I can’t seem to figure out the answer on my own. I finished my code but when I call playGame() I’ll get a “You Won!” message regardless of whether or not I did, in fact, win. What am I doing wrong? As far as I can tell, the variables userChoice and computerChoice aren’t being passed to the determineWinner() function when it is called from within the playGame function and when the variables are set as parameters for the determineWinner function. What am I missing?

const getUserChoice = (userInput) => {
 if (userInput.toLowerCase() === 'rock'){
  return userInput;
  }
 else if (userInput.toLowerCase() === 'paper'){
    return userInput;
  }
  else if (userInput.toLowerCase() === 'scissors'){
    return userInput;
  }
  else {console.log('Not Valid. Danger Will Robinson!')}
  };

const getComputerChoice = () => {
  const randomNumber = (Math.floor(Math.random() * 3));
  if (randomNumber === 0){
    return 'Rock';
  }
  else if (randomNumber === 1){
    return 'Paper';
  }
  else if (randomNumber === 2){
  return 'Scissors';
  }
    }

const determineWinner = (userChoice,computerChoice) => {
  if (userChoice === computerChoice){
    return 'The game is a tie!';
  }
  else if (userChoice === 'rock'){
    if (computerChoice === 'paper'){
      return 'The computer wins!';
    }
    else {
      return 'You won!';
    }
  }
  else if (userChoice === 'paper'){
    if (computerChoice === 'scissors'){
      return 'The computer wins!';
    }
    else {
      return 'You won!';
    }
  }
  else if (userChoice === 'scissors') {
    if (computerChoice === 'rock') {
      return 'The computer wins!';
    }
    else {
      return 'You won!';
    }
  }
  
}


const playGame = () => {
  const userChoice = getUserChoice('scissors');
  const computerChoice = getComputerChoice();
console.log('You threw:' + userChoice);
console.log('The computer threw:' + computerChoice);
console.log(determineWinner(userChoice, computerChoice));
};

playGame();

Thanks!!!

Compare the returns to the rest of the program.

Thanks Roy! The program works now. I can’t believe I made such a dumb mistake and didn’t catch it. But, I guess that’s how you learn…

1 Like

Thanks. That was a big help.

1 Like

I am a beginner and have not been able to find a solution days. Your topic is by fare the best, but I’m still not able to find a solution. That’s why I continue on this and hope to get an answer. Please excuse if the code or my question isn’t on a high level yet, I’m trying to get there.

The function computerPlay itself works fine and returns a different value, when I call it outside of the following code.

However, when I recall it within the code below, I don’t get another value each time i press a button. Why?

I’ve tried to work with the choice function instead of random. I also tried putting the calculation of the random in the variable, but both is not working.

<body>
  
  <div class="buttons">
    <button class="button" value="rock">Rock</button>
    <button class="button" value="paper">Paper</button>
    <button class="button" value="scissors">Scissor</button>
  </div>

  <script>

    var buttons = document.getElementsByClassName("button");

    for (i of buttons) {
      i.addEventListener("click", function (e) {
      let playerSelection = e.srcElement.value;
      playRound(playerSelection);
      })
    };

    function computerPlay(){
      const shapes = ['rock', 'paper', 'scissors'];
      const random = Math.floor(Math.random() * shapes.length);
      return(shapes[random]);
    };

    let computerSelection = computerPlay();

    function playRound (playerSelection){  
      if (playerSelection === computerSelection){
        console.log("Tie! Repeat to break the tie");
      }else if (playerSelection === 'rock' && computerSelection === 'paper'){
        console.log("You Lose! Paper beats Rock");
      }else if (playerSelection === 'rock' && computerSelection === 'scissors'){
        console.log("You Win! Rock beats Scissors");
      }else if (playerSelection === 'paper' && computerSelection === 'rock'){
        console.log("You Win! Paper beats Rock");
      }else if (playerSelection === 'paper' && computerSelection === 'scissors'){
        console.log("You Lose! Scissors beats Paper");
      }else if (playerSelection === 'scissors' && computerSelection === 'rock'){
        console.log("You Lose! Rock beats Scissors");
      }else if (playerSelection === 'scissors' && computerSelection === 'paper'){
        console.log("You Win! Scissors beats Paper");
      }else{
        console.log("Invalid input! Please try again");
      }
    };

  </script>```

That variable is in block scope so cannot be seen outside of the loop. Declare the variable outside the loop (global) and remove the let from that line.

Suggest using the standard, target attribute instead of srcElement.