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 and text.
  • 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 the border-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 the alt attribute as well, and add the aria-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:

  1. uses resetRPS to reset the game to start the turn
  2. uses highlightPlayerChoice to highlights the player's choice
  3. uses randomElt to determines the computer's choice
  4. uses showComputerChoice to display that choice
  5. uses rpsJudge to compare the choices to see who won
  6. updates the scores (global variables)
  7. uses updateScores to update the score display
  8. 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

  1. Your name in all files that you wrote
  2. The 'use strict'; directive in all .js files
  3. All functions and top-level variables properly documented
  4. All code neatly laid out, and lines not too long (80 characters is a good limit)
  5. Comments as needed
  6. Folder and files properly named
  7. 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.


  1. 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.