diff --git a/react_webgame/main/Form.jsx b/react_webgame/8. 지뢰찾기/Form.jsx
similarity index 100%
rename from react_webgame/main/Form.jsx
rename to react_webgame/8. 지뢰찾기/Form.jsx
diff --git a/react_webgame/main/MineSearch.jsx b/react_webgame/8. 지뢰찾기/MineSearch.jsx
similarity index 100%
rename from react_webgame/main/MineSearch.jsx
rename to react_webgame/8. 지뢰찾기/MineSearch.jsx
diff --git a/react_webgame/main/Table.jsx b/react_webgame/8. 지뢰찾기/Table.jsx
similarity index 100%
rename from react_webgame/main/Table.jsx
rename to react_webgame/8. 지뢰찾기/Table.jsx
diff --git a/react_webgame/main/Td.jsx b/react_webgame/8. 지뢰찾기/Td.jsx
similarity index 100%
rename from react_webgame/main/Td.jsx
rename to react_webgame/8. 지뢰찾기/Td.jsx
diff --git a/react_webgame/main/Tr.jsx b/react_webgame/8. 지뢰찾기/Tr.jsx
similarity index 100%
rename from react_webgame/main/Tr.jsx
rename to react_webgame/8. 지뢰찾기/Tr.jsx
diff --git a/react_webgame/8. 지뢰찾기/client.jsx b/react_webgame/8. 지뢰찾기/client.jsx
new file mode 100644
index 00000000..a8b1eeb2
--- /dev/null
+++ b/react_webgame/8. 지뢰찾기/client.jsx
@@ -0,0 +1,5 @@
+import React from "react";
+import ReactDom from "react-dom";
+import MineSearch from "./MineSearch";
+
+ReactDom.render(, document.querySelector("#root"));
diff --git a/react_webgame/8. 지뢰찾기/index.html b/react_webgame/8. 지뢰찾기/index.html
new file mode 100644
index 00000000..3257650c
--- /dev/null
+++ b/react_webgame/8. 지뢰찾기/index.html
@@ -0,0 +1,21 @@
+
+
+
+ 지뢰찾기
+
+
+
+
+
+
+
diff --git a/react_webgame/main/Games.jsx b/react_webgame/main/Games.jsx
new file mode 100644
index 00000000..e1b80cd6
--- /dev/null
+++ b/react_webgame/main/Games.jsx
@@ -0,0 +1,20 @@
+import React from "react";
+import { BrowserRouter, HashRouter, Route } from "react-router-dom";
+import NumberBaseBall from "./games/NumberBaseball";
+import RSP from "./games/RSP";
+import Lotto from "./games/Lotto"
+
+const Games = () => {
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default Games;
diff --git a/react_webgame/main/client.jsx b/react_webgame/main/client.jsx
index a8b1eeb2..a453f103 100644
--- a/react_webgame/main/client.jsx
+++ b/react_webgame/main/client.jsx
@@ -1,5 +1,5 @@
import React from "react";
import ReactDom from "react-dom";
-import MineSearch from "./MineSearch";
+import Games from "./Games";
-ReactDom.render(, document.querySelector("#root"));
+ReactDom.render(, document.querySelector("#root"));
diff --git a/react_webgame/main/games/Ball.jsx b/react_webgame/main/games/Ball.jsx
new file mode 100644
index 00000000..a2d2bffd
--- /dev/null
+++ b/react_webgame/main/games/Ball.jsx
@@ -0,0 +1,23 @@
+import React, { memo } from "react";
+
+const Ball = memo(({ number }) => {
+ let background;
+ if (number <= 10) {
+ background = "red";
+ } else if (number <= 20) {
+ background = "orange";
+ } else if (number <= 30) {
+ background = "yellow";
+ } else if (number <= 40) {
+ background = "blue";
+ } else {
+ background = "green";
+ }
+ return (
+
+ {number}
+
+ );
+});
+
+export default Ball;
diff --git a/react_webgame/main/games/Lotto.jsx b/react_webgame/main/games/Lotto.jsx
new file mode 100644
index 00000000..1877e8b6
--- /dev/null
+++ b/react_webgame/main/games/Lotto.jsx
@@ -0,0 +1,78 @@
+import React, {
+ useState,
+ useRef,
+ useEffect,
+ useMemo,
+ useCallback,
+} from "react";
+import Ball from "./Ball";
+
+function getWinNumbers() {
+ console.log("getWinNumbers");
+ const candidate = Array(45)
+ .fill()
+ .map((v, i) => i + 1);
+ const shuffle = [];
+ while (candidate.length > 0) {
+ shuffle.push(
+ candidate.splice(Math.floor(Math.random() * candidate.length), 1)[0]
+ );
+ }
+ const bonusNumber = shuffle[shuffle.length - 1];
+ const winNumbers = shuffle.slice(0, 6).sort((p, c) => p - c);
+ return [...winNumbers, bonusNumber];
+}
+
+const Lotto = () => {
+ const lottoNumbers = useMemo(() => getWinNumbers(), []);
+ const [winNumbers, setWinNumbers] = useState(lottoNumbers);
+ const [winBalls, setWinBalls] = useState([]);
+ const [bonus, setBonus] = useState(null);
+ const [redo, setRedo] = useState(false);
+ const timeouts = useRef([]);
+
+ useEffect(() => {
+ runTimeouts();
+ return () => {
+ timeouts.current.forEach((v) => {
+ clearTimeout(v);
+ });
+ };
+ }, [timeouts.current]);
+
+ const runTimeouts = () => {
+ for (let i = 0; i < winNumbers.length - 1; i++) {
+ timeouts.current[i] = setTimeout(() => {
+ setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]]);
+ }, (i + 1) * 1000);
+ }
+ timeouts.current[6] = setTimeout(() => {
+ setBonus(winNumbers[6]);
+ setRedo(true);
+ }, 7000);
+ };
+
+ const onClickRedo = useCallback(() => {
+ setWinNumbers(getWinNumbers());
+ setWinBalls([]);
+ setBonus(null);
+ setRedo(false);
+ timeouts.current = [];
+ }, [winNumbers]);
+
+ return (
+ <>
+ 당첨 숫자
+
+ {winBalls.map((v) => (
+
+ ))}
+
+ 보너스
+ {bonus && }
+ {redo && }
+ >
+ );
+};
+
+export default Lotto;
diff --git a/react_webgame/main/games/NumberBaseball.jsx b/react_webgame/main/games/NumberBaseball.jsx
new file mode 100644
index 00000000..3b8fe210
--- /dev/null
+++ b/react_webgame/main/games/NumberBaseball.jsx
@@ -0,0 +1,83 @@
+import React, { useState, useRef, memo } from 'react';
+import Try from './Try';
+
+// 숫자 4개를 겹치지않고 랜덤하고 뽑는 함수
+function getNumbers() {
+ const candidate = [1,2,3,4,5,6,7,8,9];
+ const array = [];
+ for (let i = 0; i < 4; i++) {
+ const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
+ array.push(chosen);
+ }
+ return array;
+}
+
+const NumberBaseball = memo(() => {
+ const [result, setresult] = useState('');
+ const [value, setvalue] = useState('');
+ const [answer, setanswer] = useState(getNumbers());
+ const [tries, settries] = useState([]);
+ const inputRef = useRef(null);
+
+ const onSubmitForm = (e) => {
+ e.preventDefault();
+ if(value === answer.join('')) { // 정답
+ setresult('홈런!');
+ settries((prevTries) => {
+ return [...prevTries, { try: value, result: '홈런!'}]
+ })
+ alert('게임을 다시 시작합니다.');
+ setvalue('');
+ setanswer(getNumbers());
+ settries([]);
+ inputRef.current.focus();
+ } else {
+ const answerArray = value.split('').map((v) => parseInt(v));
+ let strike = 0;
+ let ball = 0 ;
+ if(tries.length >= 9) { // 10번이상 틀렸을 때
+ setresult(`실패! 답은 ${answer.join(',')} 였습니다!`);
+ alert('게임을 다시 시작합니다.');
+ setvalue('');
+ setanswer(getNumbers());
+ settries([]);
+ } else {
+ for (let i = 0; i < 4; i++) {
+ if(answerArray[i] === answer[i]) {
+ strike++;
+ } else if (answer.includes(answerArray[i])) {
+ ball++;
+ }
+ }
+ settries((prevTries) => {
+ return [...tries, {try: value, result: `${strike} 스트라이크, ${ball} 볼 입니다.`}]
+ })
+ setvalue('');
+ }
+ inputRef.current.focus();
+ }
+ }
+
+ const onChangeInput = (e) => {
+ setvalue(e.target.value);
+ }
+
+ return (
+ <>
+ {result}
+
+ 시도: {tries.length}
+
+ {tries.map((v, i) => {
+ return (
+
+ )
+ })}
+
+ >
+ )
+});
+export default NumberBaseball; // import NumberBaseball
\ No newline at end of file
diff --git a/react_webgame/main/games/RSP.jsx b/react_webgame/main/games/RSP.jsx
new file mode 100644
index 00000000..0f855413
--- /dev/null
+++ b/react_webgame/main/games/RSP.jsx
@@ -0,0 +1,89 @@
+import React, { useState, useRef, useEffect } from "react";
+
+const rspCoords = {
+ 바위: "0",
+ 가위: "-142px",
+ 보: "-284px",
+};
+
+const scores = {
+ 가위: 1,
+ 바위: 0,
+ 보: -1,
+};
+
+const computerChoice = (imgCoord) => {
+ return Object.entries(rspCoords).find(function (v) {
+ return v[1] === imgCoord;
+ })[0];
+};
+
+const RSP = () => {
+ const [result, setResult] = useState("");
+ const [imgCoord, setImgCoord] = useState(rspCoords.바위);
+ const [score, setScore] = useState(0);
+ const interval = useRef();
+
+ useEffect(() => {
+ // componentDidMount, componentDidUpdate 역할
+ // setTimeout(changeHand, 100);
+ interval.current = setInterval(changeHand, 100);
+ return () => {
+ // componentWillUnMount 역할
+ clearInterval(interval.current);
+ };
+ }, [imgCoord]);
+
+ const changeHand = () => {
+ if (imgCoord === rspCoords.바위) {
+ setImgCoord(rspCoords.가위);
+ } else if (imgCoord === rspCoords.가위) {
+ setImgCoord(rspCoords.보);
+ } else if (imgCoord === rspCoords.보) {
+ setImgCoord(rspCoords.바위);
+ }
+ };
+
+ const onClickBtn = (choice) => () => {
+ clearInterval(interval.current);
+ const myScore = scores[choice];
+ const cpuScore = scores[computerChoice(imgCoord)];
+ const diff = myScore - cpuScore;
+ if (diff === 0) {
+ setResult("비겼습니다!");
+ } else if ([-1, 2].includes(diff)) {
+ setResult("이겼습니다!");
+ setScore((prevScore) => prevScore + 1);
+ } else {
+ setResult("졌습니다ㅠㅜ");
+ setScore((prevScore) => prevScore - 1);
+ }
+ setTimeout(changeHand, 2000);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ {result}
+ 현재 {score}점
+ >
+ );
+};
+
+export default RSP;
diff --git a/react_webgame/main/games/Try.jsx b/react_webgame/main/games/Try.jsx
new file mode 100644
index 00000000..d5f5ea25
--- /dev/null
+++ b/react_webgame/main/games/Try.jsx
@@ -0,0 +1,11 @@
+import React, { memo } from 'react';
+
+const Try = memo(({ tryInfo }) => {
+ return (
+
+ {tryInfo.try}
+ {tryInfo.result}
+
+ )
+});
+export default Try;
\ No newline at end of file
diff --git a/react_webgame/main/index.html b/react_webgame/main/index.html
index 3257650c..a4512fbf 100644
--- a/react_webgame/main/index.html
+++ b/react_webgame/main/index.html
@@ -1,7 +1,7 @@
- 지뢰찾기
+ Games