Search

Scissors, Paper or Rock?

In this article, I'm going to tackle a children's game that's extraordinarily
complicated, with many variations, and the programming task is going to be quite
tricky. Just kidding! Rock Paper Scissors (or RPS, as it's known) is
pretty darn easy to simulate because there aren't really many variants or
possible outcomes.

If you've never played it before, it's a one-vs.-one game where each person
secretly chooses one of three possible options (rock, paper or, you guessed it,
scissors). The players reveal their choices simultaneously, and then there are rules about
what beats what. For example, scissors beats paper because "scissors cut
paper", and rock beats scissors because "rock beats scissors". If both
players pick the same option, it's a tie and the game proceeds.

Although you can play it as a one-off, it's also generally played as a best of
three to even things out slightly, although if everything's completely random,
you'll win 33.33% of the time. For any given choice, there's a 1/3 chance
that you'll have a tie, where both players pick the same thing, a 1/3 chance that
you'll win, and a 1/3 chance that you'll lose.

The World Rock Paper Scissors Society

Except, in the real game, it turns out that there's psychology involved too. In
fact, according to the World Rock, Paper, Scissors
Society,
rock is chosen 35.4%, paper 35% of the time and scissors only 29.6% of the time. Got
it?

For the first version of the program, however, let's stick with a completely
random choice. The easy way to choose a random number between 1 and 3 in a Linux shell
script is to use the variable $RANDOM like this:

compchoice=$(( ($RANDOM % 3) + 1 ))

The % is a modulus function and causes the random integer to be divided by
3, resulting in a 0..2 value. Add one, and you've got the 1...3 value. Easy
enough.

With a simple shell array, you can add the name of the choice (remember, arrays
start at index 0):

declare -a RPS; RPS=(nothing rock paper scissors)

Then the choice name is specified simply as:

choicename=${RPS[$compchoice]}

Those three lines are good enough for a tiny script where the computer can
choose randomly between rock, paper and scissors:

It's considerably more fun to have the computer prompt users for their
selection, then "choose" its own and decide who won.

Making It into a Game

Interactivity is easily added by prompting users to choose whether they want rock,
paper or scissors using a numeric value. Even better, you can prompt them using the
same numeric values you're using internally:

Now you need to compare answers and generate a result message. This is best done in a
function, either standalone or by including an output string and tracking win/loss.
I'll go for overkill (of course), so here's my function:

It's straightforward, just a lot of typing. But really, that's 95% of the program.
All you need is a looping mechanism so that you're "stuck" in the
program until you get sick of the game—I mean ready to wrap things up.

Notice that the above code tracks wins, but not total games played; that'll
have to be done in the main code, which, of course, is pretty straightforward
because of how much of the code is pushed into the
results() function:

When I tried it, I had a surprisingly longer-term result: an all-scissors strategy
produced a 50% win rate (six games out of 12). Statistically that's unlikely if the computer
really is picking randomly, but sometimes random is not so random.

In fact, playing all paper won only four of 14 games on a trial, and rock, the most
popular choice? That produces a win rate of three out of 14—worse than paper!

Matching Probabilities

The biggest change you could make to this program to match the
"real" choice
statistics is to stop picking randomly and instead reflect the percentages that the
Rock Paper Scissors Society publishes: rock is chosen 35.4%, paper 35%
and scissors only 29.6% of the time.

The easiest way to model that is to choose a random number between 1–1000 and then say
that 1–354 is rock, 355–705 is paper, and 706–1000 is scissors. Instead of a single
line where the number is being chosen, a function would be well written, and
it's pretty darn easy.

The other area you can expand this is to add a few more possibilities, and I bet most
everyone reading this knows how to add "lizard" and
"Spock" to the
mix. Not sure? Here's how a
five-object RPS game works.

So there you have it. Scientific? Not really. But, uh, rock, paper,
scissors—come
on!

Dave Taylor has been hacking shell scripts on UNIX and Linux systems for a
really long time. He's the author of Learning Unix for Mac OS
X and Wicked Cool Shell Scripts. You can find him on Twitter
as @DaveTaylor, and you can reach him through his tech Q&A site: Ask Dave Taylor.