[js]카드 짝 맞추기(이벤트 루프)

babypig·2023년 1월 14일
1

javascript

목록 보기
9/12
post-thumbnail

이벤트 루프를 시각적으로 확인 가능한 사이트

  • 호출 스택(Call Stack) : 함수들이 실행되는 공간
  • 백그라운드: 타이머, 이벤트 리스너 등의 [비동기 함수]들이 들어감. 여러 작업이 동시에 실행될 수 있는 공간
  • 태스크 큐 : 비동기 함수들의 Callback 함수들이 들어감 -> 백그라운드의 비동기 함수들의 조건(time-out, click 등)이 충족되었을때, 테스크 큐로 call-back 함수들이 넘어감.

<div id="wrapper"></div>
<script>
  const $wrapper = document.querySelector('#wrapper');
  const total = parseInt(prompt('카드 개수를 짝수로 입력하세요(최대 20).'));
  const colors = [
    'red', 'orange', 'yellow', 'green', 'white',
    'pink', 'cyan', 'violet', 'gray', 'black',
  ];
  let colorSlice = colors.slice(0, total / 2);
  let colorCopy = colorSlice.concat(colorSlice);
  let shuffled = [];
  let clicked = [];
  let completed = [];
  let clickable = false;
  let startTime;



  function shuffle() { // 피셔-예이츠 셔플
    for (let i = 0; colorCopy.length > 0; i += 1) {
      const randomIndex = Math.floor(Math.random() * colorCopy.length);
      shuffled = shuffled.concat(colorCopy.splice(randomIndex, 1));
    }
  }

  function createCard(i) { // div.card > div.card-inner > (div.card-front + div.card-back)
    const card = document.createElement('div');
    card.className = 'card'; // .card 태그 생성
    const cardInner = document.createElement('div');
    cardInner.className = 'card-inner'; // .card-inner 태그 생성
    const cardFront = document.createElement('div');
    cardFront.className = 'card-front'; // .card-front 태그 생성
    const cardBack = document.createElement('div');
    cardBack.className = 'card-back'; // .card-back 태그 생성
    cardBack.style.backgroundColor = shuffled[i];
    cardInner.appendChild(cardFront);
    cardInner.appendChild(cardBack);
    card.appendChild(cardInner);
    return card;
  }

  function onClickCard() {
    if(!clickable || completed.includes(this) || clicked[0] === this) {
      return;
    }
    this.classList.toggle('flipped');
    clicked.push(this);
    if(clicked.length !== 2) {
      return;
    }
    const firstBackColor = clicked[0].querySelector('.card-back').style.backgroundColor;
    const secondBackColor = clicked[1].querySelector('.card-back').style.backgroundColor;
    if (firstBackColor === secondBackColor) {
      completed.push(clicked[0]);
      completed.push(clicked[1]);
      clicked = [];
      if(completed.length !== total) {
        return;
      }
      const endTime = new Date();
      setTimeout(() => {
        alert(`축하합니다! ${(endTime - startTime) / 1000}초 걸렸습니다.`)
        resetGame();
      },500)
      return;
    }
    clickable = false;
    setTimeout(() => {
      clicked[0].classList.remove('flipped');
      clicked[1].classList.remove('flipped');
      clicked = [];
      clickable = true;
    },500)
  }

  function startGame() {
    clickable = false;
    shuffle();
    for(let i = 0; i < total; i +=1) {
      const card = createCard(i);
      card.addEventListener('click', onClickCard);
      $wrapper.append(card)
    }

    document.querySelectorAll('.card').forEach((card, index) => { // 초반 카드 공개
      setTimeout(() => {
        card.classList.add('flipped');
      }, 1000 + 100 * index);
    });

    setTimeout(() => { // 카드 감추기
      document.querySelectorAll('.card').forEach((card) => {
        card.classList.remove('flipped');
      });
      clickable = true;
      startTime = new Date();
    }, 5000);
  }
  startGame();

function resetGame() {
  $wrapper.innerHTML = '';
  colorCopy = colorSlice.concat(colorSlice);
  shuffled = [];
  completed = [];
  startGame();
}


</script>
profile
babypig

0개의 댓글