DEV Community

Cover image for Building a rock ๐Ÿงฑ, paper ๐Ÿ“ฐ ,scissor โœ‚๏ธ, lizard ๐ŸฆŽ and spock ๐Ÿ–– game in react
Pramit Marattha for Aviyel Inc

Posted on • Updated on

Building a rock ๐Ÿงฑ, paper ๐Ÿ“ฐ ,scissor โœ‚๏ธ, lizard ๐ŸฆŽ and spock ๐Ÿ–– game in react

In this blog tutorial, we are going to set up and build a rock, paper, scissor, lizard and spock game using react.js from absolutely scratch. If you want to learn more about react, there is a specific article for you.

https://dev.to/aviyel/building-a-react-application-from-absolute-scratch

We will be creating the UI and its functionalities from the ground up. However, before we begin, the final version of the app should resemble this.

demo

You can also view the application's final live version.

rock-paper-scissor-spock-game.netlify.app

Installing react application

Let us begin with our first react application. So, if Node.js isn't already installed on your system, the first thing you should do is install it. So, go to the official Node.js website and install the correct and appropriate version. We need node js so that we can use the node package manager, also known as NPM.

Make a directory

Now, create a blank folder and open it inside the code editor of your choice. For this tutorial, I will be using VScode. Next step, letโ€™s open the integrated terminal and type npx create-react-app music-payer-react-app this command will create the app inside the current directory and that application will be named as rock-paper-scissor

npx script

create react app

It usually takes only a few minutes to install. Normally, we would use npm to download packages into the project, but in this case, we are using npx, the package runner, which will download and configure everything for us so that we can start with an amazing template. It's now time to start our development server, so simply type npm start, and the browser will automatically open react-app.

react application

So, the boilerplate template appears right away. It's now time to look into the file and folder structure provided by create-react-app. All of our node dependencies are stored in a folder called node module. Then there's the public folder, where the index.html file is the only thing that matters. So far, it appears that this is a standard HTML file, complete with head, body, and meta tags. Inside our body tag, you'll notice a div with the id root, followed by the fallback noscript tag, which will be visible only if the user's browser has javascript disabled.

index html

root

So you're probably wondering where the content comes from. Remember that, All of our source code is contained within our source or src folder, and react will inject it into the root div element. Let's take a look at our src folder, which contains some stylesheets, javascript files, and SVG files.

Folder structure

Now, head over to our App.js file

App js boilerplate

In this case, we're simply using standard javascript to import react from react and logo from our logo. Following that, we have a normal javascript function called APP, and this function in react is known as a functional component, and this function is returning a react-element that looks like HTML but is actually an jsx as you can see there is a div tag with a className of APP, and we can't say class by itself because the class is a reserved word in javascript, so we have to use className in jsx. Following that, we have the header and then the image, and notice on the image source that we have our logo, which is actually a javascript variable that we imported at the top, so in order to use the javascript within JSX, we must surround it with curly brackets, and then we have a paragraph, an anchor tag, and that is all for this component.

NOTE: Because of the export, we are able to extract the component and place it on the webpage. Export appears at the bottom of the app.js file, indicating that we are exporting the App function.

So, Now let's look at the index.js file.

index js boilerplate

So, in this case, we're importing react from react again, and this time we're also importing react-dom, and then we're importing the CSS stylesheet file, and finally, we're importing App from App.js, which is the file we just talked about, and there's service worker, which is used to make your application work completely offline. Then we call ReactDom.render, which takes two arguments. The first parameter is the jsx object, and within jsx we can include our user-defined components, so react strict mode is a react defined component, whereas App is a user-defined component. The second parameter is *documented.getElementById('root')*, which targets the root div in our index.html file and is how we access the content in our webpage.

Note: ReactDom renders our content into our root div located at our index.html file.


Creating a rock ๐Ÿงฑ, paper ๐Ÿ“ฐ ,scissor โœ‚๏ธ, lizard ๐ŸฆŽ and spock๐Ÿ–– game.

Let's build a simple rock, paper, scissor, lizard and Spock app in react from the ground up, but first let's make a prototype or mindmap of our final application. So, our final app will look something like this.

Prototype

Before we begin building our projects, we must first clean them up by removing some of the files provided by create-react-app. Your src files should look like this after you've cleaned them up.

Folder structure

Now, within the src folder, make another folder called components, and within that components folder, add the file name called Game.js

Folder structure

Now, go to your Game.js file and create a useState() because this hook will enable us to integrate the state into our functional component. useState(), unlike state in class components, does not work with object values. If necessary, we can use primitives directly and create multiple react hooks for multiple variables. const [state, setState] = useState(initialState); . Hooks in React must always be declared at the top of a function. This also aids in the preservation of state between all rendering for the component.

React Hook: useState()

useState hook

Now create three state computerSelection , userSelection and finalOutput and initialize all with null value.

states

Copy and paste the code below into your Game.js file.

// Game.js

import {useState,useEffect} from "react";

const Game = () => {
  const [computerSelection, setComputerSelection] = useState(null);
  const [userSelection, setUserSelection] = useState(null);
  const [finalOutput, setFinalOutput] = useState(null);

  return (
    <>
      <div>Rock, paper, scissor, lizard and Spock</div>
    </>
  );
};

export default Game;

Enter fullscreen mode Exit fullscreen mode

Now, let's create a function called clickHandler so that whenever a button is clicked, this function is called and a value is passed to it, which is then stored in our computerSelection state.

const clickHandler = (value) => {
    setUserSelection(value);
  };

Enter fullscreen mode Exit fullscreen mode

After that, we'll update the jsx within the return statement.

// Game.js

import React from "react";

const Game = () => {
  const [computerSelection, setComputerSelection] = useState(null);
  const [userSelection, setUserSelection] = useState(null);
  const [finalOutput, setFinalOutput] = useState(null);

  const clickHandler = (value) => {
    setUserSelection(value);
  };

  return (
    <>
      <h1>Rock Paper Scissors lizard Spock</h1>
      <div>
        <div className="container">
          <div className="section">
            <div className="info">
              <h3>You</h3>
            </div>
            <div className="show">{userSelection}</div>
          </div>

          <div className="section">
            <div className="info">
              <h3>Computer</h3>
            </div>
            <div className="show computer">{computerSelection}</div>
          </div>
        </div>
        <h2>Final Output</h2>
        <button onClick={() => clickHandler("๐Ÿงฑ")}>๐Ÿงฑ</button>
        <button onClick={() => clickHandler("๐Ÿ“ฐ")}>๐Ÿ“ฐ</button>
        <button onClick={() => clickHandler("โœ‚๏ธ")}>โœ‚๏ธ</button>
        <button onClick={() => clickHandler("๐ŸฆŽ")}>๐ŸฆŽ</button>
        <button onClick={() => clickHandler("๐Ÿ––")}>๐Ÿ––</button>
      </div>
    </>
  );
};

export default Game;

Enter fullscreen mode Exit fullscreen mode

So now, every time that button is clicked, the clickHanlder function will be called, and the value will be modified. That value will then be transferred to the setUserSelection state, where it will be updated and lastly it will get passed down to userSelection.

It's time to make some selection, and we'll do so with emoji.

  const selection = ["๐Ÿงฑ", "๐Ÿ“ฐ", "โœ‚๏ธ", "๐ŸฆŽ", "๐Ÿ––"];
Enter fullscreen mode Exit fullscreen mode

Now take the selection and map it over each selection, adding a button inside it. After that, your Game component file should look like this.

// Game.js

import React from "react";

const Game = () => {
  const [computerSelection, setComputerSelection] = useState(null);
  const [userSelection, setUserSelection] = useState(null);
  const [finalOutput, setFinalOutput] = useState(null);
  const selection = ["๐Ÿงฑ", "๐Ÿ“ฐ", "โœ‚๏ธ", "๐ŸฆŽ", "๐Ÿ––"];

  const clickHandler = (value) => {
    setUserSelection(value);
  };

  return (
    <>
      <h1>Rock Paper Scissors lizard Spock</h1>
      <div>
        <div className="container">
          <div className="section">
            <div className="info">
              <h3>You</h3>
            </div>
            <div className="show">{userSelection}</div>
          </div>

          <div className="section">
            <div className="info">
              <h3>Computer</h3>
            </div>
            <div className="show computer">{computerSelection}</div>
          </div>
        </div>
        <h2>Final Output</h2>

        <div className="attack-btn">
          {selection.map((select) => (
            <button onClick={() => clickHandler(select)}>{select}</button>
          ))}
        </div>
      </div>
    </>
  );
};

export default Game;
Enter fullscreen mode Exit fullscreen mode

Let's import our Game component into our App.js component, so go to App.js and type import Game from "./components/Game" and then simply use/pass that component inside the return statement.
Your App.js file should resemble something like this.

// App.js

import "./App.css";
import Game from "./components/Game";

function App() {
  return (
    <>
      <Game />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Itโ€™s time to start our development server, so for that simply type npm start and thatโ€™s going to automatically open react-app in the browser.

If you followed all of the steps up to this point, your react app should look something like this.

react app

Now, there may be a warning in your console about the unique key prop, so let's remove that first.

warning

To remove that warning, simply provide a key to your mapped selection inside the Game component.

{
  selection.map((select, index) => (
    <button key={index} onClick={() => clickHandler(select)}>
      {select}
    </button>
  ));
}
Enter fullscreen mode Exit fullscreen mode

Now that we've handled the user choice, let's randomly generate the computer choice. To do this, create a function called randomChoiceGenerator with a variable called randomSelection inside it, and then take the selection array and use the Math.random function to generate the random choices, and finally set that generated value and pass it to the computerSelection state.

const randomChoiceGenerator = () => {
  const randomSelection =
    selection[Math.floor(Math.random() * selection.length)];
  setComputerSelection(randomSelection);
};
Enter fullscreen mode Exit fullscreen mode

To use this function, simply call it from within the previously created clickHandler function.

const clickHandler = (value) => {
  setUserSelection(value);
  randomChoiceGenerator();
};
Enter fullscreen mode Exit fullscreen mode

React Hook: useEffect()

react useEffect

Let's use the useEffect() hooks in our project. By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (weโ€™ll refer to it as our โ€œeffectโ€), and call it later after performing the DOM updates. To this effect, we set the document title, but we could also perform data fetching or call some other imperative API. Placing useEffect() inside the component lets us access the count state variable (or any props) right from the effect. We donโ€™t need a special API to read it โ€” itโ€™s already in the function scope. Hooks embrace JavaScript closures and avoid introducing React-specific APIs where JavaScript already provides a solution.useEffect() hook is somewhat similar to the life-cycle methods that we are aware of for class components. It runs after every render of the component including the initial render. Hence it can be thought of as a combination of componentDidMount, componentDidUpdate, and componentWillUnmount .If we want to control the behavior of when the effect should run (only on initial render, or only when a particular state variable changes), we can pass in dependencies to the effect to do so. This hook also provides a clean-up option to allow cleaning up of resources before the component is destroyed. basic syntax of the effect:useEffect(didUpdate); Here, didUpdate is a function that performs mutations, subscriptions, timers, logging, etc. It will get triggered after the component is rendered to the screen as well as on every subsequently completed render. Now, getting back to our application, let us put this in use to set all the logic behind our application. Add the following code in the Game component:

useEffect(() => {
    {
      switch (userSelection + computerSelection) {
        case "โœ‚๏ธ๐Ÿ“ฐ":
        case "๐Ÿงฑโœ‚๏ธ":
        case "๐Ÿ“ฐ๐Ÿงฑ":
        case "๐ŸฆŽ๐Ÿ“ฐ":
        case "๐Ÿ––โœ‚๏ธ":
        case "๐Ÿงฑ๐ŸฆŽ":
        case "๐Ÿ“ฐ๐Ÿ––":
        case "๐Ÿ––๐Ÿงฑ":
        case "โœ‚๏ธ๐ŸฆŽ":
        case "๐ŸฆŽ๐Ÿ––":
          setFinalOutput("YOU WON! ๐ŸŽ‰");
          break;
        case "๐Ÿ“ฐโœ‚๏ธ":
        case "โœ‚๏ธ๐Ÿงฑ":
        case "๐Ÿงฑ๐Ÿ“ฐ":
        case "๐Ÿ“ฐ๐ŸฆŽ":
        case "โœ‚๏ธ๐Ÿ––":
        case "๐ŸฆŽ๐Ÿงฑ":
        case "๐Ÿ––๐Ÿ“ฐ":
        case "๐Ÿงฑ๐Ÿ––":
        case "๐ŸฆŽโœ‚๏ธ":
        case "๐Ÿ––๐ŸฆŽ":
          setFinalOutput("YOU LOSE! ๐Ÿ‘Ž ");
          break;
        case "๐Ÿงฑ๐Ÿงฑ":
        case "๐Ÿ“ฐ๐Ÿ“ฐ":
        case "โœ‚๏ธโœ‚๏ธ":
        case "๐ŸฆŽ๐ŸฆŽ":
        case "๐Ÿ––๐Ÿ––":
          setFinalOutput("ITS A DRAW! ๐Ÿ’ฅ ");
          break;
      }
    }
  }, [computerSelection, userSelection]);
Enter fullscreen mode Exit fullscreen mode

The logic underlying our application is represented in this illustration.

game logic

Finally, the Game component is locked and ready. The final code inside the Game component should look something like this.

// Game.js

import React, { useEffect, useState } from "react";
import "./Game.css";

const Game = () => {
  const [computerSelection, setComputerSelection] = useState(null);
  const [userSelection, setUserSelection] = useState(null);
  const [finalOutput, setFinalOutput] = useState(null);
  const selection = ["๐Ÿงฑ", "๐Ÿ“ฐ", "โœ‚๏ธ", "๐ŸฆŽ", "๐Ÿ––"];

  const clickHandler = (value) => {
    setUserSelection(value);
    randomChoiceGenerator();
  };

  const randomChoiceGenerator = () => {
    const randomSelection =
      selection[Math.floor(Math.random() * selection.length)];
    setComputerSelection(randomSelection);
  };

  useEffect(() => {
    {
      switch (userSelection + computerSelection) {
        case "โœ‚๏ธ๐Ÿ“ฐ":
        case "๐Ÿงฑโœ‚๏ธ":
        case "๐Ÿ“ฐ๐Ÿงฑ":
        case "๐ŸฆŽ๐Ÿ“ฐ":
        case "๐Ÿ––โœ‚๏ธ":
        case "๐Ÿงฑ๐ŸฆŽ":
        case "๐Ÿ“ฐ๐Ÿ––":
        case "๐Ÿ––๐Ÿงฑ":
        case "โœ‚๏ธ๐ŸฆŽ":
        case "๐ŸฆŽ๐Ÿ––":
          setFinalOutput("YOU WON! ๐ŸŽ‰");
          break;
        case "๐Ÿ“ฐโœ‚๏ธ":
        case "โœ‚๏ธ๐Ÿงฑ":
        case "๐Ÿงฑ๐Ÿ“ฐ":
        case "๐Ÿ“ฐ๐ŸฆŽ":
        case "โœ‚๏ธ๐Ÿ––":
        case "๐ŸฆŽ๐Ÿงฑ":
        case "๐Ÿ––๐Ÿ“ฐ":
        case "๐Ÿงฑ๐Ÿ––":
        case "๐ŸฆŽโœ‚๏ธ":
        case "๐Ÿ––๐ŸฆŽ":
          setFinalOutput("YOU LOSE! ๐Ÿ‘Ž ");
          break;
        case "๐Ÿงฑ๐Ÿงฑ":
        case "๐Ÿ“ฐ๐Ÿ“ฐ":
        case "โœ‚๏ธโœ‚๏ธ":
        case "๐ŸฆŽ๐ŸฆŽ":
        case "๐Ÿ––๐Ÿ––":
          setFinalOutput("ITS A DRAW! ๐Ÿ’ฅ ");
          break;
      }
    }
  }, [computerSelection, userSelection]);

  return (
    <>
      <h1>Rock Paper Scissors lizard Spock</h1>
      <div>
        <div className="container">
          <div className="section">
            <div className="info">
              <h3>You</h3>
            </div>
            <div className="show">{userSelection}</div>
          </div>

          <div className="section">
            <div className="info">
              <h3>Computer</h3>
            </div>
            <div className="show computer">{computerSelection}</div>
          </div>
        </div>
        <h2>{finalOutput} </h2>

        <div className="attack-btn">
          {selection.map((select, index) => (
            <button key={index} onClick={() => clickHandler(select)}>
              {select}
            </button>
          ))}
        </div>
      </div>
    </>
  );
};

export default Game;
Enter fullscreen mode Exit fullscreen mode

Full project CSS and article available here => https://aviyel.com/post/1203

Happy Coding!!

Follow @aviyelHQ or sign-up on Aviyel for early access if you are a project maintainer, contributor, or just an Open Source enthusiast.

Join Aviyel's Discord => Aviyel's world

Twitter =>[https://twitter.com/AviyelHq]

Top comments (5)

Collapse
 
fael profile image
Rafael Santos Sรก • Edited

Nice idea for a tutorial and the attention to some details are nice, like the images.

Since this is an article for beginners, I think it's important to tell them that by using the useEffect + setting a new state, you could be doing unecessary rerendering the game component, it can be problematic, as it's been for me; the alternative is to just compute the result after setting the state and IF the computation is heavy, then optimise it with useMemo (but it'd too much information for a beginner).

Also, I guess you know that the switch case there, although works for teaching the logic, it can be simplified.

I did these changes here: codesandbox.io/s/practical-archite...

Cheers,

Collapse
 
pramit_marattha profile image
Pramit Marattha

๐Ÿ™Œ๐Ÿ™Œ๐Ÿ™Œ

Collapse
 
j471n profile image
Jatin Sharma

It's nice perhaps you should make it responsive. :)

Collapse
 
solotoo_48 profile image
PBt

Not a big deal, but in a few places you've written 'spoke' instead of 'spock'
๐Ÿ––

Collapse
 
pramit_marattha profile image
Pramit Marattha

Thankss !! Fixing it right now !!