자바스크립트 카드 짝맞추기

banhogu·2023년 5월 25일
0
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>짝맞추기</title>
  <style>
    #wrapper {
      max-width: 400px;
    }

    .card {
      display: inline-block;
      margin-right: 20px;
      margin-bottom: 20px;
      width: 70px;
      height: 100px;
      perspective: 140px;
    }

    .card-inner {
      position: relative;
      width: 100%;
      height: 100%;
      text-align: center;
      transition: transform 0.8s;
      transform-style: preserve-3d;
    }

    .card.flipped .card-inner {
      transform: rotateY(180deg);
    }

    .card-front {
      background: navy;
    }

    .card-front,
    .card-back {
      position: absolute;
      width: 100%;
      height: 100%;
      border: 1px solid black;
      backface-visibility: hidden;
    }

    .card-back {
      transform: rotateY(180deg);
    }
  </style>
</head>

<body>
  <div id="wrapper"></div>
  <script>
    let $wrapper = document.querySelector('#wrapper')
    let total = 12
    let colors = ['red', 'orange', 'yellow', 'green', 'white', 'pink']
    let colorcopy = colors.concat(colors)
    let shuffled = []
    let clicked = []
    let completed = []
    let clickable = false
    let starttime
    let endtime

    function shuffle() {
      while (colorcopy.length > 0) {
        let index = Math.floor(Math.random() * colorcopy.length)
        shuffled = shuffled.concat(colorcopy.splice(index, 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 reset() {
      $wrapper.innerHTML = ''
      let colorcopy = colors.concat(colors)
      let shuffled = []
      let clicked = []
      let completed = []
      startgame()
    }

    function clickcard() {
      if(!clickable || completed.includes(this.querySelector('.card-back').style.backgroundColor) || clicked[0]===this){
        return
      }
      
      this.classList.toggle('flipped')
      clicked.push(this)
      if (clicked.length !== 2) {
        return
      }
      let color1 = clicked[0].querySelector('.card-back').style.backgroundColor
      let color2 = clicked[1].querySelector('.card-back').style.backgroundColor
      clickable = false;
      
      if (color1 === color2) {
        completed.push(color1)
        completed.push(color2)
        clicked = []
        clickable = true
        if (completed.length !== total) {
          return
        }
        endtime = new Date()

        setTimeout(() => {
          alert(`축하합니다 ${(endtime - starttime)/1000}초 걸렸습니다.`)
          reset()
          
        }, 1000);
        return;

      }
      setTimeout(() => {
        clicked[0].classList.remove('flipped')
        clicked[1].classList.remove('flipped')
        clicked = []
        clickable = true
        return
      }, 1000);

    }

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

      document.querySelectorAll('.card').forEach((el, idx) => {
        setTimeout(() => {
          el.classList.add('flipped')
        }, 1000 + 100 * idx);
      })

      setTimeout(() => {
        document.querySelectorAll('.card').forEach((el) => {
          el.classList.remove('flipped')
        })
        clickable = true;
        starttime = new Date()
      }, 3000);
    }

    startgame()


  </script>
</body>

</html>

피셔 예이츠 셔플을 이용하여 카드 색을 섞고 반복문으로 각각의 카드 뒷면에 색을 추가하여 사용자가 카드 2장을 뒤집을 때 같은면 놔두고 다르면 다시 뒤집는 방식이다. 빠르게 3-4장 클릭하면 뒤에 1-2장 카드가 그대로 남아지는 버그가 있었는데, 자바스크립트 이벤트루프 문제였다. 1,2,3,4 카드가 모두 settimeout에 걸렸기 때문이다. 그래서 중간에 2장을 뒤집었을때 강제로 플래기변수 clickable을 사용해 버그를 막았다. 찾아보니 자바스크립트에서 이벤트 루프 문제는 꼭 알아야 할 개념이므로 추가로 더 공부해서 포스팅해야겠다.

profile
@banhogu

0개의 댓글