본문 바로가기
개발/Javascript

[js] 자바스크립트로 카드 뒤집기 게임 구현하기(카드 세팅 ver.2)

by 코딩하는 갓디노 2021. 2. 16.

카드뒤집기 게임

 

자바스크립트를 이용하여,
카드 뒤집기 게임을 구현하는 예제(ver.2)입니다.
- 기능 구현, 초기화 -



 

예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다.

구현 내용

1 카드 2개씩만 오픈하도록 설정  
2 카드끼리 색깔이 같은지 다른지 체크  
3 같을 경우, 카드 계속 오픈 클릭 방지
4 틀릴 경우, 1초 후 카드 닫기 클릭 방지
5 클릭한 카드의 색깔이 같을 경우, 클릭한 카드를 완성 카드에 넣어줌  
6 완성 카드가 모두 오픈 되었을 경우, 성공 메시지 출력 타이머
7 초기화 피츠예이츠 셔플 함수로 설정, 백업변수

 

구현 화면(성공 후)

카드 뒤집기 게임

 

html 코드

<!--  초기화 위해 전체 감싸는 태그 필요-->
<div id="wrapper"></div>

 

script 전체 코드

const x = 4;
const y = 3;
//카드 뒤 색깔 7개 2개씩 미리 설정
let backColor = ['#FFC312', '#FFC312', '#C4E538', '#C4E538', '#12CBC4', '#12CBC4', 
'#ED4C67', '#ED4C67', '#FDA7DF', '#FDA7DF', '#833471', '#833471'];
let colors = backColor.slice(); //백업 복사
//클릭 flag: 카드 세팅하는 동안에 클릭 기능 방지(flag가 true일 경우에만 클릭 가능)
let clickFlag = true;
//카드 오픈은 2개씩 가능, 카드끼리 색깔이 같은지 다른지 판단
let clickedOne = [];
//카드 2개 매치했을 경우, 클릭 방지를 위해
let completedOne = [];
let start; //시작시간

//위의 색깔 랜덤 섞기 - 피셔예이츠 방식
let chosenColor = [];

function shuffle() {
  while (colors.length > 0) {
    let color = Math.floor(Math.random() * colors.length);
    let mixedColor = colors.splice(color, 1)[0];
    chosenColor.push(mixedColor);
  }
  console.log(chosenColor);
}

function cardSetting(x, y) {
  clickFlag = false;
  //카드 세팅
  for (let i = 0; i < x * y; i++) {
    const card = document.createElement('div');
    card.className = 'card';
    const cardInner = document.createElement('div');
    cardInner.className = 'card-inner';
    const cardFront = document.createElement('div');
    cardFront.className = 'card-front';
    const cardBack = document.createElement('div');
    cardBack.className = 'card-back';
    cardBack.style.backgroundColor = chosenColor[i];
    cardInner.appendChild(cardFront);
    cardInner.appendChild(cardBack);
    card.appendChild(cardInner);
    document.querySelector('#wrapper').appendChild(card);

    //클릭하여 카드 뒤집기
    card.addEventListener('click', function() {
      if (clickFlag && !completedOne.includes(card)) { //clickFlag가 true, 매치 안된 카드일 경우,
        card.classList.toggle('flipped');
        clickedOne.push(card); //선택한 카드 배열에 추가
        if (clickedOne.length == 2) { //선택한 카드가 2개일때
          //색깔이 같으면 계속 오픈 시킴
          if (clickedOne[0].querySelector('.card-back').style.backgroundColor ===
            clickedOne[1].querySelector('.card-back').style.backgroundColor) {
            console.log('matched!');
            completedOne.push(clickedOne[0]); //매치된 카드를 완성카드로 넣기
            completedOne.push(clickedOne[1]);
            clickedOne = [] //초기화
            if (completedOne.length === x * y) { //모두 매치했을 경우 성공 메시지
              let end = new Date(); //끝시간 재기
              const result = document.createElement('div');
              result.innerHTML = '축하합니다.' +(end-start)/1000 + '초 걸렸습니다.';
              result.style.fontSize = '20px';
              document.body.appendChild(result);
              setTimeout(() => {
                result.innerHTML = '';
              }, 1000);

              document.querySelector('#wrapper').innerHTML = ''; //전체 초기화
              completedOne = [];
              clickedOne = [];
              start;
              chosenColor = [];
              colors = backColor.slice();
              shuffle();
              cardSetting(x, y);
            }
          } else { //색깔이 다르면 1초 후 카드 닫기
            clickFlag = false; //미리 클릭 방지
            setTimeout(
              () => {
                clickedOne[0].classList.remove('flipped');
                clickedOne[1].classList.remove('flipped');
                clickFlag = true;
                clickedOne = [] //초기화
              }, 1000
            );
          }
        }
      }
    });

    //카드 세팅되면 몇초 보여주기(*카드 index별 시간차를 주고 오픈)
    document.querySelectorAll('.card').forEach((ele, index) =>
      setTimeout(() => {
        ele.classList.add('flipped')
      }, 1000 + 100 * index)
    );
    //5초뒤에 닫기
    setTimeout(() => {
      document.querySelectorAll('.card').forEach((ele) => ele.classList.remove('flipped'));
      clickFlag = true;
      start = new Date(); //시작시간 재기
    }, 3000);
  }
}

shuffle();
cardSetting(x, y);



 

초기화를 위한 백업 변수의 사용

· 피셔 예이츠 셔플을 shuffle 함수로 설정
· 백업 변수를 이용하여 색깔들을 넣어주고, 피셔 예이츠 셔플의 기존 변수에서 백업 변수로 변경

before

const backColor = ['#FFC312', '#FFC312', '#C4E538',
  '#C4E538', '#12CBC4', '#12CBC4', '#ED4C67', '#ED4C67',
  '#FDA7DF', '#FDA7DF', '#833471', '#833471'
]

//위의 색깔 랜덤 섞기 - 피셔 예이츠 방식
let chosenColor = [];

while (backColor.length > 0) {
  let color = Math.floor(Math.random() * backColor.length); //0-13까지 정수
  let mixedColor = backColor.splice(color, 1)[0];
  chosenColor.push(mixedColor);
}

 

after

let backColor = ['#FFC312', '#FFC312', '#C4E538', '#C4E538', '#12CBC4', 
'#12CBC4', '#ED4C67', '#ED4C67', '#FDA7DF', '#FDA7DF', '#833471', '#833471'];
let colors = backColor.slice(); //백업 복사
let chosenColor = [];

//backColor => colors로 모두 변경
function shuffle() {
  while (colors.length > 0) {
    let color = Math.floor(Math.random() * colors.length);
    let mixedColor = colors.splice(color, 1)[0];
    chosenColor.push(mixedColor);
  }
}

 

문제점

splice로 인하여 기존 변수의 배열 값이 0이 됨에 따라 백업 변수도 0이 되어(참조),
다음 게임 진행시, 빈 카드로 출력됨

 

해결: 복사(깊은 복사), 참조(얕은 복사) 

변수.slice()를 이용하여 깊은 복사로 처리

 

화면 결과

반응형

댓글