Rock the Paper and scissors
Tags: react, javascript, beginners, tutorial
Published: 2022-11-15 05:43:58

Hi Everyone,

back for the third article in the series. Time for some fun! let's build Rock Paper Scissors...

again this was an actual exercise I had to go through and the interesting part was that I did not get the role even though the feedback I got was that it was the best explanation the interviewer had ever heard during a coding exercise.

ah well... you live and learn.

## Approach
so there was a great freedom when it came to making rock paper scissors. There were no expectations for the UI other than the user can select an option.

the other requirements were:
- When the user clicks an option, a computer option should be shown
- There are 5 rounds to the game, each round should show who won the round
- After all 5 rounds are played a message should showcase the winner.
- After the game has been played a restart button should appear to restart the game
- You have 45 minutes to complete this exercise

## React implementation
Since the job was for a Senior React Developer the IDE was using React so the approach here was the one I used in the actual implementation. 

I started off with commenting out the necessary items to complete the game:
- options for the user, which I decided were going to be buttons
- A computers choice, implementing a random option each time the player clicks one of the buttons
- A check to see who won the round
- Metrics for the game such as user selection, user score, computer selection, computer score, rounds and winning message.

### Logic
I decided to start with creating a utils file that would hold the game logic.

```jsx

 const [userScore, setUserScore] = useState(0);
  const [compScore, setCompScore] = useState(0);
  const [usersSelection, setUserSelection] = useState(null);
  const [compSelection, setCompSelection] = useState(null);
  const [message, setMessage] = useState(null);
  const [round, setRounds] = useState(5);

 const options = ["rock", "paper", "scissors"];


 const game = (userSelection) => {
    setRounds(round - 1);

    const random = Math.floor(Math.random() * options.length);

    const compChoice = options[random];
    setCompSelection(compChoice);
    setUserSelection(userSelection);

    const combinations = {
      rock: options[2],
      paper: options[0],
      scissors: options[1],
    };

    // Logic for a Tie game
    if (userSelection === compChoice) {
      setMessage("Tie");
      return;
    }

    // Logic for scoring
    if (combinations[userSelection] === compChoice) {
      setUserScore(userScore + 1);
      setMessage("You win this round");
    } else {
      setCompScore(compScore + 1);
      setMessage("You lose this round");
    }
  };
```

 We start with setting some state variables... scores, selections and rounds. The rounds start off with 5 so the first thing the logic will do is deduct 1.  

Math.random is used to calculate a number between 0 and 2 to select an option for the computer.The state is set with the selections for both computer and user.

An object is used with the keys being the user selections and the value being the losing selection for the computer.

we then create the logic to decide who wins or when it is a tie. If the user selection is the same as the computer selection, it is a tie. If the user selection is the winning combination the user wins otherwise the computer wins the round and we set the message accordingly.

Then we needed to build out the rest of the logic which is deciding the winner and restarting the game.

```jsx
const [restart, setRestart] = useState(false)

  useEffect(() => {
    if (round < 1) {
      winner();
    }
  }, [round]);

  const winner = () => {
    setRestart(true);

    if (userScore === compScore) return setMessage("its a Tie");
    return userScore > compScore
      ? setMessage("you are the winner")
      : setMessage("You lost");
  };


 const reset = () => {
    setUserScore(0);
    setCompScore(0);
    setCompSelection(null);
    setUserSelection(null);
    setRounds(5);
    setMessage(null);
    setRestart(false);
  };
```

Let's start off with the useEffect. It checks the rounds whether it has reached 0, if it has, it runs the winner function to decide who won. 

The winner function is a simple ternary statement returning the winner with the highest score. Otherwise if the scores are equal it returns early with the score being a Tie. It sets the state variable restart to true so the restart button becomes visible.

The restart function is simply resetting all the state variables to their original values.

I also created a React component that builds a UI for all the metrics we need to take care off. 

```jsx

  const Info = () => (
    <Scores>
      <div>Rounds Left: {round}</div>
      <div>
        User Score: {userScore}
        <br />
        Computer Score: {compScore}
      </div>
    </Scores>
  );
```
here is the complete picture

```jsx
import React, { useEffect, useState } from "react";
import { Scores } from "./styles";
const Logic = () => {
  const [userScore, setUserScore] = useState(0);
  const [compScore, setCompScore] = useState(0);
  const [usersSelection, setUserSelection] = useState(null);
  const [compSelection, setCompSelection] = useState(null);
  const [message, setMessage] = useState(null);
  const [round, setRounds] = useState(5);
  const [restart, setRestart] = useState(false);

  const options = ["rock", "paper", "scissors"];

  const reset = () => {
    setUserScore(0);
    setCompScore(0);
    setCompSelection(null);
    setUserSelection(null);
    setRounds(5);
    setMessage(null);
    setRestart(false);
  };
  const winner = () => {
    setRestart(true);

    if (userScore === compScore) return setMessage("its a Tie");
    return userScore > compScore
      ? setMessage("you are the winner")
      : setMessage("You lost");
  };

  const game = (userSelection) => {
    setRounds(round - 1);

    const random = Math.floor(Math.random() * options.length);

    const compChoice = options[random];
    setCompSelection(compChoice);
    setUserSelection(userSelection);

    const combinations = {
      rock: options[2],
      paper: options[0],
      scissors: options[1],
    };

    // Logic for a Tie game
    if (userSelection === compChoice) {
      setMessage("Tie");
      return;
    }

    // Logic for scoring
    if (combinations[userSelection] === compChoice) {
      setUserScore(userScore + 1);
      setMessage("You win this round");
    } else {
      setCompScore(compScore + 1);
      setMessage("You lose this round");
    }
  };

  useEffect(() => {
    if (round < 1) {
      winner();
    }
  }, [round]);

  const Info = () => (
    <Scores>
      <div>Rounds Left: {round}</div>
      <div>
        User Score: {userScore}
        <br />
        Computer Score: {compScore}
      </div>
    </Scores>
  );

  return {
    game,
    reset,
    message,
    restart,
    options,
    Info,
    usersSelection,
    compSelection,
  };
};

export default Logic;


```

### UI
I decided to use the logic to build the UI, we already have the array with the options which can be used to showcase the buttons for both the user as well as the computer.

```jsx
import React from "react";
import { Game, Options, Option } from "./styles";
import Logic from "./utils";

export default function App() {
  const {
    Info,
    restart,
    reset,
    game,
    message,
    options,
    compSelection,
    usersSelection,
  } = Logic();

  const images = {
    rock: "https://cdn-icons-png.flaticon.com/512/3562/3562093.png",
    paper: "https://cdn-icons-png.flaticon.com/512/2949/2949963.png",
    scissors: "https://cdn-icons-png.flaticon.com/512/4151/4151732.png",
  };

  return (
    <>
      <Info />
      <Game>
        {message}
        <Options>
          {options.map((item, i) => (
            <Option
              id={item}
              key={i}
              disabled={restart && item !== usersSelection}
              onClick={() => game(item)}
            >
              <img src={images[item]} alt={item} height="100%" />
            </Option>
          ))}
        </Options>

        <Options>
          {options.map((item, i) => (
            <Option key={i} disabled={item !== compSelection}>
              <img src={images[item]} alt={item} height="100%" />
            </Option>
          ))}
        </Options>

        <div>{restart && <button onClick={() => reset()}>restart</button>}</div>
      </Game>
    </>
  );
}

```

as you can see it is the info section that is being returned from the Logic hook. Then the options being mapped twice to create the different options for both the user as well as the computer.

Images to represent the hand gestures for Rock Paper and Scissors. disabled variable to show the computer selection and to showcase the users last selection after the game ends.

lastly a restart button that uses logical and to decide whether to show the button, which equates to the restart state in the hook.

### Styled components
As you might know by now I have a preference for styled components, I just think they have multiple use cases that can come in handy at anytime. They are not necessary in this example but since we are using the library... 

```css
import styled from "styled-components";

export const Scores = styled.div`
  display: flex;
  justify-content: space-between;
`;

export const Game = styled.div`
  display: flex;
  justify-content: center;
  align-content: center;
  flex-direction: column;
  text-align: center;
`;

export const Options = styled.div`
  display: flex;
  justify-content: space-around;
  width: 50vw;
  margin: 5rem auto;
`;

export const Option = styled.button`
  height: 10rem;
  padding: 1rem;
  border: none;
  border-radius: 50%;
  transition: 0.5s;

  :disabled {
    background: black;
    border: 10px solid black;
  }

  :hover {
    box-shadow: 0px 0px 9px black;
  }
`;

```

## JavaScript Implementation
For the JavaScript implementation I have reused about 90% of the code of the React implementation since the logic doesn't change to much.

Here is the full implementation. I will be diving into the code that is separate from the React implementation after 

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Rock Paper Scissors</title>
  </head>
  <body>
    <div id="root"></div>
    <div id="score"></div>
    <div id="messages"></div>

    <script>
      let userScore = 0;
      let compScore = 0;
      let rounds = 5;
      let message = "";
      let restart = false;
      let compSelection;

      const root = document.getElementById("root");
      const score = document.getElementById("score");
      const messages = document.getElementById("messages");
      let comp = document.createElement("p");

      score.innerHTML = `rounds: ${rounds} , user score: ${userScore}, comp score = ${compScore}`;

      const options = ["Rock", "Paper", "Scissors"];

      const userBlocks = options.map((item, i) => {
        const button = document.createElement("button");
        button.innerHTML = item;
        button.addEventListener("click", () => game(item));

        root.append(button);
      });

      const game = (userSelection) => {
        if (restart) return;

        rounds--;

        const random = Math.floor(Math.random() * options.length);
        compSelection = options[random];
        comp.innerHTML = compSelection;

        const combinations = {
          Rock: "Scissors",
          Paper: "Rock",
          Scissors: "Paper",
        };

        if (userSelection === compSelection) {
          message = "its a Tie";
          messages.innerHTML = message;
          score.innerHTML = `rounds: ${rounds} user score: ${userScore}, comp score = ${compScore}`;
          return winner();
        }

        if (combinations[userSelection] === compSelection) {
          userScore++;
          message = "You won this round";
        } else {
          compScore++;
          message = "You lost this round, better luck next time";
        }

        messages.innerHTML = message;
        score.innerHTML = `rounds: ${rounds} user score: ${userScore}, comp score = ${compScore}`;
        return winner();
      };

      root.append(comp);

      const winner = () => {
        if (rounds > 0) return;

        restart = true;

        const restartButton = document.createElement("button");
        restartButton.id = "restartButton";
        restartButton.innerHTML = "restart";
        restartButton.addEventListener("click", (e) => {
          userScore = 0;
          compScore = 0;
          rounds = 5;
          message = "";
          restart = false;
          compSelection = null;

          comp.innerHTML = compSelection;

          messages.innerHTML = message;
          score.innerHTML = `rounds: ${rounds} user score: ${userScore}, comp score = ${compScore}`;
          restartButton.remove();
          return;
        });
        document.body.append(restartButton);

        if (userScore === compScore) {
          message = `It's a Tie`;
          return (messages.innerHTML = message);
        }

        userScore > compScore
          ? (message = "You Won!!!")
          : (message = "You Lose !!");
        return (messages.innerHTML = message);
      };
    </script>
  </body>
</html>

```

### Initializing 

```html
  const root = document.getElementById("root");
      const score = document.getElementById("score");
      const messages = document.getElementById("messages");
      let comp = document.createElement("p");

      score.innerHTML = `rounds: ${rounds} , user score: ${userScore}, comp score = ${compScore}`;

const userBlocks = options.map((item, i) => {
        const button = document.createElement("button");
        button.innerHTML = item;
        button.addEventListener("click", () => game(item));

        root.append(button);
      });
```
since there isn't a possibility of embedding the JavaScript values in the JSX code in a vanilla approach, we have to setup some elements that can showcase the changes when they happen.

in this case the root element which will be holding the buttons for the user selection. A paragraph that showcases the computer selection is also used. 

score is an element that will keep score on the metrics.

instead of setting the state and having the page restart reactively, we just set the innerHTML of the existing elements to represent the new metrics that happen after every round. 

### Restart Button

```html
const restartButton = document.createElement("button");
        restartButton.id = "restartButton";
        restartButton.innerHTML = "restart";
        restartButton.addEventListener("click", (e) => {
          userScore = 0;
          compScore = 0;
          rounds = 5;
          message = "";
          restart = false;
          compSelection = null;

          comp.innerHTML = compSelection;

          messages.innerHTML = message;
          score.innerHTML = `rounds: ${rounds} user score: ${userScore}, comp score = ${compScore}`;
          restartButton.remove();
          return;
        });
        document.body.append(restartButton);
```
The restart button does the same as the restart button on the react side, but the biggest difference is that we have to reset the elements as well as the variables.

after the restart button is clicked it is being removed by itself as well. until restart is set to true again and the cycle starts over.


## Thank You
Thank you again for reading this and I hope this will help you in your next interview or coding exercise. I would love to hear your feedback or comments on the implementation and I encourage you to practice this when you are interviewing. It will help you with your chances.

Stay tuned for the next one tomorrow.