Skip to content
Related Articles

Related Articles

Create Rock Paper Scissor Game using ReactJS
  • Last Updated : 10 Dec, 2020

Here both the players will take their turn one by one. Starting with player one followed by player two. There are three weapons to select from namely stone, paper, scissors. Once player two plays his turn result is computed updating the win/lose the status of both the players.

Technologies Used / Pre-requisites:

  1. ReactJS
  2. Antd library for UI

Approach: Containers are ​ Stateful​ React components ( Class Based ). Components are ​ Stateless​ React Components ( Function-Based ). In this project, I have one container that is Controller which is responsible for state management and the entire game logic. Also, there are three components namely:

Player ->Represent​ing a Player entity in-game;
GameControls -> For Choosing stone, paper, or scissor; 
DecisionBox -> Displays win/loose status for players;

On clicking weapon buttons state in Controller is updated for the respective player. When the second player’s weapon is updated result is computed by the result handler function which covers all nine combinations of stone, paper, scissors taken two at a time.

Project Structure:



Steps :

  1. Set up React project using create-react-app command: create-react-app <<name of project>> –scripts-version 1.1.5. Using this command project structure like above will be generated except components and container folders that are to be created inside src folder manually.
  2. Install antd library using the command: npm install antd
  3. Remove the code inside App.css.
  4. Edit code inside App.js: App Component renders Controller and displays title.
    App.js

    Javascript

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    import React, { Component } from "react";
    import Controller from "./containers/controller/controller";
    import { Typography } from "antd";
      
    import "antd/dist/antd.css";
      
    import "./App.css";
    const { Title } = Typography;
      
    class App extends Component {
      render() {
        return (
          <div className="App">
            <Title level={3} style={{ textAlign: "center" }}>
              Stone Paper Scissor
            </Title>
            <Controller />
          </div>
        );
      }
    }
      
    export default App;

    chevron_right

    
    

  5. Controller.js: The controller holds a state which includes each player’s last used weapon, current win/loose status, and active state indicating which player’s turn it is

    Javascript

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    import React, { Component } from "react";
    import { Row, Col, Divider } from "antd";
    import { Typography } from "antd";
    import axios from "axios";
    import "antd/dist/antd.css";
      
    import Player from "../../components/Player/Player";
    const { Title } = Typography;
      
    class Controller extends Component {
      state = {
        playerOne: {
          active: true,
          weapon: "",
          status: ""
        },
        playerTwo: {
          active: false,
          weapon: "",
          status: ""
        }
      };

    chevron_right

    
    

    The core idea here is that on clicking weapon buttons corresponding player’s weapon in the state should get updated and the next player’s turn should come which is done here via toggleactive function. Also, if the second player’s weapon is updated then win/loose should be updated too which is done here via resultHandler function. For game logic it holds a bunch of functions :

    • WeaponUpdate: For updating a player’s weapon in the state. It takes two arguments first is playerId i.e playerOne or playerTwo since it’s a two-player game and the second is a weapon that is chosen by the player.

      Javascript



      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      weaponUpdate = (player, weapon) => {this.setState({
      [player]: {
      ...this.state[player],
      weapon: weapon
      }
      });
      if (player == "playerTwo") {
      this.resultHandler();
      } else {
      this.toggleActive();
      }
      };

      chevron_right

      
      

    • ToggleActive: For reversing active status of players once either of player selects a weapon. Active property in the state is a boolean variable, so we just have to use NOT operator to reverse the current state of each player.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      toggleActive = () => {
      this.setState(prevState => {
      return {
      ...prevState,
      playerOne: {
      ...prevState.playerOne,
      active: !prevState.playerOne.active
      },
      playerTwo: {
      ...prevState.playerTwo,
      active: !prevState.playerTwo.active
      }
      };
      });
      };

      chevron_right

      
      

    • ResultHandler: It contains the major game logic which decides which player has won. It uses a helper function called decision helper which takes two arguments that are each player’s weapon and returns an array containing two elements wherein the first element corresponds to the first player’s win/loose status and similarly the second element to the second player’s status. Then resulthandler updates state with values returned by decicerhelper function.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      resultHandler = () => {
      this.setState(prevState => {
      let [s1, s2] = this.deciderHelper(
      prevState.playerOne.weapon,
      prevState.playerTwo.weapon);
      return {
      ...prevState,
      playerOne: {
      ...prevState.playerOne,
      status: s1
      },
      playerTwo: {
      ...prevState.playerTwo,
      status: s2
      }
      };
      });
      this.toggleActive();
      };

      chevron_right

      
      

    • DeciderHelper: It is a helper function that takes two inputs that are weapons for each player and returns an array consisting of two elements each denoting the win/loose status of player 1 and player 2 respectively. Here ‘r’ stands for rock, ‘s’ stands for scissors, ‘p’ stands for the paper, ‘w’ for the win, and ‘l’ stands for loose. All possible combinations of rock, stone, scissors are considered in case of a tie both players with win status are returned.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      deciderHelper = (p1, p2) => {
        if (p1 == "r" && p2 == "s") {
          return ["w", "l"];
        }
       
        if (p1 == "r" && p2 == "p") {
          return ["l", "w"];
        }
       
        if (p1 == "r" && p2 == "r") {
          return ["w", "w"];
        }
       
        if (p1 == "p" && p2 == "r") {
          return ["w", "l"];
        }
        if (p1 == "p" && p2 == "s") {
          return ["l", "w"];
        }
        if (p1 == "p" && p2 == "p") {
          return ["w", "w"];
        }
        if (p1 == "s" && p2 == "r") {
          return ["l", "w"];
        }
        if (p1 == "s" && p2 == "p") {
          return ["w", "l"];
        }
        if (p1 == "s" && p2 == "s") {
          return ["w", "w"];
        }
      };

      chevron_right

      
      

    • Render Method:

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      render() {
          return (
            <Row justify="space-around" align="middle">
              <Col className="gutter-row" xs={15} sm={15} md={5} lg={5}>
                <Title level={3}>Player One</Title>
                <Player
                  active={this.state.playerOne.active}
                  weaponUpdate={weapon => this.weaponUpdate("playerOne", weapon)}
                  weapon={this.state.playerOne.weapon}
                  status={this.state.playerOne.status}
                />
              </Col>
        
              <Col className="gutter-row" xs={15} sm={15} md={5} lg={5}>
                <Title level={3}>Player Two</Title>
                <Player
                  active={this.state.playerTwo.active}
                  weaponUpdate={weapon => this.weaponUpdate("playerTwo", weapon)}
                  weapon={this.state.playerTwo.weapon}
                  status={this.state.playerTwo.status}
                />
              </Col>
            </Row>
          );
        }
      }
        
      export default Controller;

      chevron_right

      
      

  6. Coding the Components: Code is very simple in these. Just the representational logic resides here.

    • Player.js: As mentioned earlier it’s a stateless component representing a player entity. It receives four props that are the active status of the player, current weapon, win/loose status, and functionHandler for updating weapon. It further uses two components GameControls and decision box which are discussed below. Also, if active props received are true then a CSS object called glowEffect is applied to the div.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      import React from "react";
      import GameControls from "../GameControls/GameControls";
      import DecisionBox from "../DecisionBox/DecisionBox";
        
      const Player = props => {
        let glowEffect = {};
        if (props.active) {
          glowEffect = {
            "-webkit-box-shadow": "0 0 20px blue",
            "-moz-box-shadow": "0 0 20px blue",
            "box-shadow": "0 0 20px blue"
          };
        }
        
        return (
          <div style={glowEffect}>
            <GameControls wUpdate={props.weaponUpdate} isActive={props.active} />
            <DecisionBox weapon={props.weapon} status={props.status} />
          </div>
        );
      };
        
      export default Player;

      chevron_right

      
      

    • GameControls.js: It contains three buttons rock, stone, scissors. If the player is not active then the buttons are disabled. On button click weaponupdate function is called which takes one argument ‘p’ for paper, ‘r’ for rock, ‘s’ for scissors and state of corresponding gets updated.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      import React from "react";
      import { Card } from "antd";
      import { Button } from "antd";
        
      import "antd/dist/antd.css";
        
      const GameControls = props => {
        return (
          <Card
            title="Controls"
            style={{ width: "300px", height: "250px", alignItems: "center" }}
          >
            <p style={{ alignItems: "center" }}>
              <Button
                type="dashed"
                size="large"
                shape="round"
                block
                onClick={() => props.wUpdate("r")}
                disabled={!props.isActive}
              >
                Rock
              </Button>
            </p>
        
        
            <p style={{ alignItems: "center" }}>
              {" "}
              <Button
                type="dashed"
                size="large"
                shape="round"
                block
                onClick={() => props.wUpdate("p")}
                disabled={!props.isActive}
              >
                Paper
              </Button>
            </p>
        
        
            <p style={{ alignItems: "center" }}>
              <Button
                type="dashed"
                size="large"
                shape="round"
                block
                onClick={() => props.wUpdate("s")}
                disabled={!props.isActive}
              >
                Scissors
              </Button>
            </p>
        
          </Card>
        );
      };
        
      export default GameControls;

      chevron_right

      
      

    • DecisionBox.js: It displays two things player’s weapon and the player’s win/loose status. It receives two props weapon (‘r’ or ‘p’ or ‘s’ ) and status (‘w’ or ‘l’ ). Two objects weaponmap and status map are used for mapping shortforms to proper words that can be displayed on the screen.

      Javascript

      filter_none

      edit
      close

      play_arrow

      link
      brightness_4
      code

      import React from "react";
      import { Card } from "antd";
      import { Typography } from "antd";
        
      const { Title } = Typography;
        
      const weaponMap = {
        s: "Scissors",
        p: "Paper",
        r: "Rock"
      };
      const statusMap = {
        w: "Win",
        l: "Loose"
      };
        
      const DecisionBox = props => {
        return (
          <Card
            title="Decision Box"
            style={{
              width: "300px",
              height: "250px",
              alignItems: "center",
              marginTop: "15px"
            }}
            bodyStyle={{ textAlign: "center" }}
          >
            <Title level={1} type="warning">
              {weaponMap[props.weapon]}
            </Title>
            <Title level={2} mark type="secondary">
              {statusMap[props.status]}
            </Title>
          </Card>
        );
      };
        
      export default DecisionBox;

      chevron_right

      
      

Output:

react-js-img

My Personal Notes arrow_drop_up
Recommended Articles
Page :