Rock Paper Scissors

(ToC)


This Video link and the text below it are essentially the same, except the links in the text are hot:

RPS Introduction (No) Video (0 minutes) Transcript follows below

Video Transcript: 6. Rock Paper Scissors Introduction

Almost everybody knows how to play Rock Paper Scissors. If you never even saw it played, Google
How to play Rock Paper Scissors
Rock Paper Scissors is a hand-motion game played between two people. Today we will write a computer program (in English) that plays one of those people (the other player is still a person). You should design your program as a description of what the one player does -- except the computer has no hands and watching the other person is too hard at your present skill level, so we will use text input and output instead of hand motions.

By this time, you should have already worked your way through PBJ, Calculator, and the Guessing Game. You should already be familiar with the process of defining your computer program in English, then converting every part of that description into one of the Five Concepts, after which it should run in the English Computer. If you missed or skipped over these informational sessions, or if you find the next step difficult, you might go back and review one or more of these preparational sessions:

1. You Already Know How
2. Conditionals & Input
3. Iteration & Variables
4. Calculator
5. Guessing Game
Three times you watched me go from a vague idea to runnable code, three different programs.

Now you try it on your own. Click this button to open our "Integrated Development Environment" in a new window, which you can position to one side or above or below the instructions in this page:

 
Button to open IDE
If you don't know how to begin, Watch this video to see if it helps:
RPS Design Video (2 minutes) Transcript below


If you are doing fine, but don't know how to generate a random number for the computer play, Watch this video (or read the transcript):

Choosing Random Rock Paper or Scissors (2 minutes) Transcript below
If you cannot find a simple way to compare the computer and human plays, Watch this video (or read the transcript):
Comparing Rock Paper and Scissors (6 minutes) Transcript below
If you have an English description of your game, but you do not know how to turn it into lines of "Five Concepts" items, Raise your hand in Zoom to get a Mentor to look at your description and suggest a way forward.

If each line of the English description of your game already begins with one of the keywords in the Reference section from the English IDE, but your program misbehaves when you try to run it, Watch this video to see if it helps:

Debugging Video (0 minutes) (Transcript) [video & transcript not ready yet]
If you didn't see anything in the video to help your situation, Raise your hand in Zoom to get a Mentor to look at your program and suggest a way forward.

When your game runs, Raise your hand in Zoom to continue.

If you are like me and prefer to read at your own pace instead of whatever pace set in some video, You can read the transcripts here.


Video Transcript: 6a. Rock Paper Scissors: Defining the Problem

Rock Paper Scissors is a game played between two people. You will write a program that plays one of those two people. RPS is normally played with hand motions, but your program will use text input and output. When two people play RPS, one of them usually calls out the synchronization and announces the scoring; your program will be that person.

First of all, we will consider a single play. It has three parts:

1. Synchronization

2. Presenting the plays

3. Deciding the winner

The synchronization is faked. The computer is very much faster than any human, so we will have it print out the words at one-second intervals, nothing more.

The computer can decide its play any time before reading the human play as input. There are numerous internet resources that purport to offer a winning strategy, but if any of them actually worked, and if both players used that strategy, it wouldn't work. I suggest your first cut use a random number to decide (more about random numbers later). Your program will then announce both plays,...

and decide who won (or if it's a tie), and print out that decision. More about the decision later.

In simple English, the program looks like this

Print "One"
Wait 1 second
Print "Two"
Wait 1 second
Print "Three"
{decide what to play}
Let myPlay = {whatever}
Input HumPlay
Print "I played " myPlay ", you played " HumPlay
{compare plays}
{announce winner}

Video Transcript: 6b. Choosing Random Rock Paper or Scissors

"Random" is a perfectly good English word, and the English computer knows it. If you say:
Random r
it will set variable r to some random fractional number between 0 and 1 (always less than 1). Most programming languages have a library routine that does the same thing. What we want is a discrete random number that comes back with one of only three values (rock, paper, or scissors). This is a very common requirement in games -- flip a coin: either heads or tails; roll a die: one of six; pick a card out of a shuffled deck: one out of 52; etc. -- so most random number generators have a variant that does that. When we get to Java you will learn how they spell it (it's exactly the same result, just a matter of spelling).

You can get there with simple arithmetic on the default random number by multiplying that default random fraction times the number of values you want it to choose from, then truncating it to an integer (whole number), like this:

Random r
let r = r*3
Truncate r
Or you can use the built-in random integer option in English:
Random r < 3
which reads "Give me a random number less than 3."

Converting that to the computer play is as simple as:

Random r < 3
if r=0 then Let myPlay = "rock"
if r=1 then Let myPlay = "paper"
Otherwise Let myPlay = "scissors"


Don't forget to declare myPlay to be a variable somewhere. You can do that in English by presetting it as the default:

Variable myPlay = "scissors"
Random r < 3
if r=0 then Let myPlay = "rock"
if r=1 then Let myPlay = "paper"


If the English computer didn't know about random numbers, you could still get something like that from the time of day, basically derived from the remainder when the number of seconds in the wall clock time is divided by three. The human player will take some variable number of seconds to type in their input, so that the wall clock time cannot be accurately predicted. That makes it a pretty good random number.

For example, at 8:44:29 in the morning, the seconds (from midnight) is 31469. If you divide this by 3 and truncate it to a whole number, you get 10489. Multiply that times 3 again gives 31467, so the remainder of the original division is the difference, =2. The remainder will always be 0 or 1 or 2, so you can use it to choose between rock, paper, or scissors for your play, and it will be reasonably random.

In English you'd write:

put the seconds into s
let d = s/3
Truncate d {to a whole number}
let r = s-d*3 {= the remainder}
if r=0 let myPlay = "rock"
if r=1 let myPlay = "paper"
otherwise let myPlay = "scissors"
print "Seconds = " s ", I got " r "=" myPlay {for testing only}
Don't forget to declare Variable myPlay somewhere.


Video Transcript: 6c. Comparing Rock Paper and Scissors

You cannot just compare the words "rock" to (for example) "scissors" because the normal alphabetic sort has both paper and scissors greater than rock. It's a bit tedious, but you can try all nine possible combinations, one at a time, where score>0 is the computer won, <0 is the human won:
if myPlay = "rock" then if HumPlay = "rock" then let score = 0
if myPlay = "rock" then if HumPlay = "paper" then let score = -1
if myPlay = "rock" then if HumPlay = "scissors" then let score = 1
if myPlay = "paper" then if HumPlay = "rock" then let score = 1
...
or you could preset a default, and reduce it to the six comparisons that are not a tie:
let score = 0
if myPlay = "rock" then if HumPlay = "paper" then let score = 1
if myPlay = "rock" then if HumPlay = "scissors" then let score = -1
...
You cannot use "otherwise" here because the mixed true/false tests confuse the English computer (for example, if both the human and the computer chose rock, the first compare is true, so English assumes no otherwise applies).

Some programming languages let you combine the multiple conditions using "and" or "or" but the English computer does not understand those words.

When you are playing this game, you will quickly see what a drag it is to type in the whole eight letters of "scissors" (or even the four or five of "rock" or "paper"), and if you don't spell it exactly right, the compare will fail and you can't win. Usually games like this let the user type in just a single letter (the first letter is unique among the three). The English computer will even capitalize it for you, so that it doesn't matter whether the user has caps-lock set or not:

Input HumPlay,1
Of course you must change the generated myPlay to be "R", "P", or "S" to match.

This much works, and you can stop here.

If you like math, there's a really elegant approach you might be interested in. If math is not your thing, just stop here, and you will have a working program. Otherwise...

If you convert the two plays into numbers (basically reverse the calculation you did for deciding the computer play) and multiply either of them (not both) times a larger number (three or ten) then adding them together gives you one of nine unique numbers, which you can test with a single conditional (so otherwise works) and your code is a little simpler, but not so easy to understand:

let h = 0
if HumPlay = "P" then let h = 1
if HumPlay = "S" then let h = 2
let score = h*10+r  {r is still 0/1/2 from the random calc}
if score=01 then let score = -1 {h=rock, r=paper, comp wins}
if score=10 then let score = 1 {r=rock, h=paper, hum wins}
if score=12 then let score = -1 {h=paper, r=scis, comp wins}
...
otherwise let score = 0  {00 or 11 or 22 = tie}


A more mathematical approach would be where you convert the plays into the ternary number system (base 3, assuming they taught you that in school), then the difference would be the desired score. [If you do not understand strange number systems like ternary, then you might have trouble understanding this, but you could Google "ternary number" for a better understanding.] Where other number systems are generally all positive, base-3 is often represented as zero and plus or minus 1. Here is the subtraction table (read the human play along the top, minus the computer play down the left, and the score is the table value:

 
H-C -1=R 0=P 1=S
-1=R -1 
0=P -1 
1=S -1 
For example, if the human plays rock (1st column) and the computer plays rock also (1st row), then the difference is zero, a tie. If the computer plays paper (zero, second row), that beats the computer's rock (-1: the human lost). If the computer plays scissors  (bottom row) to the human rock, rock breaks scissors (+1, the human won). And so on.

So your code might look something like this:

let score = 0
if HumPlay = "R" then let score = -1
if HumPlay = "Z" then let score = 1
if myPlay = "R" then let score = score+1
if myPlay = "S" then let score = score-1
if score>1 then let score = -1
if score<-1 then let score = 1


The first three lines convert the human play to ternary. The next two combine turning the computer play into ternary and subtracting it from the human play. The difference (in ternary, but not decimal) will be +1 if the human won, and -1 if the computer won, which is exactly what we want to know.

You already have numbers for the computer play (from Random), you can subtract one from that value to convert it into signed ternary, and then those two "myPlay" conditionals turn into a simple subtract:

let score = score-(r-1)


You can also combine those last two lines into one. If you subtract -1 from +1, the result (in decimal) is +2, which is out of range, it needs to be wrapped around to -1; that's the first of the two lines. The other way around it goes negative to -2 and must wrap around to +1 in the other line. In both cases the intermediate result is (plus or minus) two, which squared is +4. The wrap-around wants to be the negative of whatever you had, but one instead of two, like this:

if score*score=4 then let score = -score/2


This is a little shorter than the six compare lines, but carries oh so much more bragging rights (assuming you understand how it works). If you get lost in the math, stick with the six compare lines above: it's much more important that you understand what your program does (and therefore it works and you can explain it) than that it looks elegant but fails in ways you do not understand and Bad Things Happen. Programmers do not go to jail* for writing bad code today, but in your lifetime that will start to happen. Don't be one of them: it might be too late after you find out.


If you still have trouble, Raise your hand in Zoom to get a Mentor to look at your program and suggest a way forward.
 

[2021 August 31]

* Jail: Most of the people designing autonomous cars truly believe that cars can be smarter than the people who designed them. If they convince enough legislatures and governors to agree, there will be a million autonomous cars and trucks out there on the streets in your lifetime. Even if the cars are smarter than people (and the physics says otherwise), accidents will happen, stupid people will get in the way of the cars, and at first they will blame the owner. Then a celebrity will lose her child and hire a high-priced law firm, and they will go after the manufacturers, who will offer up the programmers as scape-goats. That will be the end of autonomous vehicles on city streets for a couple centuries, but the floodgates will already be open. Once they get a few programmers in jail, all those fine-print "Licenses" you must agree to when you start up a new program will go in the trash and programmers everywhere will be required to defend their code or go to jail. You need to be ready for it, because this will happen in your lifetime.