단어 게임(시간이내에 문제 풀기)

개발공부·2022년 12월 13일
0
post-thumbnail

* 결과

1) 단어 선택

2) 단어 선택 후 문제 풀이

3) 힌트보기(한국어 기초사전 API 사용)

4) 맞는 답은 +10, 틀린 답은 빨강색 X

5) 다 맞추면 알림(modal)

6) 다시 게임 시작 및 10개 미만인 경우

7) 게임 시 시간 초과인 경우

* 만드는 과정에서 생긴 문제

1) redux-toolkit에서 가져온 값은 바로 수정, 삭제 불가

  • 얕은 복사 후 해당 값을 진행함
  • 체크한 단어들이 랜덤으로 계속 섞임
    -> useEffect의 두 번째 값을 []으로 지정
    -> []를 추가하면 첫 렌더링에만 호출이 되어 그 이후에는 절대 재호출 되지 않음

2) 랜덤으로 값을 정렬하는 과정

  • 피셔-예이츠 셔플(Fisher-Yates shuffle) 사용
  • 게임 시작 전 단어 선택 후 shuffle에 값을 넣음
  • 1)에서 말한 것처럼 useEffect에 []이 아닌 [다른값] 존재 시 랜덤함수가 계속 호출되니 주의
  useEffect(() => {
    const shuffleArray = (array) => {
      for (let i = array.length - 1; i > 0; i--) {
        // 무작위로 index 값 생성 (0 이상 i 미만)
        let j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
      }
    };
    shuffleArray(checkedWords);
    setGameLists(checkedWords);
  }, []);

3) tailwindcss 초단위로 길이가 줄어들어야 했음

  • 변수는 인식하나 삼항연산자 인식 못함
  • num으로 0, 1, 2, 3 숫자 증가 시 길이가 줄어들도록 함
const [sec, setSec] = useState(12);
  const [num, setNum] = useState(0);
  const time = useRef(12);
  
//타이머
  useEffect(() => {
    timerId.current = setInterval(() => {
      setSec(parseInt(time.current));
      time.current -= 1;
    }, 1000);

    return () => clearInterval(timerId.current);
  }, []);

  //타임아웃
  useEffect(() => {
    if (time.current < 0) {
      console.log("타임 아웃");
      clearInterval(timerId.current);
    }
  }, [sec]);

return (
<div
              className={`bg-light-green rounded-full h-full
              ${sec === 11 && "w-11/12"}
              ${sec === 10 && "w-10/12"}
              ${sec === 9 && "w-9/12"}
              ${sec === 8 && "w-8/12"}
              ${sec === 7 && "w-7/12"}
              ${sec === 6 && "w-6/12"}
              ${sec === 5 && "w-5/12"}
              ${sec === 4 && "w-4/12"}
              ${sec === 3 && "w-3/12"}
              ${sec === 2 && "w-2/12"}
              ${sec === 1 && "w-1/12"}
              ${sec === 0 && "w-0"}`}
            ></div>
)

4) 체크한 단어들을 게임에서 사용할 수 있도록 전달

  • dispatch 사용
  • 1)내용처럼 얕은 복사 후 진행함
  const dispatch = useDispatch();
  const { checkedWordLists } = useSelector((state) => state.game);
  const checkedWords = [...checkedWordLists];

5) 단어 선택 후 게임처럼 객체를 정리해야 함 & 각 값에 1,2,3,4 answers이 랜덤 부여

  • 2)에 관한 내용을 배열 [1,2,3,4]를 랜덤 배열 후 값 정렬해 redux-toolkit으로 전달
  • 이 과정이 제일 복잡했음
    ▶ 1. redux-toolkit에서 가져온 값 중 체크할 값(checkedWordList) 선택
    ▶ 2. 체크한 값과 나머지 값(remainderData) 구분
    ▶ 3. 나머지 값 중 index 값 따로 만듦
    ▶ 4. 답이 되는 [1, 2, 3, 4] 제외한 나머지 값들 랜덤으로 섞기
    ▶ 5. 최종적으로 게임에 전달해야 할 형식대로 push하기
    ▶ 6. 들어간 형식과 답안이 맞을경우, 틀릴 경우 구분할 것
 const { wordLists, checkedWordList } = useSelector((state) => state.word); //checkedWordList는 빈배열임

  const checkedData = [...checkedWordList];
  const allData = [...wordLists];
  const numbers = [1, 2, 3, 4];
  const result = [];

  const onStartGame = useCallback(() => {
    if (checkedWordList.length < 10) {
      console.log("10개 미만!");
      setAlert(true);
      setGameStart(false);
      setOpen(true);
    } else {
      const remainderData = allData.filter((data) => data.status === "A");
      const remainderEnglish = [];
      const remainderIndex = [];

      remainderData.map((data, i) => {
        remainderEnglish.push(data.english);
        remainderIndex.push(i);
        // remainderIndex(0, 5);
      });

      remainderIndex.splice(0, 5);

      const shuffleArray = (array) => {
        for (let i = array.length - 1; i > 0; i--) {
          // 무작위로 index 값 생성 (0 이상 i 미만)
          let j = Math.floor(Math.random() * (i + 1));
          [array[i], array[j]] = [array[j], array[i]];
        }
      };

      shuffleArray(remainderEnglish);
      shuffleArray(remainderIndex);

      checkedData.map((data, i) => {
        shuffleArray(numbers); //랜덤 1, 2, 3, 4
        const randomIdx1 = remainderIndex[0];
        const randomIdx2 = remainderIndex[1];
        const randomIdx3 = remainderIndex[2];
        if (numbers[0] === 1) {
          result.push({
            question: data.korean,
            answer: 1,
            choices: [
              data.english,
              remainderEnglish[randomIdx1],
              remainderEnglish[randomIdx2],
              remainderEnglish[randomIdx3],
            ],
          });
        } else if (numbers[0] === 2) {
          result.push({
            question: data.korean,
            answer: 2,
            choices: [
              remainderEnglish[randomIdx1],
              data.english,
              remainderEnglish[randomIdx2],
              remainderEnglish[randomIdx3],
            ],
          });
        } else if (numbers[0] === 3) {
          result.push({
            question: data.korean,
            answer: 3,
            choices: [
              remainderEnglish[randomIdx1],
              remainderEnglish[randomIdx2],
              data.english,
              remainderEnglish[randomIdx3],
            ],
          });
        } else if (numbers[0] === 4) {
          result.push({
            question: data.korean,
            answer: 4,
            choices: [
              remainderEnglish[randomIdx1],
              remainderEnglish[randomIdx2],
              remainderEnglish[randomIdx3],
              data.english,
            ],
          });
        }
      });
      // console.log("checkedData", checkedData);
      console.log("result", result);

      dispatch(startGameRequest(result));
      setGameStart(true);
      setOpen(false);
      console.log("gameStart", gameStart);
    }
  }, [result]);
  • 게임에 넣기 전 데이터

    {
    id: 2,
    english: "red",
    korean: "빨강",
    type: "easy",
    status: "A",
    },

  • 게임에 넣고 난 뒤 데이터

    {
    question: "빨강",
    answer: 1,
    choices: ["red", "purple", "yellow", "blue"],
    },

6) 맞는 값 클릭 시 +10, 틀린 값 클릭 시 X값 나오게 하기

  • div의 id값을 찾고 div값 생성 후 적용하기
 const plusPoint = (p, pointName, name) => {
    let copy = [...answers];
    copy[p] = true;
    setAnswers(copy);
    const pointDivName = document.getElementById(pointName);

    let div = document.createElement("div");
    div.id = name;
    div.className =
      "z-10 absolute right-0 bottom-8 bg-light-orange pt-2 pl-2 transform rotate-0 rounded-full h-12 w-12 text-white font-bold shadow-md transform  text-black text-lg";
    let text = document.createTextNode("+10");
    div.appendChild(text);
    pointDivName.appendChild(div);
  };

  const errorAnswer = (p, pointName, name) => {
    let copy = [...answers];
    copy[p] = true;
    setAnswers(copy);
    const pointDivName = document.getElementById(pointName);

    let div = document.createElement("div");
    div.id = name;
    div.className =
      "z-10 text-xl absolute left-0 top-2 text-lg font-bold text-center bg-red-500 pt-2 transform rotate-0 rounded-full h-12 w-12 text-white font-bold shadow-md text-white";
    let text = document.createTextNode("X");
    div.appendChild(text);
    pointDivName.appendChild(div);
  };

* 참고

profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글