본문 바로가기
프로젝트/한글 게임

15. 초성/중성/종성 분리

by 갱생angel 2024. 4. 29.

유니코드를 이용해서 서버에서 가져온 텍스트 데이터의 초성/종성/중성을 분리

 ※유니코드: 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현하고 다룰 수 있도록 하는 표준 문자 전산 방식

    -한글 유니코드에서 자음(ㄱ~ㅎ)은 12593 ~ 12622로 총 27개, 모음(ㅏ~ㅣ)은 12623 ~ 12643로 총 21개

    -종성은 숫자 1마다, 중성은 29 (ㅏ -> ㅐ) 마다, 초성은 589(ㄱ -> ㄲ)마다 값이 변함

[참고] [자바스크립트] 한글 자음 모음 분리 / 초성 * 중성 * 종성|작성자 Scripter

 

page - Game - <CombineGame.js>

charCodeAt(): index에 해당하는 문자의 unicode 값을 리턴

  -choIndex: 초성은 589(ㄱ -> ㄲ)마다 변하므로 588로 나눔(시작 인덱스 값이 0이기 때문)

    ex) 상(49,345): 49,345 - 44,032 = 5313 -> 5313 / 588 = 9(ㅅ)

  -jungIndex: 중성은 29(ㅏ -> ㅐ) 마다 변하고 초성이 바뀔때마다 다시 처음부터 반복되기 때문에 초성 값을 빼주고 28로 나눔

   ex) 상(49,345): 49,345 - 44,032 = 5313 -> (5313 - 10 * 588) / 28 = 0(ㅏ)

  -jongIndex: 종성은 28개의 배열 값을 지니고 있기 때문에 28로 나눈 나머지를 값으로 받음

    ex) 상(49,345): 49,345 - 44,032 = 5313 -> 5313 % 588 = 21(ㅇ)

import axios from "axios";
import React, { useEffect, useState } from "react";
import "../../css/game.css";
import Canvas from "../../component/Canvas";
import Typing from "../../component/Typing";

function CombineGame() {
  const CHO = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ',   //초성
               'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ',
               'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
  const JUNG = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ',  //중성
                'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ',
                'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'];
  const JONG = ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ',    //종성
                'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ',
                'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ',
                'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];

  const [quiz, setQuiz] = useState("");
  const [count, setCount] = useState(1);

  const [gameOver, setGameOver] = useState(false);
  const [checkQuiz, setCheckQuiz] = useState(false);
  const [moreChance, setMoreChance] = useState(0);

  const [answerObj, setAnswerObj] = useState(false);
  const [answerObjName, setAnswerObjName] = useState("타이핑");
  const [answerObjButton, setAnswerObjButton] = useState(false);

  const [charArray, setCharArray] = useState([]); //분리한 낱말 배열 변수,함수

  const separateText = () => { //텍스트 분리
    const result = []; //낱말 저장할 배열
    for (let char of quiz) { //char 변수를 지정하고 quiz에 저장된 텍스트의 낱말을 하나씩 순환
      const unicode = char.charCodeAt(0) - 44032; //char 변수에 저장된 낱말을 유니코드화

      const choIndex = parseInt(unicode / 588); //초성 인덱스 분리
      const jungIndex = parseInt((unicode - choIndex * 588) / 28); //중성 인덱스 분리
      const jongIndex = parseInt(unicode % 28); //종성 인덱스 분리

      const choChar = CHO[choIndex]; //초성을 CHO 배열에 삽입
      const jungChar = JUNG[jungIndex]; //중성을 JUNG 배열에 삽입
      const jongChar = JONG[jongIndex]; //종성을 JONG 배열에 삽입

      result.push(choChar, jungChar, jongChar); //result 배열에 초성,중성, 종성 배열 삽입
    }
    return result;
  };

  const resetButton = () => {
    window.location.reload();
  };

  const changeAnswerObj = () => {
    setAnswerObj((answerObj) => !answerObj);
    if (answerObjName === "타이핑") {
      setAnswerObjName("캔버스");
    } else {
      setAnswerObjName("타이핑");
    }
  };

  const checkAnswer = (text) => {
    if (text === quiz) {
      alert("정답입니다.");
      setCheckQuiz(true);
      setAnswerObjButton(true);
    } else {
      if (moreChance === 0) {
        alert("오답입니다. 한 번 더 시도해보세요.");
        setMoreChance((moreChance) => moreChance + 1);
      } else if (moreChance === 1) {
        alert("오답입니다. 다음 라운드로 넘어갑니다.");
        setMoreChance(0);
        setCheckQuiz(true);
        setAnswerObjButton(true);
      }
    }
  };

  const fetchData = () => {
    axios.get("http://localhost:5000/image").then((res) => {
      if (res.data.game && res.data.game.length > 0) {
        setQuiz(res.data.game[0].title);
        setCount(res.data.count);
        if (count >= 5) {
          setGameOver(true);
          alert(res.data.message);
        }
      } else {
        setGameOver(true);
        alert(res.data.message);
      }
    });
  };

  useEffect(() => {
    fetchData();
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  
  useEffect(() => {
    setCharArray(separateText()); //charArray 배열에 result 배열 저장
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [quiz]);

  return (
    <div className="combineGameContainer">
      <div className="combineDiv">
        {gameOver ? (
          <div>
            <h1>Game Over</h1>
            <button onClick={resetButton}>다시하기</button>
          </div>
        ) : (
          <div>
            <div className="roundDiv">
              <h2>Round: {count} / 5</h2>
              <button onClick={changeAnswerObj} disabled={answerObjButton}>
                {answerObjName}
              </button>
            </div>
            <div className="textQuizDiv"> <!--낱말 나열-->
              {charArray.map((char, index) => (
                <span key={index}>{char}</span>
              ))}
            </div>
          </div>
        )}
      </div>
      {!gameOver && (
        <div>
          {answerObj ? (
            <div>
              <Typing
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          ) : (
            <div>
              <Canvas
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export default CombineGame;

 

css - <game.css>

.combineGameContainer {
  width: 500px;
  margin: 0 auto;
}
.combineDiv {
  text-align: center;
  margin: 0 auto;
}
.combineDiv h2 {
  margin-left: 100px;
  margin-right: 50px;
}
.combineDiv button {
  width: 100px;
  height: 30px;
  font-size: 15px;
  font-weight: bold;
  border: 1px solid black;
  background-color: white;
  margin-right: 10px;
}
.combineDiv button:hover {
  color: white;
  background-color: black;
}
.roundDiv {
  display: flex;
  align-items: center;
}
.combineDiv span {
  font-size: 40px;
  font-weight: bold;
}
.textQuizDiv {
  border: 1px solid black;
  padding: 10px;
  margin-bottom: 10px;
}

 

'프로젝트 > 한글 게임' 카테고리의 다른 글

17. 포인트 기능  (0) 2024.05.11
16. 무작위 나열  (0) 2024.04.29
14. 재도전 기회  (0) 2024.04.26
13. 캔버스/타이핑 변환  (0) 2024.04.26
12. 캔버스, 이미지 데이터 병합  (0) 2024.04.22