JavaScript-카드맞추기 게임

Jenna·2022년 12월 23일
1

javascript

목록 보기
13/16
post-thumbnail


📌 순서도 그리기



📌 코드보기


<body>
    <div id="wrapper">
    </div>

    <script>
        const $wrapper = document.querySelector('#wrapper');
        const $btn = document.querySelector('#btn');
        const total = 12;
        const colors = ['url(/img/1.jpeg) no-repeat center / cover', 'url(/img/2.jpeg) no-repeat center / cover', 'url(/img/3.jpeg) no-repeat center / cover', 'url(/img/4.jpeg) no-repeat center / cover', 'url(/img/5.jpeg) no-repeat center / cover', 'url(/img/6.jpeg) no-repeat center / cover'];
        let colorSlice = colors.slice(0, total / 2);
        let colorCopy = colorSlice.concat(colorSlice);
        let shuffled = [];
        let completed = [];
        let clicked = [];
        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.background = 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.background;
            const secondBackColor = clicked[1].querySelector('.card-back').style.background;
            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();
                }, 1000);

                return;
            }
            clickable = false; //4번클릭하면 2개 남는 버그 수정 
            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.appendChild(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 = colors.concat(colors);
            shuffled = [];
            completed = [];
            startGame();
        }
    </script>
</body>

📌 코드 공부하기


이벤트 루프

JavaScript의 런타임 모델은 코드의 실행, 이벤트의 수집과 처리, 큐에 대기 중인 하위 작업을 처리하는 이벤트 루프에 기반
위 예제를 실행하며 카드를 연속 4번 클릭했을때 두장의 카드가 같지 않음에도 불구하고 앞면인 상태로 유지되는 버그가 발생하였었다.
이는 이벤트루프때문에 발생한 버그로 기존코드를 아래와 같이 수정하였다.


기존코드


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.background;
            const secondBackColor = clicked[1].querySelector('.card-back').style.background;
            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();
                }, 1000);

                return;
            }
           

수정된 코드


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.background;
            const secondBackColor = clicked[1].querySelector('.card-back').style.background;
            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();
                }, 1000);

                return;
            }
            clickable = false; //4번클릭하면 2개 남는 버그 수정 
            setTimeout(() => {
                clicked[0].classList.remove('flipped');
                clicked[1].classList.remove('flipped');
                clicked = [];
                clickable = true;
            }, 500);
        }

clickable = false; 를 넣어줌으로써 2번 클릭한 후에는 다른 카드를 클릭할 수 없게 막아준다.

업로드중..

이벤트 루프를 참고하여 버그를 해결할 수 있다.

profile
connecting the dots 💫

0개의 댓글