Is there a better or more concise way to write this code?

I have been working on learning JavaScript as a hobby and maybe move to professional at some point in the future. I have been going through the basic Codecademy learning path and just got done with functions. I am not signed up for pro but I saw that one of the projects for pro was to code Rock, Paper, Scissors. I wanted to challenge myself and see if I could do it without much help. So far this is what I’ve made:

const rock = 0
const paper = 1
const scissors = 2

const playerChoice = scissors;
const comChoice = Math.floor(Math.random() * 3);

function comName(comChoice){
  if(comChoice === 0){
    return 'The computer chose Rock.';
  } else if(comChoice === 1){
    return 'The computer chose Paper.';
  } else{
    return 'The computer chose Scissors.';
  } 
}

function compareAnswer(playerChoice, comChoice){
  if(playerChoice === comChoice){
    return'Tie game! Try again.';
  }else if(playerChoice === rock){//player choice rock
    if(comChoice === scissors){
      return 'You Win! Want to try again?';
    } else{
      return 'You Lose! Try again.';
    }
  } else if(playerChoice === paper){//player choice paper
    if(comChoice === rock){
      return 'You Win! Want to try again?';
    } else{
      return 'You Lose! Try again.';
    }
  } else if(playerChoice === scissors){//player choice scissors
    if(comChoice === paper){
      return 'You Win! Want to try again?';
    } else{
      return 'You Lose! Try again.';
    }
  }
}

console.log(comName(comChoice));
console.log(compareAnswer(playerChoice, comChoice));

I am wondering if there is a more concise way to write this code with the limited knowledge I have?

Thanks!

Hello, @cssblaster91686

Better? I suppose that’s a matter of personal preference.
More concise? For sure. That doesn’t necessarily mean better.

You might consider ways you could DRY your code. For instance, you could try utilizing logical operators to eliminate using the same return statements three times each in your compareAnswer function.

1 Like

I guess you could use arrays.

function comName(comChoice){
  const options = ["Rock", "Paper", "Scissors"];
  return 'The computer chose ' + options[comChoice];
}

And you could use some math to check who wins:

function mod3(x) {
  const result = x % 3;
  if (result < 0) {
    result = result + 3;
  }
  return result;
}

function compareAnswer(playerChoice, comChoice){ 
  const result = mod3(playerChoice - comChoice);
  if (result == 0) {
    return 'Tie game! Try again.';
  } else if (result == 1) { 
    return 'You Win! Want to try again?'; 
  } else /*if(result == 2)*/ {
    return 'You Lose! Try again.';
  }
}

You could use switch and case instead of if, else-if, and else there.

1 Like

Looks like you can teach us something here. Please explain this math and associated logic.

1 Like

x % 3 gives the remainder when dividing by 3 (also called x mod 3)

The mod3 function is just to get x % 3 (but having a result of only 0 or 1 or 2),
but in JavaScript, if x is negative, then x % 3 would be negative (so x % 3 could be -1, -2, 0, 1, 2)
thus add 3 to a negative result to get the appropriate positive result of doing mod 3.

A cycle of 3:

Notice that those are in order:
paper beats rock, scissors beats paper, rock beats scissors.
In all those cases, the winning one is always 1 more (or 2 less) than the losing one;
so the (winner − loser) = 1 or −2 (which would have a result of 1 when doing mod 3).
Also, the losing one is always 1 less (or 2 more) than the winning one;
so the (loser − winner) = −1 or 2 (which would have a result of 2 when doing mod 3).

For example,
if the playerChoice is rock and comChoice is scissors,
then playerChoice - comChoice would be 0 - 2 which is -2 and mod3(-2) is 1 indicating that the player is the winner.
if the playerChoice is rock and comChoice is paper,
then playerChoice - comChoice would be 0 - 1 which is -1 and mod3(-1) is 2 indicating that the player is the winner.

3 Likes

Think you meant computer here. :wink:

1 Like

Very nice solution and logic.

Just a question, what is the motivation in including the statement

const result = x % 3;

I am assuming that playerChoice and comChoice would be random numbers 0, 1, 2
Therefore, playerChoice - comChoice would be one of -2, -1, 0, 1, 2

So, the mod statement doesn’t seem absolutely necessary. In case of negative difference, incrementing the difference by 3 would work.

However, the inclusion of the mod statement does make for better readability. It helps in understanding why an increment of 3 works in cycling from a negative difference to a non-negative difference. Without the mod statement, it may not be clear why 3 has been chosen in the statement result = result + 3;

Was that the motivation or were there other reasons for including the mod statement?

On second thought, the inclusion of

const result = x % 3;

does make more sense.

Including this statement in the mod3 function frees us from making assumption that the argument will be an integer in the range -2 to +2. With your statement, mod3 can handle any integer argument and normalize the result to be one of 0, 1, 2.

Your code gave me an idea. Thanks!

Code
const whoWon = (p, c) => ["It's a tie!", "You won!", "You lost!"][(p - c + 3) % 3];
const choice = () => Math.floor(Math.random() * 3);
const tokens = ["Rock", "Paper", "Scissors"];
const p = choice(); // player choice
const c = choice(); // computer choice
console.log(`\nYou chose ${tokens[p]}. The computer chose ${tokens[c]}.\n${whoWon(p, c)}`);
3 Likes