0

Alright, new to coding here, but in my JavaScript program I am attempting to add 2 new conditions to the already popular RPS game (Lizard and Spock). However, when adding these two new conditions in the index.js file, nothing seems to happen.

I've tried changing up the math to .20 each but that did not seem to do anything. I believe that the problem is that I am using the wrong function for 5 different variables (if, else if)

function run() {
    playerChoice = this.innerText;
    computerGamble();
    compare();
}

function computerGamble() {
    var dice = Math.random();
    if (dice <= 0.33) {
        computerChoice = "Rock";
    } else if (dice > 0.33 && dice <= 0.66) {
        computerChoice = "Paper";
    } else {
        computerChoice = "Scissors";
    } else {
      computerChoice = "Lizard";
    } else {
      computerChoice = "Spock";
    }
}

All variables/conditions should have an equal chance to be picked.

vsync
  • 118,978
  • 58
  • 307
  • 400
Mark
  • 15
  • 8
  • 1
    You can't have multiple `else` statements. Only multiple `else if` statements. – Aaron3219 Oct 27 '19 at 18:03
  • You can only have one `else` at the end of all your `else if` conditions. The `else` is used when none of the other specific `else if` conditions have been met. – Scott Marcus Oct 27 '19 at 18:04
  • The else statement is the default value that if none of the conditions is satisfied then it moves to the default case which is the else. In your case you have defined three default cases (Three else cases). So only the first else will be executed every time leaving the last two else out of the code execution. – Mazhar Khan Oct 27 '19 at 18:06
  • Duplicate of: [Getting a random value from a JavaScript array](https://stackoverflow.com/questions/4550505/getting-a-random-value-from-a-javascript-array) – vsync Oct 27 '19 at 18:57

4 Answers4

2

Basically you have like other pointed out as well use if else statements and divide it by number of choices.

function computerGamble() {
    var dice = Math.random();
    if (dice < 0.2) {
        computerChoice = "Rock";
    } else if (dice < 0.4) {
        computerChoice = "Paper";
    } else if (dice < 0.6) {
        computerChoice = "Scissors";
    } else if (dice < 0.8) {
      computerChoice = "Lizard";
    } else{
      computerChoice = "Spock";
}

As an alternative I think I would just use random-numbers between 0-5 and than use a simple switch case statement like so:

function run() {
    playerChoice = this.innerText;
    computerGamble();
    compare();
}

let numberOfChoices = 5;
function computerGamble() {
 var dice = Math.floor(Math.random()*numberOfChoices); //numbers between 0-5
 switch(dice){
  case 1: computerChoice = "Rock";break;
  case 2: computerChoice = "Paper";break;
  case 3: computerChoice = "Scissors";break;
  case 4: computerChoice = "Lizard";break;
  case 5: computerChoice = "Spock";break;
 }
}

Than you can easily adjust the number of choices and don't have to deal with some hard coded decimal numbers if you want to change something. And personally I think its a bit more clear in a switch case - it looks a bit more tidied up. Or without any statements:

let numberOfChoices = 4;
function computerGamble() {
 let choices = ["Rock", "Paper", "Scissors", "Lizard", "Spock"];
 var dice = Math.floor(Math.random()*numberOfChoices); //numbers between 0-4
 computerChoice = choices[dice];
}
Christian Meyer
  • 1,501
  • 1
  • 14
  • 19
  • While this is a better solution, your answer doesn't actually address the question that was asked. – Scott Marcus Oct 27 '19 at 18:14
  • Haha okay right 1:0 for you. Next time i stick more to the question but maybe it gives some ideas how to solve the problem in a different fashion since some other already pointed out how to solve it with decimals. – Christian Meyer Oct 27 '19 at 18:21
  • We're always about answering the question first. Even with your edits, you still haven't addressed the actual question of why the original technique isn't working. – Scott Marcus Oct 27 '19 at 18:22
  • I know i had to rethink and edited like you suggested thanks for pointing that out – Christian Meyer Oct 27 '19 at 18:30
2

You need to add else if for every outcome. i.e you should have something more like

function computerGamble() {
    var dice = Math.random();
    if (dice <= 0.2) {
        computerChoice = "Rock";
    } else if (dice <= 0.4) {
        computerChoice = "Paper";
    } else if (dice <= 0.6) {
        computerChoice = "Scissors";
    } else if (dice <= 0.8) {
      computerChoice = "Lizard";
    } else{
      computerChoice = "Spock";
}

also regarding your statement else if (dice > 0.33 && dice <= 0.66) each else implies that the one before it didn't occur so if dice was 0.25 then the first if would evaluate to false and the second else if would be attempted. If on the other hand dice was 0.1 then only the statement in the first if would execute an all of the other elses would be skipped. as a result you don't need to compare with the lower bound again as it already implicitly satisfies that condition.

Maurice Byrne
  • 173
  • 1
  • 1
  • 6
  • Correct me if im wrong but you have not a 100% equality since the first one has a 21% chance since the 0 counts and than the spock has 19% chance since it starts with 0.81 – Christian Meyer Oct 27 '19 at 18:27
  • 1
    Would like some more clarification on what @ChristianMeyer said as well – Mark Oct 27 '19 at 18:33
2

With an IF statement, you can have any number of "else if" you need, but only one final else, meaning that if the previous possibilities fail, this is the path to execute. So, you'll need to modify your example to something like:

if (dice <= 0.20) {
  computerChoice = "Rock";
} else if (dice > 0.20 && dice <= 0.40) {
  computerChoice = "Paper";
} else if (dice > 0.40 && dice <= 0.60) {
  computerChoice = "Scissors";
} else if (dice > 0.60 && dice <= 0.80) {
  computerChoice = "Lizard";
} else {
  computerChoice = "Spock";
}
rubenccdev
  • 161
  • 4
  • Correct me if im wrong but you have not a 100% equality since the first one has a 21% chance since the 0 counts and than the spock has 19% chance since it starts with 0.81 – Christian Meyer Oct 27 '19 at 18:27
  • 1
    Probability is practically 20% in all cases. Not 21% or 19% in the cases you mention, as the random generated number has a lot of decimal digits, not only 2. For example, the last option doesn't start with 0.81, a possible random number like 0.80000000000001 could trigger it. True, the 0 is included in the first option, but also the 0.20, 0.40... in the other options. That doesn't make a difference. The only difference I see is in the last option, where 1 is really not a possible value for Math.random. Anyways, given the hugh amount of random number possibilities, this doesn't affect equality. – rubenccdev Oct 27 '19 at 18:55
  • Thanks for pointing that out - you are right i made a little test: http://prntscr.com/poui5r "Anyways, given the hugh amount of random number possibilities, this doesn't affect equality" thats the point. The differences are not measurable. – Christian Meyer Oct 27 '19 at 19:04
-2

Here's a completely automated solution for your problem:

If you wish to have a random option out of an arbitrary Array of values, in an automated way, where your function does not care or know in advance about the number of options, then you can use a bit of math and place it inside an iterator.

The main line of thought in these situations is to go from your maximum value down to the lowest, and this will be tremendously helpful with your if..else statements because it eliminate the need to check if the current value is within a range. All you need to do is just test if the current value is equal or below a certain threshold, but not within a range.

// dice-roller on fixed input Array
const randomOption = options => () => options[Math.floor(Math.random() * options.length)]

// initiailze "randomOption" with an Array of possible values
const getRandomOption = randomOption(["Spock", "Lizard", "Scissors", "Paper", "Rock"])

// roll the dice 10 times
for( let i = 10; i--; )
  console.log(  getRandomOption()  )
vsync
  • 118,978
  • 58
  • 307
  • 400
  • Nice solution. Poor Stack Overflow answer as it doesn't explain anything about what it does, nor does it actually answer the question that was asked. – Scott Marcus Oct 27 '19 at 18:17
  • Actually I am trying to use your solution but I get an undefined error when clicking on any of the 5 (RPSLS) choices – Mark Oct 27 '19 at 18:43
  • @UmarFaruque - Try now, I've refactored it even more. What error? show me in a chat – vsync Oct 27 '19 at 18:48
  • I don't know how to chat you but here is my code that works: https://gyazo.com/b87979943c48aab390c73372fa102492 and here is the result of your solution: https://gyazo.com/dce2c03aef349ed1899dde4ab7b8cdf2 – Mark Oct 27 '19 at 18:59
  • @vsync - I think that a more significant problem is that the code generates wildly uneven results. This is what I got for 10000 iterations: {Spock: 2053, Lizard: 481, Scissors: 779, Paper: 1622, Rock: 5065} – mankowitz Oct 27 '19 at 19:25
  • @vsync - I think you are missing the point. Over 10000 iterations, Math.random will generate a relatively even distribution. It is your math that is incorrect. The last item in the array will be selected 50% of the time, regardless of how many options you have. – mankowitz Oct 27 '19 at 21:54
  • You are looking for something like this: `function computerGamble() { var dice = Math.random(); var states = ["Spock", "Lizard", "Scissors", "Paper", "Rock"] return states.find((result, i) => { return ( dice < (i+1)/(states.length) ) }) }` but even that is inefficient. You should use `Math.floor()` as others suggested. – mankowitz Oct 27 '19 at 22:14