Sunday, November 10, 2013

Paper Rock Scissors Game Without If – Else If Statements



When writing a JavaScript program to play the paper-rock-scissors game, I came across an interesting way to compute the winner. This method is much more compact than the program that would be constructed using if/else if statements.  It is also more easily extendable to games of N players. 
 
The basic game is the familiar one played by children all over the world: two players make fists, then beat time with their fists while counting out one, two, three; on the third beat they each make one of three forms with their hands: flat for paper, a V-sign for scissors, or  a fist for rock. The winner is determined by the logic that scissors cut paper, paper wraps rock and rock dulls scissors. 
 
Writing a program for the game is straightforward for one player pitted against the computer. The computer picks paper, rock or scissors based on the output of a random number generator. In JavaScript:

var randomVariable = Math.random();  // value between 0 and 1
var computerValue = 0;
computerValue = Math.floor(3*randomVariable); // 0, 1, 2
if (computerValue < 1) {
     computerChoice = "paper";
}
else if(computerValue < 2) {
     computerChoice = "rock";
}
else {
     computerChoice = "scissors";
}

The program would then prompt the user for a choice between the three values and determine the winner. The winner could be determined using the brute force method:
 
    if (userChoice == computerChoice){
        return("It’s a tie.");
    }
    if (userChoice == "rock")
    {
        if(computerChoice == "scissors")
        {
            return("You win!");
        }
        else
        {
            return("I win");
        }
    }

And so on for all combinations. This is easy to understand and straightforward to put together by cutting and pasting the text above and making the necessary changes to each iteration.  This works as long as the programmer is careful to make the right changes to each iteration and double check to make sure that everything was done correctly.

A more elegant method would be to assign a number to each choice and possible outcome, then determine the winner mathematically. Table 1 shows the possible plays and the outcomes. 

Table 1: Possible Plays and Outcomes of Paper Rock Scissors


Computer


Paper
Rock
Scissors
Player
Paper
Tie
Player wins
Computer wins
Rock
Computer wins
Tie
Player wins
Scissors
Player wins
Computer wins
Tie

Translating this to a mathematical form can be done by creating another table with numbered rows and columns. The table is populated with the value of the row subtracted from the value of the row (Table 2). The reason for doing this will be apparent after the next step. 

Table 2. Difference between Row and Column for a 3x3 Array
Column-Row
0
1
2
0
0
1
2
1
-1
0
1
2
-2
-1
0

Next we take the Modulo 3 value for each entry in Table 2

Table 3. Modulo 3 of Difference between Row and Column for a 3x3 Array
Column-Row
0
1
2
0
0
1
2
1
2
0
1
2
1
2
0

Now the effect of all this is clear: a value of 0 in Table 3 corresponds to a Tie in Table 1; a value of 1 corresponds to the Player winning and a value of 2 corresponds to the Computer winning. 

The method of determining the winner is now straightforward. Once the Player and Computer have made their choices as before and the values of Paper, Rock and Scissors have been assigned values of 0, 1, and 2 respectively, the calculation of the winner is made with the formula:

difference = column-row;
if (difference < 0){
     difference = difference + 3;    // difference, modulo 3

The winner is declared using the array:

var winner = new Array();
winner[0] = "It's a tie.";
winner[1] = "You win!";
winner[2] = "I win! Better luck next time.";

and the statement:

console.log(winner[difference]);

The method would be a little difficult to understand without good documentation. At a minimum the programmer should include Table 1 and Table 3 in the comments. The user should be able to pick up on the concept from that and a little explanation.

This works well for the paper rock scissors game with two players. A game with more players could be decided using the same method applied two players at a time. For three players, the winner between the computer and Player 1 would be decided using the method above: once for Player 1 vs. the computer, again for Player 2 vs. the computer and again for Player 1 vs. Player 2. 

That would get a little unwieldy for a large number of players. It would be better to extend the method to N players using 3N-1 layers of the 3x3 array in Table 1, where each element in the array records the winners and losers.The array would be built in advance for N players and the winner would be declared by looking up that element in the array.