[#51] 가위바위보 게임 (feat. React)

2025. 4. 10. 16:58·LG 유플러스 유레카 SW/React
목차
  1. ✍🏻 개발 시작 전, 약식 기획서 작성해두면 훨씬 수월 !
  2. ✨ 프로젝트: 가위바위보 게임
  3. 🛠️ 사용 기술
  4. 📁 프로젝트 구조
  5. 👩🏻‍💻 개발 사항
  6. 🪄 완성 코드

✍🏻 개발 시작 전, 약식 기획서 작성해두면 훨씬 수월 !

  1. 프로젝트 개요
    • 이 프로젝트는 어떤 용도로 만드는지 간단히 설명
    • (예: "가위바위보 게임 웹앱")
  2. 전체 와이프레임
    • 화면 흐름이 어떻게 되는지 대략적으로 그림으로 정리
  3. 확정된 디자인이 있으면 첨부
    • 없다면 색상, 폰트, 버튼 스타일 정도라도 간단히
  4. 비즈니스 로직 설명
    • 웹/앱이 어떤 규칙으로 동작하는 지 설명
    • (예: 가위바위보 게임 → 유저 선택 → 컴퓨터 랜덤 선택 → 승패 판정)
  5. 주요 기능 리스트
    • 프로젝트에 들어갈 핵심 기능 나열
    • (예: 사용자 선택 , 컴퓨터 랜덤 선택, 승패 결과 표시, 리셋 기능)

 

📚 어디에 정리하면 좋을까?

  • Figma
    → 와이어프레임, 시안 정리하기 최고
  • GitHub README
    → 개발 전에 간단한 기획서 내용을 정리해두면
    → 팀원이랑 공유하거나 기록용으로도 딱 좋다.

 

📌 참고한 강사님의 가위바위보 게임 기획서

https://somyclass.notion.site/1d0973f5e0fe80fb9343f7e67249e537

 

가위 바위 보 게임 | Notion

assets.zip

somyclass.notion.site

 


✨ 프로젝트: 가위바위보 게임

가위바위보 게임은 사용자와 컴퓨터가 각각 가위 / 바위 / 보를 선택해 승패를 겨루는 간단한 React 기반 게임입니다.

https://rps-game-dun.vercel.app/

 

가위바위보 게임

 

rps-game-dun.vercel.app

 

🛠️ 사용 기술

  • React(Vite 기반)
  • CSS Module로 컴포넌트 스타일링
  • Vercel을 통한 배포

 

📁 프로젝트 구조

/public
  └── vite.svg             
/src
  ├── /assets
  │   ├── scissors.png      # 가위 이미지
  │   ├── rock.png          # 바위 이미지
  │   ├── paper.png         # 보 이미지
  │   └── questionmark.png  # 선택 전 물음표 이미지
  │
  ├── /components
  │   ├── Button.jsx        # 가위/바위/보 버튼 컴포넌트
  │   └── Card.jsx          # 유저/컴퓨터 선택 카드 컴포넌트
  │
  ├── /css
  │   ├── App.module.css    # App 컴포넌트 스타일
  │   ├── Button.module.css # Button 컴포넌트 스타일
  │   └── Card.module.css   # Card 컴포넌트 스타일
  │
  ├── /utils
  │   ├── game.js           # 승패 결정 및 컴퓨터 선택 유틸 함수
  │   └── result.js			# 결과 뒤집는 유틸 함수
  ├── App.jsx               # 메인 App 컴포넌트
  ├── index.css				# 전역 스타일
  └── main.jsx              
  
indx.html
package.json                 
README.md                    
vite.config.js               
...

 

👩🏻‍💻 개발 사항

1️⃣ Choice 객체 배열

  • 가위/바위/보의 이름, 이미지 정보, 타입을 가진 객체 배열 생성
  • useMemo 훅을 통해서 최초 한 번만 배열을 만들고, 그 이후 렌더링에서 재사용하도록 함
  const choice = useMemo(
    () => [
      { name: '가위', imgUrl: scissors, type: 'scissors' },
      { name: '바위', imgUrl: rock, type: 'rock' },
      { name: '보', imgUrl: paper, type: 'paper' },
    ],
    []
  )

 

2️⃣ 기본 UI 레이아웃 구성 및 스타일 적용 

  • App.jsx
<div className={styles.app}>
      <h1>가위바위보 게임</h1>
      <div className={styles.main}>
        <Card
          title="너님"
          choice={userChoice}
          type="user"
          result={result}
          isPlaying={isPlaying}
          count={count}
        />
        <div className={styles.btn__con}>
          {choice.map(c => (
            <Button
              key={c.type}
              name={c.name}
              imgUrl={c.imgUrl}
              type={c.type}
              onClick={() => handleUserChoice(c)}
              disabled={isPlaying}
            />
          ))}
          <span className={styles['btn__con--common']}>{result}</span>
          {(userChoice || computerChoice) && (
            <button
              className={`${styles['btn--retry']} ${styles['btn__con--common']}`}
              onClick={handleRetry}
              disabled={isPlaying}
            >
              다시하기
            </button>
          )}
        </div>
        <Card
          title="상대선수"
          choice={computerChoice}
          type="computer"
          result={reverseResult(result)}
          isPlaying={isPlaying}
          count={count}
        />
      </div>
      <div className={styles.description}>
        버튼을 클릭하여 가위, 바위, 보 중 하나를 선택하세요.
        <br />
        컴퓨터는 랜덤으로 선택합니다.
      </div>
    </div>

 

3️⃣ 상태 관리 구현

상태 역할
userChoice 사용자가 고른 가위/바위/보 저장
computerChoice 컴퓨터가 고른 가위/바위/보 저장
result 승/패/비김 결과 저장
isPlaying 게임이 진행 중인지 여부 관리
count 카운트다운 숫자 저장 및 관리
const [userChoice, setUserChoice] = useState(null)
const [computerChoice, setComputerChoice] = useState(null)
const [result, setResult] = useState('?')
const [isPlaying, setIsPlaying] = useState(false) // 플레이 상태
const [count, setCount] = useState(null) // 카운트​

 

4️⃣ Card, Button 컴포넌트 분리

  • Card 컴포넌트: 유저와 컴퓨터가 선택한 결과를 보여주는 카드 형태의 컴포넌트
    • 상태에 따라 유동적으로 화면이 바뀜 (카운트다운 ➡️ 선택 결과 표시)
    • 승패에 따라 스타일 변동 (조건부 스타일링)
    • 유저와 컴퓨터 카드 모두 재사용 가능
import React from 'react'
import questionMark from '../assets/questionmark.png'
import styles from '../css/Card.module.css'

const Card = ({ title, choice, type, result, isPlaying, count }) => {
  const getResultClass = () => {
    if (result === '이겼다') return styles.win
    if (result === '졌다') return styles.lose
    return ''
  }

  const content = () => {
    if (isPlaying && count > 0) {
      return (
        <>
          <div className={styles.count}>{count}</div>
          <p>카운트다운</p>
        </>
      )
    }

    if (choice) {
      return (
        <>
          <img src={choice.imgUrl} alt={choice.type} />
          <p>{result}</p>
        </>
      )
    }

    return (
      <>
        <img src={questionMark} alt="?" />
        <p>선택하세요</p>
      </>
    )
  }

  return (
    <div className={`${styles.card} ${styles[type]} ${getResultClass()}`}>
      <h2>{title}</h2>
      {content()}
    </div>
  )
}

export default Card
  • Button 컴포넌트: 유저가 가위/바위/보를 선택할 수 있도록 하는 버튼 컴포넌트
    • 가위 / 바위 / 보 각각 다른 스타일 적용
    • 게임 진행 중이면 버튼 비활성화
import React from 'react'
import styles from '../css/Button.module.css'

const Button = ({ name, imgUrl, type, onClick, disabled }) => {
  return (
    <button
      className={`${styles.btn} ${styles[`btn--${type}`]}`}
      onClick={onClick}
      disabled={disabled}
    >
      <img src={imgUrl} alt={name} />
      <p>{name}</p>
    </button>
  )
}

export default Button

 

5️⃣ 컴퓨터 랜덤 선택 함수 구현

컴퓨터는 랜덤으로 가위, 바위, 보 중 하나를 선택

const generateComputerChoice = choice => {
  const randomIdx = Math.floor(Math.random() * choice.length)
  return choice[randomIdx]
}

 

6️⃣ 승패 판정 로직 구현

사용자와 컴퓨터가 각각 가위, 바위, 보를 선택한 후, 사용자의 승패 판정

const determineWinner = (userChoice, computerChoice) => {
  if (userChoice.type === computerChoice.type) return '비겼다'
  if (
    (userChoice.type === 'scissors' && computerChoice.type === 'paper') ||
    (userChoice.type === 'rock' && computerChoice.type === 'scissors') ||
    (userChoice.type === 'paper' && computerChoice.type === 'rock')
  ) {
    return '이겼다'
  } else {
    return '졌다'
  }
}

 

7️⃣ 사용자 버튼 선택 이벤트 처리

  • handleUserChoice: 게임 시작 + 카운트다운 준비
  • useEffect: 카운트다운 진행 ➡️ 카운트 0이면 컴퓨터 선택 + 승패 결정
  • setTimeout으로 1초마다 카운트를 1씩 줄여나감
  const handleUserChoice = userSelected => {
    if (isPlaying) return // 이미 게임이 진행 중이면 무시

    // 이전 기록 초기화
    setUserChoice(null)
    setComputerChoice(null)
    setResult('?')

    setIsPlaying(true) // 게임 진행 중으로 변경
    setUserChoice(userSelected) // 사용자 선택 저장
    setCount(3) // 카운트다운 시작 (3초)
  }

  useEffect(() => {
    if (count === null) return
    // 카운트가 0이 되면
    if (count === 0) {
      const computerSelected = generateComputerChoice(choice) // 컴퓨터 선택 생성
      setComputerChoice(computerSelected) // 컴퓨터 선택 저장

      const gameResult = determineWinner(userChoice, computerSelected) // 승부 결과 계산
      setResult(gameResult) // 결과 저장

      setIsPlaying(false) // 게임 종료 상태로 변경
      setCount(null) // 카운트 리셋
      return
    }

    // 타이머 (카운트가 0이 아닐 때, 1초마다 count를 1 감소)
    const timer = setTimeout(() => {
      setCount(prev => prev - 1)
    }, 1000)

    // 클린업 함수 (타이머 정리)
    return () => clearTimeout(timer)
  }, [count, userChoice, choice])

 

8️⃣ 결과 뒤집는 함수 구현

"사용자" 기준의 결과를 뒤집어서 "컴퓨터" 결과를 만들어내기 위함

const reverseResult = result => {
  if (result === '이겼다') return '졌다'
  if (result === '졌다') return '이겼다'
  if (result === '비겼다') return '비겼다'
  return ''
}

 

9️⃣ 다시하기 버튼을 통한 초기화 구현

게임을 초기 상태로 리셋 (사용자/컴퓨터 선택 및 결과 초기화)

 const handleRetry = () => {
    setUserChoice(null)
    setComputerChoice(null)
    setResult('?')
  }
{(userChoice || computerChoice) && (
    <button
      className={`${styles['btn--retry']} ${styles['btn__con--common']}`}
      onClick={handleRetry}
      disabled={isPlaying}
    >
      다시하기
    </button>
)}

 

🔟 UI 세부 스타일링

  • 카운트가 시작되면 숫자가 커졌다가 작아지는 애니메이션 효과 주기
/* ... 생략 */

.count {
  text-align: center;
  font-size: 3rem;
  font-weight: bold;
  padding: var(--gap2) 0;
  animation: scaleUp 0.5s ease-in-out;
}

@keyframes scaleUp {
  0% {
    transform: scale(1);
    opacity: 0.5;
  }
  50% {
    transform: scale(1.5);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 0.5;
  }
}

 

🪄 완성 코드

https://github.com/nue-os/rps-game

 

GitHub - nue-os/rps-game: 가위바위보 게임 ✌🏻✊🏻✋🏻

가위바위보 게임 ✌🏻✊🏻✋🏻 . Contribute to nue-os/rps-game development by creating an account on GitHub.

github.com

 

 

728x90
반응형

'LG 유플러스 유레카 SW > React' 카테고리의 다른 글

[#53] React 쇼핑몰 - 헤더 반응형으로 만들어보기  (1) 2025.04.14
[#52] React Router  (2) 2025.04.11
[#50] React - useState  (5) 2025.04.09
[#49] React 설정  (1) 2025.04.08
[#46] React 컴포넌트, props, state  (1) 2025.04.02
  1. ✍🏻 개발 시작 전, 약식 기획서 작성해두면 훨씬 수월 !
  2. ✨ 프로젝트: 가위바위보 게임
  3. 🛠️ 사용 기술
  4. 📁 프로젝트 구조
  5. 👩🏻‍💻 개발 사항
  6. 🪄 완성 코드
'LG 유플러스 유레카 SW/React' 카테고리의 다른 글
  • [#53] React 쇼핑몰 - 헤더 반응형으로 만들어보기
  • [#52] React Router
  • [#50] React - useState
  • [#49] React 설정
nueos
nueos
  • nueos
    nueos 공부 기록
    nueos
  • 전체
    오늘
    어제
    • 분류 전체보기 (191)
      • 해커톤 (1)
      • 네이버 BoostCamp (6)
      • LG 유플러스 유레카 SW (3)
        • React (21)
        • TypeScript (2)
        • JavaScript (2)
        • HTML+CSS (5)
        • Spring (7)
        • Java (6)
        • SQL (2)
        • Algorithm (8)
        • CX (6)
        • Git (2)
        • 프로젝트 (2)
        • 스터디 (9)
        • 과제 (8)
        • 특강 (1)
      • React (3)
      • Next (0)
      • Javascript (2)
      • HTML (2)
      • CSS (9)
      • Algorithm (6)
      • Database (0)
      • OS (13)
      • C++ (24)
      • Python (1)
      • jQuery (1)
      • Django (1)
      • Git (1)
      • 개발 지식 (3)
      • 정보 보안 (22)
      • 포렌식 (1)
      • 암호 (2)
      • 기타 (4)
      • 패스트캠퍼스 FE 프로젝트십 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스택
    큐
    디지랩챌린지
    기술로바꾸는세상
    힙
    디지털혁신
    제주지역혁신플랫폼지능형서비스사업단
    Stack
    완전 탐색
    Queue
    heap
    exhaustive search
    제주해커톤
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
nueos
[#51] 가위바위보 게임 (feat. React)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.