본문 바로가기

프로그래밍/javascript

[javascript] API를 활용해서 컴퓨터와 하는 끝말잇기 게임 만들기(3)

728x90
반응형
SMALL

저번 글에서 게임의 시작과 종료를 구현했다

 

이제는 API를 이용해 단어가 정말 있는 단어인지 아닌지를 확인해서 게임의 기능을 구현할 것이다

 

우선 API 가져오기 위해 우리말샘이라는 API 제공 사이트를 이용한다

 

https://opendict.korean.go.kr/service/openApiInfo

 

우리말샘 - 오픈 API 서비스 소개

1. 우리말샘 오픈 API 서비스 소개 우리말샘 오픈 API는 검색 플랫폼을 외부에 공개하여 다양하고 재미있는 서비스 및 애플리케이션을 개발할 수 있도록 외부 개발자와 사용자들이 공유하는 프로

opendict.korean.go.kr

 

위 사이트에 접속 후 회원가입을 한 뒤 API KEY를 발급받아 주면 된다

 

API로 보낼 파라미터는 상세하게 설명이 되어 있으니 문서를 참고해서 사용하면 된다

 

한 가지 아쉬운 건 데이터 타입이 JSON이 아닌 XML 형식이라 우리는 데이터를 받아와 XML을 한번 파싱 해서 사용해 줘야 한다

 

뭐 그렇게 어려운 건 아니니 일단 진행해 보자

 

우선 API를 가져올 준비를 했으니 가져오기 전에 끝말잇기에서 중요하다면 중요한 두음법칙을 처리해야 한다

 

직접 구현해도 되지만 이미 만들어진 라이브러리를 가져와 사용하겠다

 

https://github.com/123jimin/hangul-tools

 

123jimin/hangul-tools

한글 분해, 결합, 조사 처리, 두음 법칙 적용, 숫자 읽기, 쿼티를 한글로 변환 등등의 잡다한 한글 관련 함수를 사용할 수 있는 자바스크립트 라이브러리 - 123jimin/hangul-tools

github.com

위 github에 들어가면 hangul-tools.js라는 파일을 다운로드하거나 복사해와서 js폴더에 그대로 넣어 준다

 

그 후 html 파일에서 불러오기만 하면 끝이다

 

index.html 파일에 아래와 같이 한 줄 추가해준다

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/index.css">
</head>
<body>
    
    <div class="main">
        <div class="keyWord"></div>
        
        <input type="text" id="word" autocomplete="off">
        
        <div class="timeZone"></div>

        <div class="point">
            <span>점수 : </span>
            <span id="point"></span>
        </div>

    </div>

    <script src="js/hangul-tools.js"></script>
    <script src="js/game.js"></script>
</body>
</html>

 

그다음 game.js 에 저번에 작성했던 소스 밑에 아래 소스를 추가해 주면 게임은 완성이다

 

const apiKey = "발급받은 본인의 apiKey"

input.addEventListener("keydown", function(event) {
    if(event.keyCode === 13) {
        const prevWord = keyWord.innerHTML
        word = this.value

        clearInterval(start)

        if(word.length > 1 && HanTools.dueum(prevWord[prevWord.length - 1]) === word[0]) {

            fetch(`https://opendict.korean.go.kr/api/search?key=${apiKey}&q=${word}&advanced=y&method=exact`)
            .then(res => {
                return res.text()
            })
            .then(data => {
                
                const parser = new DOMParser()
                const xmlDoc = parser.parseFromString(data, "text/xml")

                const result = xmlDoc.getElementsByTagName("total")[0].childNodes[0].nodeValue

                if(result > 0) {
                    keyWord.innerHTML = word
                    this.value = ''
                    this.style.outline = ''
                    time = 10

                    point = point + (word.length * 10)
                    pointZone.innerHTML = point

                    fetch(`https://opendict.korean.go.kr/api/search?key=${apiKey}&q=${HanTools.dueum(word[word.length - 1])}&advanced=y&sort=popular&type1=word&method=start&num=100`)
                    .then(res => {
                        return res.text()
                    })
                    .then(comData => {
                        const comXmlDoc = parser.parseFromString(comData, "text/xml")
                        const item = comXmlDoc.getElementsByTagName("item")
                
                        let comWord = []
                        
                        Array.from(item).forEach(item => comWord.push(item.getElementsByTagName("word")[0].childNodes[0].nodeValue) )
                        
                        comWord = comWord.map(word => word.replace(/\-|\^/g, ""))
                                        .filter(word => word.length > 1 )
                        
                        keyWord.innerHTML = comWord[Math.floor(Math.random() * comWord.length)]   

                        timeCheck()
                        start = setInterval(timeCheck, 1000)
                    })
                    .catch(error => {
                        console.log(error)
                    })

                } else {
                    this.value = ''
                    this.style.outline = '1px solid red'
                    start = setInterval(timeCheck, 1000)
                }
                
            })
            .catch(error => {
                console.log(error)
            })

            
        } else {
            this.value = ''
            this.style.outline = '1px solid red'
            start = setInterval(timeCheck, 1000)
        }
        
    }
})

이제 소스를 살펴보자

 


우선 input 창에서 엔터를 입력했을 때 우리가 쓴 단어가 맞는 단어인지 API를 호출하게 만들기 위해

keydown이라는 이벤트 리스너를 등록해 주었고 엔터키의 코드는 13이기 때문에 13번이 들어왔을 때 동작하도록 해주었다

 

prevWord 현재 화면에 보이는 단어로 우리가 이어서 말해야 할 단어가 되는 것이다

즉 화면에 찍혀있는 단어를 prevWord 넣어준 것이다

 

그 뒤에 word에 우리가 입력한 단어를 넣어 준 뒤 clearInterval로 시간을 멈추게 해 놨다

왜냐하면 우리가 API로 정보를 받아오는 게 생각보다 시간이 조금 걸려서 우선은 이 부분은 간단하게 만들어 볼 게임이기 때문에 크게 신경 쓰지 않고 잠시 시간을 멈추는 걸로 해결했다

 

if문을 보면 우리가 입력단 단어가 2글자 이상이어야 하며 우리가 이어 말해야 할 prevWord의 끝 글자를 외부에서 가져온 HanTools.dueum 에 넣어주면 리턴 값이 두음법칙에 의해 바뀐 음절이 리턴이 된다 예를 들어 "님"으로 끝난 단어를 

HanTools.dueum으로 리턴 받은 값이 "임"으로 바뀌게 되는 것이다 즉 "님"으로 끝난 단어를 우리가 이어 말할 때는 "임금님"이라고 말해도 리턴 값이 "임"이기 때문에 우리가 말한 단어의 첫 번째인 word[0] 을 이용하면 "임" === "임" 이 되는 것이다 만약 우리가 말한 단어가 2글자 이상이 아니거나 이어 말할 단어의 끝 글자가 우리가 말한 단어의 첫 글자와 틀리게 되면 else 구문으로 들어가 입력창을 공백으로 비우고 테두리를 빨갛게 표시해 준 뒤 멈춰놨던 시간을 다시 진행하게 되어 있다

 

그다음 우리가 입력한 단어가 조건에 충족하게 되면 fetch를 이용해 API를 호출하게 되는데 여기서 fetch는 IE 브라우저에서는 지원이 안되니 IE에서 사용하길 원한다면 polyfill이라는 걸 구글에 검색해 보면 될 것이다 참고로 IE 브라우저는 22년 6월 완전 종료 예정인 브라우저이니 웬만하면 Edge나 Chrome을 이용하길 권장한다

 

fetch 안에 아래 URL을 호출하는데

https://opendict.korean.go.kr/api/search?key=${apiKey}&q=${word}&advanced=y&method=exact

여기서 봐야 될 건 key 파라미터에 우리가 발급받은 apiKey 값을 넣어주고 q 파라미터에는 우리가 입력한 단어를 넣어준다 그리고 advanced라는 파라미터를 y로 해줘야 API에서 원하는 설정이 작동하게 된다 method에 exact라는 값은

우리가 q에 넣어준 단어와 완전 일치하는 단어만 가져오게 하는 것이다

 

그리고 API를 정상적으로 리턴 받았다면 XML을 파싱 해서 원하는 결괏값만 뽑아오면 되는데 여기서 해야 할 건 우리가 입력한 단어로 검색했을 때 검색한 결과 수가 0이 아니면 있는 단어로 판단해 정상 처리를 하면 된다 XML구조를 보면 total이라는 곳에 값이 우리가 입력한 단어의 존재하는 개수인걸 파악할 수 있다

 

그럼 XML을 파싱 하기 위해 DOMParser라는 걸 이용해 우리가 받은 xml형식의 data를 전달해 준 뒤 거기서 total이라는 노드를 찾아 그 안에 있는 값을 꺼내 오는 과정을 한 것이다

 

결국 우리가 꺼내온 값이 0보다 크다면 다음 동작을 처리할 것이고 그렇지 않다면 없는 단어를 말한 것이기 때문에 입력창을 비우고 빨간 테두리를 씌워준 뒤 다시 시간 초가 흐르게 만들어 주었다

 

입력 값이 정상이라면 시간을 다시 10초로 리셋 해준 뒤에 점수는 우리가 말한 단어의 길이에 10을 곱한 값을 점수로 넣어 주었다

 

그런 뒤에 우리는 컴퓨터가 이어 말하는 듯한 작업을 만들기 위해 fetch로 아래와 같은 URL을 호출하는데

https://opendict.korean.go.kr/api/search?key=${apiKey}&q=${HanTools.dueum(word[word.length - 1])}&advanced=y&sort=popular&type1=word&method=start&num=100

여기서 봐야 할 것은 두음법칙으로 변환한 우리가 말한 단어의 끝 음절을 검색어로 보냈으며 sort는 사람들이 검색을 많이 한 인기순으로 보이게 하고 type 1 은 단어인 것만 나오게 했다 method에 start는 우리가 검색어로 입력한 단어로 시작하는 단어를 찾으라는 뜻이며 num=100 은 100개까지 찾으라는 뜻이다 그럼 이제 다시 API를 리턴 받은 값에서 무작위로 아무 단어나 뽑아오면 컴퓨터가 우리가 말한 단어를 이어 말한 듯한 효과를 볼 수 있다

 

여기서 우리는 XML에 item이라는 노드에 word라는 자식 노드의 값을 가져와야 하는데 item이라는 노드는 여러 개 이므로 comWord라는 배열의 변수를 만들어 forEach를 활용해 item의 노드를 순차적으로 돌면서 그 안에 있는 word라는 자식 노드의 값을 배열에 넣어주는 작업을 했다

 

그 뒤에 값을 정제하는 작업이 필요한데 API를 호출한 XML 문서를 보면 단어에 -,^ 이런 특수문자가 들어가 있는 걸 확인할 수 있다 우리는 저런 특수문자를 제거한 뒤 단어의 길이가 2개 이상인 단어를 다시 comWord 배열에 넣어줘야 하기 때문에 map을 이용해 정규식으로 -,^ 특수문자를 없애 준 뒤 filter를 통해 단어의 길이가 2글자인 것만 다시 배열에 넣어 주는 작업을 했다

 

그런 다음 화면에 뿌려줄 단어를 배열에서 무작위로 뽑아 와야 하기 때문에 배열의 길이만큼 랜덤의 숫자를 뽑아 무작위로 뽑아와 화면에 뿌려준 뒤 다시 시간을 동작하게 하면 컴퓨터와 내가 단어를 하나씩 번갈아 가며 말하는 끝말잇기가 완성된 것이다


 

이걸로 자바스크립트를 활용해 어렵지 않게 끝말잇기 게임을 만들어 보았다

 

아 참고로 저 소스에는 문제가 없지만 아마 실제 브라우저에서 동작하게 되면 CORS 정책에 걸려 작동이 안 될 것이다

 

CORS의 해결방법에는 여러 가지가 있다 

 

1) server 쪽에서 origin을 등록해 풀어주는 방법

2) proxy서버를 두어 우회하는 방법

3) 브라우저에서 풀어 주는 방법

등이 있는데 저 API 서버는 우리가 만든 서버가 아니므로 1번은 불가능하며 우리는 간단하게 만들어 동작 확인만 해볼 것이기 때문에 나는 브라우에서 풀어주는 방법을 선택했다

 

기본적으로 CORS는 브라우저에서 막아 놓는데 이것을 푸는 방법은 매우 간단하다

 

cors를 검색 후 맨 아래 프로그램을 받아 준 뒤에

실행시켜 왼쪽 빨간 테두리를 클릭하면 불이 꺼졌다 켜졌다 하는데 불이 켜져 있는 게 cors 기능을 브라우저에서 끄는 것이다

 

cors를 끄고 동작시키면 정상적으로 잘 동작이 될 것이다

 

아 그리고 우리가 말한 단어가 정말 한방 단어가 아닌 이상 컴퓨터는 끝없이 우리가 말한 단어를 이어 말하기 때문에

컴퓨터를 이길 수는 없고 최대한 점수를 쌓아가면서 플레이를 해보면 좋을 것 같다

 

[javascript] API를 활용해서 컴퓨터와 하는 끝말잇기 게임 만들기(1)

 

[javascript] API를 활용해서 컴퓨터와 하는 끝말잇기 게임 만들기(1)

javascript와 API를 활용해 컴퓨터와 하는 끝말잇기 게임을 만들어 볼 것이다 위 동영상처럼 잘못 입력하면 재입력을 받고 맞는 단어를 말하면 다음 턴으로 컴퓨터로 넘어가며 내가 말한 단어의 글

ldevlog.tistory.com

[javascript] API를 활용해서 컴퓨터와 하는 끝말잇기 게임 만들기(2)

 

[javascript] API를 활용해서 컴퓨터와 하는 끝말잇기 게임 만들기(2)

이전 글에서 화면은 완성했기 때문에 이번 글부터는 javascript를 이용해서 기능을 넣어 볼 것이다 우선은 처음 게임이 시작할 때 주어지는 단어와 시간 그리고 점수를 화면에 그려 줄 것이다 index.

ldevlog.tistory.com

 

728x90
반응형
LIST