<!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을 사용해 버그를 막았다. 찾아보니 자바스크립트에서 이벤트 루프 문제는 꼭 알아야 할 개념이므로 추가로 더 공부해서 포스팅해야겠다.