JS 끝말잇기 게임 만들어보기

shinyeongwoon·2022년 10월 26일
0

JS

목록 보기
14/16

끝말잇기 게임 만들어보기

<!DOCTYPE html> <html>
<head>
<meta charset="utf-8">
<title>끝말잇기</title> </head>
<booy>
<div><span id="order">1</span>번째 참가자</div> <div>제시어: <span id="word"></span></div> <input type="text">
<button>입력</button>
<script>
</script>
</body> </html>

Chrome 화면

1) 참가자 수 정하기

참가자 수를 사용자로 부터 입력받는다

prompt 사용하기

prompt('몇 명이 참가하나요?');

위 와 같은 prompt 창에 입력을 할 수 있게 된다.
입력 값은 prompt의 반환값으로 반환 되며 변수에 담아 활용할 수 있다.

const member = prompt('몇 명이 참가하나요?');
console.log(member);

prompt 창에 3 입력

결과 )
3

참가자의 수를 입력하기 때문에 숫자가 아닌 값이 입력되는 경우 검열이 필요하다
정규식을 사용할 수 있으나 JS의 특성을 좀 더 파악하기 위해 타입을 이용한 방법을 사용해 보겠다.

const member = prompt('몇 명이 참가하나요?');
console.log(typeof member);

결과 )
string

prompt로 받아오는 사용자 입력은 모두 string type으로 받아오게 된다.
숫자만을 받아오기 위해 number type인지 확인하고 아니면 다시 입력하도록 설계가 필요하다.

 const member = Number(prompt('몇 명이 참가하나요?'));
 console.log(typeof member);

숫자 3을 입력하는 경우 number type으로 출력되지만
숫자가 아닌 다른 타입이 입력 되는 경우 NaN (Not a Number, Number type)이 출력된다.
여기서 typeof 로 타입검사만 하게 된다면 NaN은 Number type이므로 검열이 제대로 되지 않는다.

const member = Number(prompt('몇 명이 참가하나요?'));
if(typeof member == 'number'){
    console.log('number');
}

prompt 에 a를 입력

결과 )
number

JS에서는 NaN infinity null undefined 등의 자료형을 파악해 두는 것이 중요하다.

이를 해결하는 방법은 NaN이 반환되는 특징을 이용하는 것이다.
JS에서는 isNaN() 이라는 메소드를 지원한다.
이를 이용하여 검열을 하는 코드를 작성해보면

let member; 
while(true){
  member = Number(prompt('몇 명이 참가하나요?'));
  if(!isNaN(member)) break;
}

위와 같이 무한 loop를 이용하여 알맞는 값이 입력 되지 않으면 재 입력을 하도록 만든다
문자가 입력되면 isNaN이 true를 반환하기 때문에 !을 이용해 반전해준다.
즉, 숫자가 입력되었을 때 break를 만나 무한 loop를 빠져나오게 설계한다.

실수의 경우 검열에 실패하지만 일단 넘어가도록 한다.

입력창 (input tag)로 입력받기

input tag에 입력되는 사용자입력을 JS에서 사용하기 위해서는 해당 입력창을 JS로 가져와야 한다.
이를 '선택'이라고 한다.

//단일 선택일때
document.querySelector('선택자');
//다중 선택일때
document.querySelectorAll('선택자');

input tag 와 button tag를 활용하기 위해 JS 변수에 선택하여 대입한다

const $input = document.querySelector('input');
const $button = document.querySelector('button');    

tag에 event 달기

사용자와 태그와 상호 작용할 때 이벤트 발생
input 태그에 글자 입력 : input 이벤트 발생
JS는 이벤트를 자동으로 감지 하지 못함 - 이벤트 리스너를 달아줘야 한다.

$input.addEventListener('input',function(){
  console.log($input.value);
});

input tag에 addEventListener를 통해 input 이벤트를 감지하도록 달아주면
입력이 일어날때 콜백함수가 실행되게 된다.

위 코드를 화살표 함수 방식으로 표현하면

$input.addEventListener('input',() => {
  console.log($input.value);
});

위와 같이 간소화 할 수 있다.
이어 버튼에도 이벤트리스너를 달아 활용하도록 변경해주겠다.


const $input = document.querySelector('input');
const $button = document.querySelector('button');
    
$input.addEventListener('input',() => {
  console.log($input.value);
});

$button.addEventListener('click',() => {
  console.log("button click");
});

위와 같이 코드를 작성하는 경우 이벤트 콜백 함수가 재활용면에서 효율이 떨어지게 된다
중복 코드를 줄이기 위해 콜백 함수를 따로 변수에 담아 재활용성을 높여주도록 하자

const inputText = () => {
  console.log($input.value);
}

const clickBtn = () => {
  console.log("button click")
}

$input.addEventListener('input',inputText);
$button.addEventListener('click',clickBtn);

동작은 동일하나 코드의 재활용성은 높아진다.

이제 버튼클릭 시 input tag의 입력값을 알 수 있도록 코드를 수정해 보자

const $input = document.querySelector('input');
const $button = document.querySelector('button');
let input = '';
const inputText = () => {}

const clickBtn = () => {
  input = $input.value;
  console.log(input);
}

//$input.addEventListener('input',inputText);
$button.addEventListener('click',clickBtn);

input event는 아직 사용하지 않아도 됨으로 일단 주석처리한다.
button이 클릭 되면 $input의 value 값을 취해 input 변수에 담아준다

첫 단어를 입력한 사람인지 판단하기

일단 코드의 가독성을 위해 리팩토링 한다.

const $input = document.querySelector('input');
const $button = document.querySelector('button');

let member; 
let input = '';

while(true){
  member = Number(prompt('몇 명이 참가하나요?'));
  if(!isNaN(member)) break;
}

const inputText = () => {}

const clickBtn = () => {
  input = $input.value;
  console.log(input);
}

//$input.addEventListener('input',inputText);
$button.addEventListener('click',clickBtn);

첫단어 인지 판단하기 위해서는 단어를 대입해 보관할 변수를 만들고 그 변수가 비어 있는지 확인하면 된다.

const $input = document.querySelector('input');
const $button = document.querySelector('button');

let member; 
let word;

while(true){
  member = Number(prompt('몇 명이 참가하나요?'));
  if(!isNaN(member)) break;
}

const inputText = () => {}

const clickBtn = () => {
  if(!word){
  
  }else{
  
  }
}

//$input.addEventListener('input',inputText);
$button.addEventListener('click',clickBtn);

clicBtn 함수 내 if문의 조건문을 보면 !word가 있다.
word에 아무값도 대입하지 않으면 undefined로 초기화 된다.
undefined를 !!를 사용해서 bool type으로 변경해보면 false가 나온다.
즉 undefined는 false이다. undefined에 !(반전)을 주어 true로 만들어 준다는 이야기는
곧 비어있지 않다는 이야기가 된다.

정리하자면 if(!word) 조건은 첫 단어가 입력되어 있지 않는경우를 뜻한다.
첫 단어가 입력되어 있지 않은 경우 제시어로 판단하면 된다.

const clickBtn = () => {
  if(!word){
    word = $input.value;
    console.log(word);
  }else{
    console.log('첫단어 ㄴㄴ');
  }
}

위와 같이 코드를 입력하면 첫 단어의 경우 입력된 단어를 출력하고 아닐경우 첫단어 ㄴㄴ 가 출력된다.

const $input = document.querySelector('input');
const $button = document.querySelector('button');

let member; 
let word;
let newWord;
    
while(true){
  member = Number(prompt('몇 명이 참가하나요?'));
  if(!isNaN(member)) break;
}

const inputText = () => {
  newWord = $input.value;
}

const clickBtn = () => {
  if(!word){
    word = newWord;
    console.log(word);
  }else{
    console.log('첫단어 ㄴㄴ');
  }
}

$input.addEventListener('input',inputText);
$button.addEventListener('click',clickBtn);

input event 와 newWord 변수를 활용하여 짜면 위 코도와 같이 리팩토링 할 수 있다.
input evnet를 통해 newWord에 입력 단어를 받아오고 word가 비어있는지 판단하고
비어 있다면 word 변수에 newWord를 대입하여 제시어를 대입해준다.

제시어 이후 입력단어가 올바른지 판단하기

문자열 문자 분리와 길이구하기를 통해 끝말잇기에 올바른 단어인지 판단한다.
문자열[자릿수], 문자열.length를 통해 원하는 값을 구할 수 있다.


const $word = document.querySelector('#word');

const clickBtn = () => {
  if(!word){
    word = newWord;
    $word.textContent = word;   
  }else{
    if(word[word.length - 1] == newWord[0]){
      console.log('word 끝자리와 newWord 첫자리가 일치합니다.');
    }else{
    
    }
  }
}

글의 가독성을 위해 반복되는 부분은 생략하겠다.
위 코드와 같이 const $word = document.querySelector('#word'); 를 추가해
제시어가 입력되면 화면에 표시 되도록 코드를 작성했다.

또 첫 단어가 아닌 뒷사람이 단어를 입력하면 이전 단어의 끝자리와 다음 입력된 단어의 첫자리 문자가 일치하는지 확인한다.

다음 사람에게 순서 넘기기

const $order = document.querySelector('#order');

let order;

const clickBtn = () => {
  if(!word){
    word = newWord;
	$word.textContent = word;
	order = Number($order.textContent);    
    if(order >= 3){
      $order.textContent = 1;
    }else{
      $order.textContent = order + 1;
    }       
  }else{
    if(word[word.length - 1] == newWord[0]){
      console.log('word 끝자리와 newWord 첫자리가 일치합니다.');
      order = Number($order.textContent);    
      if(order >= 3){
        $order.textContent = 1;
      }else{
        $order.textContent = order + 1;
      }  
    }else{
      alert('올바르지 않은 단어입니다.');
    }
  }
}

const $order = document.querySelector('#order');
let order;
를 추가하고 button click이 발생되면 order 에 $order.textContent 의 값을 대입한다.
이때 $order.textContent의 값이 string이기 때문에 Number() 로 감싸 연산 시 원하는 값을 얻을 수 있도록 형변환 해준다.

첫단어가 아니더라도 순서는 변해야 하기 때문에 첫 단어가 아닌 판단문에도 순서넘기기 코드를 삽입해 준다.

입력된 단어가 올바르지 않은 경우 alert를 통해 올바르지 않은 단어라고 알려준다
물론 순서는 넘기지 않는다.

부족한점 추가하기

순서를 넘긴 후 input tag에는 전 입력자의 값이 남아 있다. 또 입력창에 단어입력을 위해 늘 입력창을 클릭해야 한다.

const clickBtn = () => {
  if(!word){
    
  }else{
    if(word[word.length - 1] == newWord[0]){
    
    }else{
    
    }
  }
  $input.value = '';
  $input.focus();
}

button이 클릭되면 $input.value의 값을 ''로 초기화 해주고 $input.focus()를 통해 input tag를 click하지 않아도 자동으로 포커스 되도록 만들어 준다.

이쯤 되면 중복 코드로 인해 코드이 가독성이 떨어지기 시작한다.
중복코드를 제거하고 코드 최적화를 해보자

if(!word){
  word = newWord;
  $word.textContent = word;
  order = Number($order.textContent);    
  if(order >= 3){
    $order.textContent = 1;
  }else{
    $order.textContent = order + 1;
  }
   
//------------------------------------
   
if(word[word.length - 1] == newWord[0]){
  console.log('word 끝자리와 newWord 첫자리가 일치합니다.');
  order = Number($order.textContent);    
  if(order >= 3){
    $order.textContent = 1;
  }else{
    $order.textContent = order + 1;
  }

위 코드들은 중복이 발생한다.
잘 분석해 보면 첫단어를 입력하거나 다음단어 입력 시 검열에 통과한다면 입력된 단어를 제시어로 등록하고 순서를 넘긴다
'입력하거나' 로 해석되기 때문에 ||로 중복을 제거 할 수 있다.

const clickBtn = () => {
  if(!word || word[word.length - 1] == newWord[0]){
    word = newWord;
    $word.textContent = word;
    order = Number($order.textContent);    
    if(order >= 3){
      $order.textContent = 1;
    }else{
      $order.textContent = order + 1;
    }
  }else{
    alert('올바르지 않은 단어입니다.');
  }
  $input.value = '';
  $input.focus();
}

위 코드와 같이 리팩토링해도 잘 동작 된다.

위 코드의 버그를 찾아보자

  1. 첫 번째 사람이 문자가 아닌 숫자를 말하는 경우
  2. 다음 참가자가 첫번째 음절만 맞고 나머지 숫자등 검열을 어기는 경우
  3. 한 음절의 단어를 말할경우

물론 이외 버그들이 상당히 많을 것이다.
하나하나 테스트하며 리팩토링 과정을 거쳐 점진적으로 높은 품질의 프로그래밍을 하는것이 개발자의 궁극적인 목표이다.
일단 위 3개의 버그를 수정하는 것을 목표로 프로그래밍을 해 보자.

1,2번의 버그의 경우 정규식을 통해 해결 할 수 있다.

참고 : https://hamait.tistory.com/342

정규식은 늘 까먹는다 늘 새로워!!!!

일단 이 게임에선 한글만 입력 받도록 하겠다.


const check = /[ㄱ-ㅎ|가-힣]/;

if(check.test(newWord)){
  if(!word || word[word.length - 1] == newWord[0]){
    word = newWord;
    $word.textContent = word;
    order = Number($order.textContent);    
    if(order >= 3){
      $order.textContent = 1;
    }else{
      $order.textContent = order + 1;
    }
  }else{
    alert('올바르지 않은 단어입니다.');
  }
  $input.value = '';
  $input.focus();
}else{
  alert('한글만 입력하세요!!');
}

check 변수에 원하는 정규식을 대입하고 check.test(newWord)를 통해 입력된 단어를 검열한다.
정규식에 알맞는 단어가 입력되면 check.test()는 true를 반환한다.
알맞는 단어가 아닐경우 alert를 통해 알려준다.

  1. 한 음절의 단어를 말할경우
    newWord의 단어 길이를 판단하면 된다.
    if(check.test(newWord) && newWord.length > 1) 로 수정하여 한음절 단어도 검열한다.

full code

<!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>끝말잇기</title>
</head>
<body>
  
  <div><span id="order">1</span>번째 참가자</div>
  <div>제시어: <span id="word"></span></div>
  <input type="text">
  <button>입력</button>

   <script>
    
    const $input = document.querySelector('input');
    const $button = document.querySelector('button');
    const $word = document.querySelector('#word');
    const $order = document.querySelector('#order');

    const check = /[ㄱ-ㅎ|가-힣]/;

    let member; 
    let word;
    let newWord;
    let order;

    while(true){
      member = Number(prompt('몇 명이 참가하나요?'));
      if(!isNaN(member)) break;
    }

    const inputText = () => {
      newWord = $input.value;
    }

    const clickBtn = () => {
      if(check.test(newWord) && newWord.length > 1){
        if(!word || word[word.length - 1] == newWord[0]){
          word = newWord;
          $word.textContent = word;
          order = Number($order.textContent);    
          if(order >= 3){
            $order.textContent = 1;
          }else{
            $order.textContent = order + 1;
          }
        }else{
          alert('올바르지 않은 단어입니다.');
        }
        $input.value = '';
        $input.focus();
      }else{
        alert('한글또는 단어를 입력하세요');
      }
    }
    $input.addEventListener('input',inputText);
    $button.addEventListener('click',clickBtn);

  </script>

</body>
</html>

0개의 댓글