Javascript Functions: Project : Rock, Paper, Scissors walkthrough bug

Hi all,
This question concerns the Rock, scissors, paper project. I have tried the exact code as in the project walkthrough for the project but have found a bug. It works fine when you run the program. However when a invalid selection is input that is not rock, paper, scissors or bomb the getUserChoice function detects the error outputs the error message but the rest of the program still executes even though there isnt a valid value for getUserChoice. I tried using ‘roc’ deliberately to see what would happen.

const getUserChoice = userInput => {
userInput = userInput.toLowerCase();
if (userInput === 'rock' || userInput === 'paper' || userInput === 'scissors' || userInput === 'bomb') {
    return userInput;
  } else {
     console.log( 'Invalid select rock, paper, scissor or bomb');
    };

The program runs through and the output to the screen as so:

Invalid select rock, paper, scissor or bomb
You threw the undefined
The computer threw rock
undefined

Has anyone else tried this before?.
Another thing is the determineWinner function. The walkthrough code is as follows:

function determineWinner(userChoice, computerChoice){
  if (userChoice === computerChoice) {
    return 'It was a Tie';
   } 
 if (userChoice === 'rock') {
  if (computerChoice === 'paper') {
    return 'The computer won!';
  } else {
    return 'You won!';
  }
}if (userChoice === 'scissors') {
  if (computerChoice === 'rock') {
    return 'The computer won!';
  } else {
    return 'You won!';
  }
}if (userChoice === 'paper') {
  if (computerChoice === 'scissors') {
    return 'The computer won!';
  } else {
    return 'You won!';
  }
}
};

It works perfect but I used else if statements instead of nested if statements. Is that wrong to do so? Is it better to use nested if statements vs else if statements?
Here is my code below and I have also modified getUserChoice and Playgame functions to overcome the first issue with when an invalid value is put in. I dont knnow if my code is over messy or could be done a better way. Please anyone with better solutions are welcome.

const getUserChoice = userInput => {
userInput = userInput.toLowerCase();
if (userInput === 'rock' || userInput === 'paper' || userInput === 'scissors' || userInput === 'bomb') {
    return userInput;
  } else {
    userInput = 'Invalid';
    return userInput;
    }
};

function getComputerChoice(){
let choice = Math.floor(Math.random() * 3);
switch (choice) {
  case 0:
    return 'paper';
    case 1:
    return 'scissors';
  default:
    return 'rock';
    }
};

function determineWinner(userChoice, computerChoice){
  if (userChoice === computerChoice) {
    return 'It was a Tie';
   } 
  else if (userChoice === 'rock' && computerChoice === 'scissors') {
    return 'You won';
 } else if (userChoice === 'paper' && computerChoice === 'rock') {
    return 'You won';
  } else if (userChoice === 'scissors' && computerChoice === 'paper') {
    return 'You won';
   } 
   else if 
   (userChoice === 'bomb') {
     return 'you won';
   } 
   else {
     return 'You Lost'
   } 
};

/*console.log(determineWinner('scissors','rock'));
console.log(determineWinner('paper','rock'));
console.log(determineWinner('rock','scissors'));*/

const playGame = () => {
const myChoices = getUserChoice('scissors');
const compChoices = getComputerChoice();
  
  if (myChoices === 'Invalid') {
   console.log('Invalid select rock, paper or scissors');
  } else {
      console.log(`You threw the ${myChoices}`);
      console.log(`The computer threw ${compChoices}`);
      console.log(determineWinner(myChoices,compChoices));
      }
};

playGame();

comments welcome please.

1 Like

So for your first point:

This isn’t a particularly game-breaking problem and as such in an early project like this isn’t something they necessarily covered. The program is working as intended, as getUserChoice() logs a message defined by the user and doesn’t throw an actual error that would stop the program. This is something that you can change if you wish to take this further, however it hasn’t been covered in the course up to this point hence why you get the undefined being carried through the rest of the program.

As for the second point:

Depending on the context one can be wrong, but in this context it’s fine. Using else if means that as soon as a condition is met, the program will execute the relevant code inside and then skip the rest of the else ifs. However using nested ifs means that even if a condition is met, it will still check the rest of the if statements. In this context every condition returns the function so the rest of the checks are skipped regardless, but there may be situations in which you want every condition checked. However in this case, both your code and the solution code is fine.

1 Like

Thanks a million for the help. Well appreciated.

1 Like

thanks for the explaination on why we are using if statements and not if else. Both can be used. Good to know.

You can input process.exit() right after the console.log( 'Invalid select rock, paper, scissor or bomb').

This will terminate the entire program and force the user to input the correct data again.

Thanks a lot man. I was so stuck getting the same undefined.

Hi all, I’m stuck for the second time on this one (but still enjoying working it out!). When I’ve tested on the latest console.log I’ve lost the logic I added at the start to change the userInput to lowercase and show the error message when I type anything incorrectly (I now just get undefined) if I add something like ‘Rock’ or ‘Tape’). I’ve followed the instructions so far and I think I maybe a bit confused with changing from userInput to userChoice. Please could some help? thank you in advance

const getUserChoice = userInput => {
 userInput = userInput.toLowerCase();
  if (userInput==='rock' || userInput==='paper' || userInput==='scissors') {
   return userInput;
 } else {
  console.log ('Error, you must state either rock, paper or scissors');
 }
}
 

const getComputerChoice =() => {
 const computerInput = (Math.floor(Math.random()*3)); 

switch (computerInput) {
case 0:
return 'rock';
break;
case 1:
return 'paper';
break;
case 2:
return 'scissors';
break;
} }
;
  /*console.log ('computer says '+getComputerChoice());
  console.log ('Jen says '+getUserChoice('paper'));*/

  const determineWinner = (userChoice, computerChoice) => {
       if (userChoice===computerChoice) {
         return 'it is a tie';
       }
    if (userChoice==='rock') 
   if (computerChoice=== 'paper') {
   return 'computer wins'
   } else {
     return 'you win!'
   }
    if (userChoice==='paper') 
     if (computerChoice=== 'scissors') {
   return 'computer wins'
   } else {
     return 'you win!'
   }
     if (userChoice==='scissors') 
       if (computerChoice=== 'rock') {
   return 'computer wins'
   } else {
     return 'you win!'   
       }
     };
     console.log(determineWinner('rock', 'rock'));
  

If you want to have the getUserChioce function to run first, and then run the getComputerChoice
you could put the function calls one after the other, and store the result of the previous function calls as a variable.

const userChoice = getUserChoice('Rock'); // result of calling getUserChoice is put into userChoice
const computerChoice = getComputerChoice(); // result of calling getComputerChoice is put into computerChoice
console.log(determineWinner(userChoice, computerChoice));

or you could call getUserChoice inside the function call for determineWinner if you want all of that on one line.

console.log(determineWinner( getUserChoice('Rock'), getComputerChoice() ));
1 Like