Assignment: Rock-Paper-Scissors Game¶
This next assignment will actually not be very much coding, but we'll build something fun (well, somewhat fun)
Learning Goals¶
The purpose of this assignment is
- to practice with event handlers: here there are four event handlers, three of which are very similar.
- to practice with coding in a modular way
- to dynamically update a page as a result of user interaction
- to learn about and use global variables
My Solution¶
Here is my obfuscated solution
Here it is in action:
Directions¶
I'm going to leave all the HTML, CSS and JS coding to you. You are welcome to crib ideas on the HTML and CSS from my solution, but not the JavaScript.
Put your work in a folder called rps
:
cd ~/public_html/cs204-assignments/
mkdir rps
It would be reasonable to copy the HTML and CSS files for my solution:
cd ~/public_html/cs204-assignments/
cp ~cs204/pub/assignments/rps/solution/rps.html rps/
cp ~cs204/pub/assignments/rps/solution/rps.css rps/
You'll write your own JavaScript/jQuery code in rps.js
Buttons¶
Rather than the hyperlink technique that we used in Ottergram, my
solution uses the button
tag. You may use either, but if you use
hyperlinks, make sure you do event.preventDefault()
. To use a
button, just wrap the button tag around the thing that you want to
make into a button (similar to hyperlinks):
<button id="..." attr="val"><img src="images/rock-200.png" alt="rock"></button>
We could make the images themselves clickable, but using buttons or hyperlinks is better because the page is more accessible: browsers know that buttons and hyperlinks are clickable, so assistive technology works better.
Images¶
Getting a copy of the images is the same as for zodiac.
Most of you will be working on Tempest, in which case it's easy to just copy the folder of images:
cd ~/public_html/cs204-assignments/rps/
cp -r ~cs204/pub/downloads/rps-images rps-images
References¶
Much of this is standard JS code. There is no fancy front-end DOM
coding needed for rpsJudge
.
- To highlight the player choice, I suggest the the
css
method jQuery API. - To show the computer choice, use the
attr
method from jQuery. - To show a message, use the
text
method from jQuery. - To reset and start over, use
css
andtext
. - to update scores, use
text
Guidelines/Suggestions¶
Here's how I approached and solved the problem. You don't have to do it my way. You can come up with a different way or follow my suggestions. I've mentioned the function names I used, but you don't have to do that, either.
- write a function,
rpsJudge
, to compare two choices (rock, paper, or scissors) as strings, returning 0 on a tie, 1 if the second argument wins, and -1 if the first argument wins. 1 - re-use the
randomElt
function from the last assignment - write a function,
highlightPlayerChoice
that, given a player's choice as a string, puts a blue border around the choice image. Note that I used a simple trick to get this so that the page doesn't jump around when you do the highlighting. Start (in the static CSS) with a white border around each image/button. Then, the highlighting is just to change theborder-color
to blue. Then it's exactly the same size, so the layout is identical. - write a function,
showComputerChoice
that, given the computer's choice as a string, sets the computer image. This is similar to what you did in the Zodiac assignment. Ideally, you should set thealt
attribute as well, and add thearia-live="polite"
attribute, so that the changed image is announced via assistive technology. - write a function,
resetRPS
, to reset the game (you'll use this at the beginning of each turn). It sets all the player choices back to a white border and clears the previous message. - write a function,
startOver
, to reset the scores (you'll use this when the game starts over). It should also reset the game. - add the latter function as an event handler for the "startOver" button
- write a function,
updateScores
to update the page with the current scores.
I strongly suggest testing each of those in the JS console and ensuring that they work before going on to the next step.
Those building blocks will make the next function, which is big, a bit
easier. I called my function playerTurn
. The playerTurn
function does
all the work to play one round of the game, given the player's choice (as
an argument, a string). That function does the following:
- uses
resetRPS
to reset the game to start the turn - uses
highlightPlayerChoice
to highlights the player's choice - uses
randomElt
to determines the computer's choice - uses
showComputerChoice
to display that choice - uses
rpsJudge
to compare the choices to see who won - updates the scores (global variables)
- uses
updateScores
to update the score display - inserts a message on the page saying the outcome
Button Handlers¶
Finally, the last step is to somehow invoke the playerTurn
function,
with the appropriate argument, when the user clicks on their
choice. The easiest way is not the fancy addThumbClickHandler
technique that Ottergram uses. (Though that can be made to work, of
course, and you're welcome to do that if you'd like.) The easier way
is to add a custom click handler function to each user choice image,
where the only thing that function does is to invoke playerTurn
with
the appropriate argument. Those handler functions can be very simple
anonymous functions, similar to one another, but not identical.
Warning: almost every student has trouble with this last step of adding the button handlers. If you have trouble, you're not alone. Please read this exercise on attaching an event handler
Advice¶
- Build functions that you can test on their own, using the JS console, rather than trying to build everything and test it using the click handlers. All of mine are done that way.
- You can use either raw JS or jQuery to manipulate the DOM. I used jQuery.
- Coding quality matters. Try to be concise and abstract.
- My code, including functions you've already written, and including blank lines, comments and space between functions, is still less than 100 lines.
Testing rpsJudge
¶
Ideally, you should check your rpsJudge function on all 9 possible input pairs. I've provided the following function that you are welcome to use. It has an array of test cases, with the two inputs and the correct output.
function rpsJudgeTester() {
let tests = [ ["rock", "rock", 0],
["rock", "paper", 1],
["rock", "scissors", -1],
["paper", "rock", -1],
["paper", "paper", 0],
["paper", "scissors", 1],
["scissors", "rock", 1],
["scissors", "scissors", 0],
["scissors", "paper", -1] ];
tests.forEach((arr) => {
let [p1, p2, correct_result] = arr;
let your_result = rpsJudge(p1, p2);
let outcome = (your_result == correct_result) ? "CORRECT": "WRONG";
console.log(`for ${p1} versus ${p2}, you computed ${your_result} which is ${outcome}`);
});
}
Note that this function uses some useful coding techniques that we haven't learned; you're welcome to learn more:
Final Checklist¶
- Your name in all files that you wrote
- The
'use strict';
directive in all.js
files - All functions and top-level variables properly documented
- All code neatly laid out, and lines not too long (80 characters is a good limit)
- Comments as needed
- Folder and files properly named
- Submit to Gradescope
How to turn this in¶
We'll grade the work in your cs204-assignments/rps
folder. Upload a
one-page PDF to Gradescope when you are done. No need to do anything else.
Tutors/Graders¶
You can use the password to view the RPS solution.
-
while other encodings of (win, tie, loss) might be perfectly reasonable, I am using an encoding that is also used when sorting. For general sorting algorithms, it's common to provide a comparision function that, for arguments A and B, returns -1 if A precedes B in the sorted result, 0 if they are a tie, and -1 if A follows B in the sorted result. That's my rationale for the return values from this particular function. ↩
Time and Work
Finally, when you have completed the assignment, make sure you fill out the Time and Work report. That report is required.