An Object-Oriented Approach to the Classic Rock, Paper, Scissors Algorithm in Javascript to Facilitate Extensibility

If you’ve been to college, a programming boot camp, or coding academy you have almost definitely at some point been assigned to code your own version of “Rock, Paper, and Scissors.”
You might have even done what most people do — just whip out a few comparisons, call it a day, and head down to the student union to quaff some root beers and slam ping-pong balls around.
Does this look familiar? Of course it does:
const rockPaperScissors = (hand1, hand2) => {hand1=hand1.toLowerCase().trim();hand2=hand2.toLowerCase().trim();if (hand1==="rock"){if (hand2==="rock") {return "It's a tie!"}if (hand2==="paper") {return "Hand two wins!"}if (hand2==="scissors") {return "Hand one wins!"}}if (hand1==="paper") {if (hand2==="rock") {return "Hand one wins"}if (hand2==="paper") {return "It's a tie!"}if (hand2==="scissors") {return "Hand two wins!"}}if (hand1==="scissors"){if (hand2==="rock") {return "Hand two wins!"}if (hand2==="paper") {return "Hand one wins!"}if (hand2==="scissors") {return "It's a tie!"}}}
And yes, I’m not saying that won’t work, or that you won’t get an A, pass the class, and get hired by some multinational gaming company for your comparison-operator skills.
But that’s when the boss comes in one day and says, “If you could go ahead and add a ‘lizard’ and ‘spock’ element to our existing Rock, Paper, Scissors game that would be great.”
So what are you going to do now? Just keep hardcoding comparisons every time the company wants to extend your code functionality? Object-oriented programming is here to save the day!
What if we were to think of the possible hands that can be played in a round as objects? Suppose there were only three of them, along with the associated properties that each has:
Rock => Beats Scissors => Loses to Paper
Paper => Beats Rock => Loses to Scissors
Scissors => Beats Paper => Loses to Rock
These are just the things we know about each possible move and, coincidentally, are also the exact structure of a PHP object, just in a different form. Suppose we wrote all that like this:
var choices = [{"choice": "rock","beats": "scissors","losesTo": "paper"},{"choice": "paper","beats": "rock","losesTo": "scissors"},{"choice": "scissors","beats": "paper","losesTo": "rock"}];
All we’ve done is enumerated what we already wrote into an array of objects that we can now manipulate for our own nefarious purposes (say “muahaha” here).
Then you can have the player make his choice, and when it’s the computer’s turn it can also choose from the same list of possibilities like this:
player2Choice = choices[getRandomInt(choices.length)].choice
(getRandomInt) is just a function to provide a random number between 0 and your desired maximum. Here it is for your convenience:
function getRandomInt(max) {return Math.floor(Math.random() * Math.floor(max));}
Then all you have to do now is process an object-oriented comparison between the player’s choice and the computer’s choice to tell who won the round. For that we will just cycle through the possible choices, see which player had which one, and also determine who had the advantage:
for (var gameTurn in choices) {// only respond to valid input// search through the object array until we find a "choices"// that matches our playif(playerChoice===choices[gameTurn].choice) {//// Show what the computer chose//console.log("Player 2 chose: " + player2Choice);// check the gameTurn dynamic to see who won and output the resultsif(choices[gameTurn].losesTo.includes(player2Choice)) {losses++;console.log("You lose, bruh");}else if(choices[gameTurn].beats.includes(player2Choice)) {wins++;console.log("You win!");} else {ties++;console.log("Tie game");}}};
You may notice the obvious sparsity of “===” operators and carpal tunnel involved. But that’s not even the great thing about it.
Because now is when Bill Lumbergh shows up at your desk with his cup of coffee and perfectly reasonable request to extend your function to include, not two, not three, but 5 thousand other possible options.
Now, thanks to good ‘ol OOP, you can just flex your knuckles and smile. Because due to your diligent coding skills and proper-prior-planning, all you have to do at all is this:
var choices = [{"choice": "rock","beats": ["scissors","lizard"],"losesTo": ["paper","spock"],},{"choice": "paper","beats": ["rock","spock"],"losesTo": ["scissors","lizard"],},{"choice": "scissors","beats": ["paper","lizard"],"losesTo": ["rock","spock"],},{"choice" : "lizard","beats": ["paper","spock"],"losesTo": ["rock","scissors"],},{"choice": "spock","beats" : ["scissors","rock"],"losesTo": ["lizard","paper"]}];
Why is this important? Because the Rock, Paper, Scissors dynamic can be used in more situations than one. It’s a classic example of having a group of items in which each item has both an advantage and a disadvantage over other members of the group.
Think pokemon, military units, chess pieces, … and so on.
By keeping your code flexible and dynamic you have facilitated scalability and extensibility while at the same time “keeping your boss’s boss off your boss’s back.” Cuz that’s what it’s all about.
Especially when Lumbergh comes back with this:

Because now you can tell him it’ll take all day, just add a few new options to your choices object and head on down to the student union for some ping-pong.
You’ve earned it.