본문 바로가기
React

[React] React로 가위 바위 보 게임 만들기 3

by IT 정복가 2023. 2. 10.
728x90

https://conquer-it.tistory.com/192

 

[React] React로 가위 바위 보 게임 만들기 2

https://conquer-it.tistory.com/191 React로 가위 바위 보 게임 만들기 1 우선, 버튼을 클릭했을 때 유저 박스의 사진이 바뀌는 것까지는 구현이 되었다. 다음 할 일은 컴퓨터 박스를 구현 하는 것이다. 3. 컴

conquer-it.tistory.com

React로 가위 바위 보 게임 만들기 2


현재 미완성된 기능은 아래와 같다.

  • 게임 결과를 통해 누가 이겼는지 승패를 결정한다.
  • 승패 결과에 따라 박스 테두리의 색이 바뀐다.(ex. 승: 초록, 패: 빨강, 무: 검정)
  • 이긴 횟수, 비긴 횟수, 진 횟수를 UI에 보여준다.
  • 리셋 버튼을 누르면 UI에 보여줬던 횟수가 초기화 된다.

하나씩 만들어 보자

 

5. 승패 결과에 따라 컴퓨터 부분에 Lose, Win, tie 보여주기

저번에 승패 결정을 구현하면서 한가지 오류를 발견했었다.

아래 사진과 같이 You가 졌는데 Computer도 Lose를 출력하고 있다.

오류

이 문제를 해결하기 위해서 컴퓨터 쪽 결과를 바꿔줄 state를 만들어 주어야 한다.

참고로, 컴퓨터 결과 state는 You의 결과 state와 차이가 없기때문에 쉽게 만들 수 있다. 

computerResult라는 state를 만들어 이것을 play함수에서 실행 시켜야 한다.

setComputerResult는 computerJudgement라는 함수를 실행시키는데 

computerJudgement의 로직은 다음과 같다.

1. 유저 == 컴퓨터 >> 비김

2. 유저가 주먹이면서 컴퓨터가 가위일 경우 >> 짐

3. 유저가 주먹이면서 컴퓨터가 보인 경우 >> 이김

4. 유저가 가위이면서 컴퓨터가 보인 경우 >> 짐

5. 유저가 가위이면서 컴퓨터가 주먹인 경우 >> 이김

6. 유저가 보이면서 컴퓨터가 주먹인 경우 >> 짐

7. 유저가 보이면서 컴퓨터가 가위인 경우 >> 이김

그 다음 computerResult를 props로 computer 쪽 박스에 전달해 주면 된다.

 

App.js

import { useState } from "react";
import "./App.css";
import Box from "./component/Box";

const choice={
  rock:{
    name: "Rock",
    img:"https://cdn.pixabay.com/photo/2014/03/25/15/26/rock-paper-scissors-296854_960_720.png" 
  },
  scissors:{
    name:"Scissor",
    img:"https://cdn.pixabay.com/photo/2014/03/25/15/26/rock-paper-scissors-296853_1280.png"
  },
  paper:{
    name:"Paper",
    img:"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSvciv57AXv5krjeGZ2dBEtESuvSk33dpvT_-AebVrCx5Flo2ME_F-r9vw7Ayqdx9oq10s&usqp=CAU"
  }
}
function App() {
  const [userSelect, setUserSelect] = useState(null);
  const [computerSelect, setComputerSelect] = useState(null);
  const [result, setResult] = useState("Start!");
  const [computerResult, setComputerResult] = useState("Start!");

  const play = (userChoice) => {
    setUserSelect(choice[userChoice]);

    let computerChoice = randomChoice();
    setComputerSelect(computerChoice);

    setResult(judgement(choice[userChoice], computerChoice));
    setComputerResult(computerJudgement(choice[userChoice], computerChoice));
  };

  const judgement = (user, computer) => {
    if (user.name == computer.name) {
      return "tie";
    } else if (user.name == "Rock")
      return computer.name == "Scissor" ? "Win" : "Lose";
    else if (user.name == "Scissor")
      return computer.name == "Paper" ? "Win" : "Lose";
    else if (user.name == "Paper")
      return computer.name == "Scissor" ? "Lose" : "Win";
  };

  const computerJudgement = (user, computer) => {
    if (user.name == computer.name) {
      return "tie";
    } else if (computer.name == "Rock")
      return user.name == "Scissor" ? "Win" : "Lose";
    else if (computer.name == "Scissor")
      return user.name == "Paper" ? "Win" : "Lose";
    else if (computer.name == "Paper")
      return user.name == "Scissor" ? "Lose" : "Win";
  };

  const randomChoice = () => {
    let itemArray = Object.keys(choice); // 객체에 키값만 뽑아 배열로 만들어 주는 함수
    let randomItem = Math.floor(Math.random() * itemArray.length);
    let final = itemArray[randomItem];
    return choice[final];
  };
  return (
    <>
      <div className="main">
        <Box title="You" item={userSelect} result={result} />
        <Box title="Computer" item={computerSelect} result={computerResult} />
      </div>
      <div className="main">
        <button onClick={() => play("scissors")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/scissors.png" />
        </button>
        <button onClick={() => play("rock")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/rock.png" />
        </button>
        <button onClick={() => play("paper")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/paper.png" />
        </button>
      </div>
    </>
  );
}

export default App;

Box.js

import React from "react";

const Box = (props) => {
  return (
    <div className="box">
      <h1>{props.title}</h1>
      <img className="item-img" src={props.item && props.item.img} />
      <h2>{props.result}</h2>
    </div>
  );
};

export default Box;

6. 이긴 횟수, 비긴 횟수, 진 횟수를 UI에 보여준다.

승패 결과에 따라 박스 테두리의 색이 바뀌는 것은 마지막에 하겠다.

테두리 색이 바뀌는 것을 하기 전에 총 대결 수와 유저가 이긴 횟수, 비긴 횟수, 진 횟수를 UI에 보여줘 보자.

 

일단 버튼 아래 UI를 보여주기 위해 아래 코드를 작성해 보자.

App.js

function App() {

//생략...

  return (
    <>
//생략...
      <div className="result">
        <h4>총 대결 수: 0</h4>
        <div className="user-result">
          <h6>이긴 횟수: 0</h6>
          <h6>비긴 횟수: 0</h6>
          <h6>진 횟수: 0</h6>
        </div>
      </div>
    </>
  );
}

App.css

.result{
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
}
.user-result{
    display: flex;
}

h4{
    margin-bottom: 0;
}

h6{
    margin-bottom: 0;
}

h6:first-child, h6:nth-child(2){
    margin-right: 15px;
}

이건 state 연습할 때 만들었던 count 기능과 굉장히 유사하여 간단하게 만들 수 있다.

버튼을 클릭할 때마다 횟수가 증가해야하기 때문에 play 함수가 실행될 때마다 동작해야 한다.

App.js

import { useState } from "react";
import "./App.css";
import Box from "./component/Box";

// 생략...

function App() {
//생략...
  const [totalCount, setTotalCount] = useState(0);
  const [winCount, setWinCount] = useState(0);
  const [loseCount, setLoseCount] = useState(0);
  const [tieCount, setTieCount] = useState(0);

  const play = (userChoice) => {
//생략...

    //횟수 카운트
    setTotalCount(totalCount + 1);
    if (judgement(choice[userChoice], computerChoice) == "Win") {
      setWinCount(winCount + 1);
    } else if (
      judgement(choice[userChoice], computerChoice) == "Tie"
        ? setTieCount(tieCount + 1)
        : setLoseCount(loseCount + 1)
    );
  };

//생략...

  return (
    <>
//생략...
        <h4>총 대결 수: {totalCount}</h4>
        <div className="user-result">
          <h6>이긴 횟수: {winCount}</h6>
          <h6>비긴 횟수: {tieCount}</h6>
          <h6>진 횟수: {loseCount}</h6>
        </div>
      </div>
    </>
  );
}

export default App;

잘 동작하는 것을 확인할 수 있다.


7. 리셋 버튼을 누르면 횟수가 초기화 된다.

리셋 기능을 만들기 위해 횟수 아래 버튼을 하나 만들자.

(css는 자기 마음대루...)

<div className="reset">
	<button>
          <i class="fa-solid fa-rotate-right"></i>
	</button>
</div>

저 버튼이 클릭되면 총 대결 수, 이긴 횟수, 비긴 횟수, 진 횟수가 모두 0이 되어야한다.

그렇게 하기 위해서는 버튼에 클릭 이벤트를 주어야한다.

클릭 이벤트가 실행하는 함수인 reset을 만들어 그 안에서 state를 0으로 만들어 주면 끝난다.

import { useState } from "react";
import "./App.css";
import Box from "./component/Box";

function App() {
//생략...
  const reset = () => {
    setTotalCount(0);
    setWinCount(0);
    setTieCount(0);
    setLoseCount(0);
  };
//생략...
  return (
    <>
//생략...
      <div className="reset">
        <button onClick={reset}>
          <i class="fa-solid fa-rotate-right"></i>
        </button>
      </div>
    </>
  );
}

export default App;

버튼을 클릭하면 0으로 초기화 되는 것을 볼 수 있다.


8. 승패 결과에 따라 박스 테두리의 색이 바뀐다.(ex. 승: 초록, 패: 빨강, 무: 검정)

마지막으로 추가해줄 기능은 결과에 따라 테두리 색이 바뀌는 기능이다.

결과에 따라 테두리가 바뀌려면 유저가 이겼는지, 졌는지, 비겼는지 알아야 한다.

과연 그 정보를 어떻게 가져올까?

 

Box.js로 와서 변수를 선언해 준 후 그 안에 props로 넘어 온 result 값을 넣어준다.

그 후 className에 이 변수를 넣어주고 css를 만져주면 끝이다.

참고로, 변수를 넣을 때는 `${ }`안에 넣어 주어야 한다.

Box.js

import React from "react";

const Box = (props) => {
  let result = props.result; // props로 넘어 온 결과를 변수에 저장
  return (
    <div className={`box ${result}`}> // 이 부분이 중요!!
      <h1>{props.title}</h1>
      <img className="item-img" src={props.item && props.item.img} />
      <h2>{props.result}</h2>
    </div>
  );
};

export default Box;

App.css

.Win{
    border: 3px solid green;
}
.Lose{
    border: 3px solid red;
}
.Tie{
    border: 3px solid black;
}

결과가 잘 나오는 것을 볼 수 있다.


이로써 가위바위보 게임이 완성되었다.

css는 자기가 원하는대로 꾸며보자!.

 

전체 코드

App.js

import { useState } from "react";
import "./App.css";
import Box from "./component/Box";

const choice={
  rock:{
    name: "Rock",
    img:"https://cdn.pixabay.com/photo/2014/03/25/15/26/rock-paper-scissors-296854_960_720.png" 
  },
  scissors:{
    name:"Scissor",
    img:"https://cdn.pixabay.com/photo/2014/03/25/15/26/rock-paper-scissors-296853_1280.png"
  },
  paper:{
    name:"Paper",
    img:"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSvciv57AXv5krjeGZ2dBEtESuvSk33dpvT_-AebVrCx5Flo2ME_F-r9vw7Ayqdx9oq10s&usqp=CAU"
  }
}
function App() {
  const [userSelect, setUserSelect] = useState(null);
  const [computerSelect, setComputerSelect] = useState(null);
  const [result, setResult] = useState("Start!");
  const [computerResult, setComputerResult] = useState("Start!");
  const [totalCount, setTotalCount] = useState(0);
  const [winCount, setWinCount] = useState(0);
  const [loseCount, setLoseCount] = useState(0);
  const [tieCount, setTieCount] = useState(0);

  const play = (userChoice) => {
    setUserSelect(choice[userChoice]);

    let computerChoice = randomChoice();
    setComputerSelect(computerChoice);

    setResult(judgement(choice[userChoice], computerChoice));
    setComputerResult(computerJudgement(choice[userChoice], computerChoice));

    //횟수 카운트
    setTotalCount(totalCount + 1);
    if (judgement(choice[userChoice], computerChoice) == "Win") {
      setWinCount(winCount + 1);
    } else if (
      judgement(choice[userChoice], computerChoice) == "Tie"
        ? setTieCount(tieCount + 1)
        : setLoseCount(loseCount + 1)
    );
  };

  const judgement = (user, computer) => {
    if (user.name == computer.name) {
      return "Tie";
    } else if (user.name == "Rock")
      return computer.name == "Scissor" ? "Win" : "Lose";
    else if (user.name == "Scissor")
      return computer.name == "Paper" ? "Win" : "Lose";
    else if (user.name == "Paper")
      return computer.name == "Scissor" ? "Lose" : "Win";
  };

  const computerJudgement = (user, computer) => {
    if (user.name == computer.name) {
      return "tie";
    } else if (computer.name == "Rock")
      return user.name == "Scissor" ? "Win" : "Lose";
    else if (computer.name == "Scissor")
      return user.name == "Paper" ? "Win" : "Lose";
    else if (computer.name == "Paper")
      return user.name == "Scissor" ? "Lose" : "Win";
  };

  const reset = () => {
    setTotalCount(0);
    setWinCount(0);
    setTieCount(0);
    setLoseCount(0);
  };

  const randomChoice = () => {
    let itemArray = Object.keys(choice); // 객체에 키값만 뽑아 배열로 만들어 주는 함수
    let randomItem = Math.floor(Math.random() * itemArray.length);
    let final = itemArray[randomItem];
    return choice[final];
  };
  return (
    <>
      <div className="main">
        <Box title="You" item={userSelect} result={result} />
        <Box title="Computer" item={computerSelect} result={computerResult} />
      </div>
      <div className="main">
        <button onClick={() => play("scissors")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/scissors.png" />
        </button>
        <button onClick={() => play("rock")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/rock.png" />
        </button>
        <button onClick={() => play("paper")} className="btn">
          <img src="https://nehalhazem.github.io/rockPaperScissors.io/img/paper.png" />
        </button>
      </div>
      <div className="result">
        <h4>총 대결 수: {totalCount}</h4>
        <div className="user-result">
          <h6>이긴 횟수: {winCount}</h6>
          <h6>비긴 횟수: {tieCount}</h6>
          <h6>진 횟수: {loseCount}</h6>
        </div>
      </div>
      <div className="reset">
        <button onClick={reset}>
          <i class="fa-solid fa-rotate-right"></i>
        </button>
      </div>
    </>
  );
}

export default App;

Box.js

import React from "react";

const Box = (props) => {
  let result = props.result;
  return (
    <div className={`box ${result}`}>
      <h1>{props.title}</h1>
      <img className="item-img" src={props.item && props.item.img} />
      <h2>{props.result}</h2>
    </div>
  );
};

export default Box;

App.css

.main{
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 100px;
}
.box{
    width: 500px;
    border: 3px solid black;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.box:first-child{
    margin-right: 30px;
}

.Win{
    border: 3px solid green;
}
.Lose{
    border: 3px solid red;
}
.Tie{
    border: 3px solid black;
}
.item-img{
    width: 400px;
}

.btn img{
    width: 70px;
}

.btn{
    background-color: white;
    border: none;
    padding:0;
    border-radius: 100%;
    
}
.result{
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
}
.user-result{
    display: flex;
}

h4{
    margin-bottom: 0;
}

h6{
    margin-bottom: 0;
}

h6:first-child, h6:nth-child(2){
    margin-right: 15px;
}
.reset{
    margin-top: 15px;
    display: flex;
    justify-content: center;
}
728x90