Today’s puzzle, number 14 of the Dev Advent Calendar 🎅, is an elven version of Rock Paper Scissors. Although it is based on a simple game, creating a digital version raises some interesting questions. It is the classic problem that can be solved in different ways. The interesting thing is to understand how to simplify the code, make it readable and above all create a version that can be expanded at will.

The puzzle: Earth-Fire-Snow Game 🌍🔥❄️ aka Rock-Paper-Scissors 💎📜✂️

Today I do different. First I show the solution I submitted for the contest, then I will report my notes on the various alternatives I found.

Let’s start with the code:

It seems a bit strange way of dealing with the problem. I decided not to use the classic if...then...else approach. I also preferred not to deal with the switch variant: there are a thousand tutorials of this type on the net. I did find, however, an old stackoverflow thread full of tricks.

This is an interesting suggestion and a good example of a creative solution. If we observe the rules of the game we have that:

  • Earth extinguishes fire (rock beats scissors)
  • Snow covers earth (paper beats rock)
  • Fire melts snow (scissors beats paper)

If we put them in line we notice an interesting thing:

Earth, Snow, Fire
Rock, Paper, Scissors

Let’s take Snow: snow defeats the elements that precede him and is defeated by those that follow him.

I try to explain myself with a drawing and taking a similar game but with more options: rock-spock-paper-lizard-scissors

I put the symbols in sequence to create a different array for each symbol. The main symbol is in the center and defeats all those who precede it. Instead, all the symbols that follow defeat him.

Due to the way the game is built, the order of the elements of the array is always the same. It means that a single, well-constructed array is enough to handle all the rules.

I can express this concept with a function similar to this one below:

This function is not my bag, it is by Paulo Almeida. It is his idea to use the modulo of a number to generalize the code even more. I also recommend reading this article from a few years ago: Modulo of Negative Numbers.

Code Rock Paper Scissor with if()

This reasoning is not the only way to solve the problem. Guides and videos generally recommend starting with the simple before complicating. For example, this video, quite long but well done, by Ania Kubów presents 3 classic solutions

Solution number 1, rewritten to fit the specifics of the puzzle, is something like this:

I think it’s possible to go a step further and make the code easier. I find a code all the more readable when it avoids the use of conditions. Even only from a visual point of view I prefer to simplify and split the code into smaller pieces.

Code Rock Paper Scissor with ifVal()

Each problem can be broken down into smaller pieces. Each repeated step can be turned into a function. The code repeatedly reports a code similar to this:

I can turn this bit into a function:

In this way I can manage all the Rock Paper Scissors options with a shorter and more readable code:

Code Rock Paper Scissor with switch()

Another way proposed by Ania Kubów involves the use of switch. This makes the code more readable than the previous if sequence.

Code Rock Paper Scissor with match()

I can change this example as well. To do this I use the advice of this post by Hajime Yamasaki Vukelic:

I create the match() function:

Then I use it to manage the rules and solve the puzzle:

Teaching the rules of Rock Paper Scissor to a referee

So far I have approached this problem starting from a list of predefined and known rules. To solve the classic game function is enough. But I can make things more interesting by adding the ability to expand the rules at will.

Of course, the first solution can be easily extended by modifying the array with the rules. But I want to try a different approach. I can create an object (in JavaScript everything is an object, even functions) that learns the rules of the game and has the ability to decide which player won the game. In other words, I want to create a simple AI referee for Rock Paper Scissor.

I create the referee() function:

This function should be able to learn a rule and apply it on demand:

How do I explain the rules to the referee? Well, with examples. For example, I can say that the learn function contains two arguments: in the first place the symbol that wins and in the second the one that loses.

Obviously the referee must have a memory to keep what he learns:

The learn() method allows you to teach the referee the rules. For the base game I get:

This object serves as a memory for the referee. I can use it with judge() to figure out who wins between two combinations of symbols:

If I join all the pieces I get a function that can be used for all the games similar to Rock Paper Scissors:

For example, I can solve the puzzle with:

Or the classic version like with:

Use JavaScript Classes for Rock Paper Scissor

Obviously the next step is to transform the function into a JavaScript class. The concept is roughly the same it changes the syntax of the code slightly:

I can use the Referee() class in my solution in a similar way:

Well, that’s it. As I said at the beginning, using JavaScript for Rock Paper Scissors is a simple problem. Well, that’s it. As I said at the beginning, using JavaScript for Sasso Carta Forbice is a simple problem. However, it is useful for learning more about many aspects of JavaScript.

The other articles in this Christmas series can be found here: