Rock Paper Scissors in the DOM

621
0

Make a game in HTML and JavaScript

Introduction

I loved being a game developer ever since I was a teenager, but once it became a career I discovered an interesting side-effect: game development teaches you a ton about software development in general. What’s great about games is that you need to think about data, logic, presentation and interaction. That’s why when I’m trying to teach a new subject to a student, or present it to an audience, I’m trying to gamify the topic. It also makes for a lot of fun and engagement.

This is going to be no different. This article will teach you about HTML, styling, data structures and algorithms combined! We’re going to build a Rock-Paper-Scissors clone using nothing but pure vanilla JavaScript without any external libraries.

It would be helpful if you already have some background in web, or at least software development, but even if you don’t, you will be able to see how much you can achieve with relatively little effort and short code.

What makes this tutorial different from most others floating in the interwebs is the fact that this one is written with professional standards in mind. Other tutorials will get the job done for sure, but you will learn little coding standards from them, so stick around.

The Setup

If you’re kind of new to web development, the following steps might seem intimidating at first, but don’t worry, most of them you’ll need to take care of only once. For future projects you’ll need only to set up your boilerplate files and rest is updates here and there.

First of all we’ll need a text editor (or IDE as it’s sometimes called). We don’t really need anything fancy, but my personal go-to editor is VSCode. So if you don’t have anything installed, you can download it and follow the instructions. I suggest you make sure that the setup also includes the context-menu options. They’ll come in handy later on.

Next thing to do is to verify you’ve got NodeJS installed. If you’re unsure, go to the terminal and type:

npm

If you get an error, then you don’t have Node and need to install it. At any rate make sure you have a recent version. We’ll be using Node as a local server to run our project later.

Once you have Node installed you’ll need another important tool, called Parcel. Parcel is a project bundler. Not only will it provide you with a convenient local server, but also bundle your project, so you can easily deploy it on the web later on. So run the following command from the terminal:

npm install -g parcel-bundler

Once done you’ll need to start with the boilerplate stuff. So let’s start with creating a dedicated folder for the project. Call it something like “snake” and you can create it wherever you feel comfortable as long as your operating system allows.

Once created the folder, right-click it (or CMD+click if you’re using Mac) and select “Open with Code”.

Once VSCode opens, make sure you have the terminal available by selecting Terminal > New Terminal from the menu.

In the terminal type:

npm init -y

This will create the basic files needed to get started.

Then in the left hand part, where you’ll see your project files (you’ll see package.json over there). Create a new file and call it index.html.

To be honest, I personally never remember all of the necessary things needed inside the HTML file. That’s why VSCode comes with a handy shortcut solution. Open the file and type

html

You should see a context menu suggesting several options. Select html:5.

And then magic! You’ll see most of the contents you need are already in place.

You will need to add one bit, though. Add the following tag within the body tags:

<script src="src/main.js"></script>

Now create a new folder from the project panel called src. Within it create a new file called main.js.

Also create the following files in that same folder:

game.js

view.js

controller.js

Also create the following stylesheet to make things more presentable. Call it stylesheet.css and put it next to the html file (outside the src folder!):

 button.btn {
     cursor: pointer;
     border-style: solid;
     padding: 1rem;
     background: rebeccapurple;
     color: white;
     border: 3px solid black;
     border-radius: 1rem;
     font-size: 2rem;
 }
 .buttons {
     display: flex;
     justify-content: space-evenly;
 }
 h2 {
     text-align: center;
 }
 .hidden {
     display: none;
 }
 .icons > .rock, .icons > .paper, .icons > .scissors {
     font-size: 10rem;
 }
 .players {
     display: flex;
     flex-wrap: wrap;
     justify-content: space-around;
 }
 .icons {
     display: flex;
     flex-direction: row;
     align-items: center;
     height: 20rem;
     justify-content: center;
 }
 .player, .cpu {
     display: flex;
     flex-direction: column;
     width: 40rem;
 }
 .separator {
     height: 20rem;
     border: 5px solid rgb(43, 32, 32);
     border-radius: 5px;
 } 

Make sure you HTML file looks like this:

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Document</title>
 </head>
 <body>
     <h1>Score Me: <span id="playerScore"></span> | CPU: <span id="cpuScore"></span></h1>
     <div class="players">
         <div class="player">
             <div class="icons">
                 <p class="rock">✊</p>
                 <p class="paper">✋</p>
                 <p class="scissors">✌️</p>
             </div>
             <h2>Player</h2>
             <div class="buttons">
                 <button class="btn rock">Rock</button>
                 <button class="btn paper">Paper</button>
                 <button class="btn scissors">Scissors</button>
             </div>
         </div>
         <div class="separator"></div>
         <div class="cpu">
             <div class="icons">
                 <p class="rock">✊</p>
                 <p class="paper">✋</p>
                 <p class="scissors">✌️</p>
             </div>
             <h2>CPU</h2>
         </div>
     </div>
     <script src="src/main.js"></script>
 </body>
 </html> 

Save the file and from the terminal type the following:

parcel index.html

You should see a message that there’s a server running at something like https://stackcodify.com:1234

Hover the URL with your cursor and follow the instructions to open the link. You should see the basic game layout sans interactivity.

That’s it. We’ve done all the boilerplate work. Time to get serious.

Design First – Code Later

An important concept in software development you should know about is MVC, or the Model View Controller design pattern. Here’s the idea behind it.

When you think about a game, for example, there’s going to be some data behind it, for example the player’s score. There is also going to be logic, such as under what conditions the game ends? This is the model.

The game also has to present itself to the player somehow. So the actual graphic manipulation is the view (also sound for the matter).

The player should have a means to manipulate the game, or control it. So there’s a controller – the means by which the model and view are manipulated.

I’m not going to go much into detail here, but in a well-crafted software those 3 entities should co-exist as separated as possible. You should be able to set the game rules, but change the presentation easily without breaking the model. You should also be able to change the controller without breaking anything else. For example if you wish to change the look and feel of the game, or you wish to switch from keyboard to gamepad, the game should play the same nonetheless.

In our case we’re going to give minimal concern to the presentation, because styling the game will be easier later. We’re also not going to pay too much attention to the controls. It’s just some button click bindings. Our main interest is the model and how to tie everything together.

So what is the model in RPS? It has several elements and rules:

  • There’s some sort of layout for the game elements.
  • The player and CPU (i.e. computer) have scores.
  • There is an icon for the player’s choice and one for the CPU.
  • The player has a set of buttons to make her move.

Rules:

  • Both scores start at 0.
  • The player makes the first move by clicking one of the buttons.
  • The CPU responds almost immediately with a random move.
  • The moves are evaluated against the regular rules and the winner picks up a point.
  • The game has no end.

On top of that you can add whatever rules you like, such as end game conditions etc.

We’re going to have 3 files which represent the MVC and a main file to arrange all. The controller needs to be aware of the other two, so it can manipulate and follow the game state as well as the view.

Some Words About Coding Conventions

There are many ways to make this game work. But I have a fondness for ES6 modules, since they are considered standard and allow us to separate code and import it from one file to another with ease.

The Model

Our model, or game file, will be our starting point. It’s going to have the following variables (sometimes called fields or properties):

  • constructor – initializes everything when the game is created
  • cpuScore – numeric
  • playerScore – numeric

It also has two functions (normally called methods in a class context):

  • constructor – initializes values
  • makeMove – picks a move at random
  • evaluate – compares both player moves and change the score accordingly
 export class Game {
     constructor() {
         this.cpuScore = 0
         this.playerScore = 0
     }
     makeMove() {}
     evaluate(playerMove, cpuMove) {}
 } 

The View

The view has only one variable:

  • domElements – this is an object with reference to all the elements to be manipulated
 export class View {
     constructor(domElements) {
         this.domElements = domElements
     }
     updateScore(playerScore, cpuScore) {}
     hideIcons() {}
     hide(element) {}
     show(elementName) {}
 } 

It has several methods:

  • constructor – initializes everything when the view is created.
  • updateScore – updates the score.
  • hideIcons – hides all the icons by calling the next method one-by-one.
  • hide – hides an element by adding a custom CSS class.
  • show – shows a hidden element by removing its respective CSS class.

The Controller

The controller has a couple of methods:

  • constructor – initializes everything when the controller is created – it hides the icons and sets up listeners for mouse click events. It also resets the score.
  • play – makes a move, waits for a counter move, evaluates and updates.
 export class Controller {
     constructor(game, view, domElements) {
         this.game = game
         this.view = view
     }
     play(playerMove) {}
 } 

The Shared File

There’s another useful file: shared.js. It serves for one purpose: to have constant values for the words rock, paper & scissors. The idea is to prevent typos when reusing them throughout the application.

 export const ROCK = 'rock'
 export const PAPER = 'paper'
 export const SCISSORS = 'scissors' 

Conclusion

In this article we have covered how to create a web based game using HTML, modern vanilla (plain) JavaScript and CSS. The main focus was how to approach the project before implementing it.

You can find the actual code implementation in the project’s GitHub repository. You can also clone the project and expand it. The project also uses a stylesheet to make it a little better than default. But you can create your own designs naturally.

If you look closely, you’ll notice the project modules are rather separated as is encouraged by MVC and good coding practices in general. The game can live on its own and so can the view. This allows great flexibility if you wish to apply different logic to the view, or a different view to the logic. The current implementation doesn’t strive to be perfect or efficient. It can be implemented in numerous other ways. But as stated before, it is meant to be a professional example for such a project.

Although rather simple, beginners might find themselves a little wondering about what’s going on. Don’t worry too much. It takes time, patience and practice to become experts.

If you wish to learn more about software development, you can find more in my personal blog. If you need expert help and mentorship, you can also find me on Codementor.

Happy coding!

Gil Steiner
WRITTEN BY

Gil Steiner

Senior software developer with game dev specialization. Currently doing full stack web dev and front end automation.

Newsletter

Loading