<html>
<head>
<meta charset="UTF-8">
<title>2048</title>
<style>
#table {
border-collapse: collapse;
user-select: none;
}
#table td {
border: 10px solid #bbada0;
width: 116px;
height: 128px;
font-size: 50px;
font-weight: bold;
text-align: center;
}
#score {
user-select: none;
}
.color-2 {
background-color: #eee4da;
color: #776e65;
}
.color-4 {
background-color: #eee1c9;
color: #776e65;
}
.color-8 {
background-color: #f3b27a;
color: 'white';
}
.color-16 {
background-color: #f69664;
color: 'white';
}
.color-32 {
background-color: #f77c5f;
color: 'white';
}
.color-64 {
background-color: #f75f3b;
color: 'white';
}
.color-128 {
background-color: #edd073;
color: #776e65;
}
.color-256 {
background-color: #edcc62;
color: #776e65;
}
.color-512 {
background-color: #edc950;
color: #776e65;
}
.color-1024 {
background-color: #edc53f;
color: #776e65;
}
.color-2048 {
background-color: #edc22e;
color: #776e65;
}
</style>
</head>
<body>
<table id="table"></table>
<div><button>되돌리기</button></div>
<script>
const $table = document.getElementById('table');
let $button = document.querySelector('button')
let data = [];
let startCoord;
let history = []
function random2cell() {
let empty = []
data.forEach((rowel, idx) => {
rowel.forEach((cellel, jdx) => {
if (!cellel) {
empty.push([idx, jdx])
}
})
})
let random = empty[Math.floor(Math.random() * empty.length)]
data[random[0]][random[1]] = 2
}
function drawcell() {
data.forEach((rowel, i) => {
rowel.forEach((cellel, j) => {
let target = $table.children[i].children[j]
if (cellel > 0) {
target.textContent = cellel
target.className = 'color-' + cellel
}
else {
target.textContent = ''
target.className = ''
}
})
})
}
function startGame() {
for (let i = 0; i < 4; i++) {
let $tr = document.createElement('tr')
let rowdata = []
for (let j = 0; j < 4; j++) {
let $td = document.createElement('td')
$tr.append($td)
rowdata.push(0)
}
data.push(rowdata)
$table.append($tr)
}
random2cell()
drawcell()
}
$button.addEventListener('click',()=>{
let predata = history.pop()
if(!predata){
return
}
data = predata
drawcell()
})
function clear() {
data = []
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
$table.innerHTML = ''
}
}
startGame()
}
window.addEventListener('keyup', (event) => {
if (event.key === 'ArrowUp') {
moveCells('up');
} else if (event.key === 'ArrowDown') {
moveCells('down');
} else if (event.key === 'ArrowLeft') {
moveCells('left');
} else if (event.key === 'ArrowRight') {
moveCells('right');
}
});
function moveCells(direction) {
let historydata = JSON.parse(JSON.stringify(data))
history.push(historydata)
switch (direction) {
case 'left': {
let newdata = [[], [], [], []]
data.forEach((rowdata, i) => {
rowdata.forEach((celldata, j) => {
if (celldata) {
let currentrow = newdata[i]
let preventcell = currentrow[currentrow.length - 1]
if (preventcell === celldata) {
currentrow[currentrow.length - 1] *= -2
}
else {
newdata[i].push(celldata)
}
}
})
});
[1, 2, 3, 4].forEach((rowel, i) => {
[1, 2, 3, 4].forEach((cellel, j) => {
data[i][j] = Math.abs(newdata[i][j]) || 0;
})
})
break;
}
case 'right': {
let newdata = [[], [], [], []]
data.forEach((rowdata, i) => {
rowdata.forEach((celldata, j) => {
if (rowdata[3 - j]) {
let currentrow = newdata[i]
let preventcell = currentrow[currentrow.length - 1]
if (preventcell === rowdata[3 - j]) {
currentrow[currentrow.length - 1] *= -2
}
else {
newdata[i].push(rowdata[3 - j])
}
}
})
});
[1, 2, 3, 4].forEach((rowel, i) => {
[1, 2, 3, 4].forEach((cellel, j) => {
data[i][3 - j] = Math.abs(newdata[i][j]) || 0;
})
})
break;
}
case 'up': {
let newdata = [[], [], [], []]
data.forEach((rowdata, i) => {
rowdata.forEach((celldata, j) => {
if (celldata) {
let currentrow = newdata[j]
let preventcell = currentrow[currentrow.length - 1]
if (preventcell === celldata) {
currentrow[currentrow.length - 1] *= -2
}
else {
newdata[j].push(celldata)
}
}
})
});
[1, 2, 3, 4].forEach((rowel, i) => {
[1, 2, 3, 4].forEach((cellel, j) => {
data[j][i] = Math.abs(newdata[i][j]) || 0;
})
})
break;
}
case 'down': {
const newData = [[], [], [], []];
data.forEach((rowData, i) => {
rowData.forEach((cellData, j) => {
if (data[3 - i][j]) {
const currentRow = newData[j];
const prevData = currentRow[currentRow.length - 1];
if (prevData === data[3 - i][j]) {
currentRow[currentRow.length - 1] *= -2;
} else {
newData[j].push(data[3 - i][j]);
}
}
});
});
console.log(newData);
[1, 2, 3, 4].forEach((cellData, i) => {
[1, 2, 3, 4].forEach((rowData, j) => {
data[3 - j][i] = Math.abs(newData[i][j]) || 0;
});
});
break;
}
}
if (data.flat().includes(2048)) {
drawcell()
setTimeout(() => {
alert('축하합니다 승리했습니다')
}, 50);
setTimeout(() => {
clear()
}, 1000);
}
else if (!data.flat().includes(0)) {
setTimeout(() => {
alert('게임오버')
}, 50);
setTimeout(() => {
clear()
}, 1000);
}
else {
random2cell()
drawcell()
}
}
window.addEventListener('mousedown', (event) => {
startCoord = [event.clientX, event.clientY];
});
window.addEventListener('mouseup', (event) => {
const endCoord = [event.clientX, event.clientY];
const diffX = endCoord[0] - startCoord[0];
const diffY = endCoord[1] - startCoord[1];
if (diffX < 0 && Math.abs(diffX) > Math.abs(diffY)) {
moveCells('left');
} else if (diffX > 0 && Math.abs(diffX) > Math.abs(diffY)) {
moveCells('right');
} else if (diffY > 0 && Math.abs(diffX) <= Math.abs(diffY)) {
moveCells('down');
} else if (diffY < 0 && Math.abs(diffX) <= Math.abs(diffY)) {
moveCells('up');
}
});
startGame()
</script>
</body>
</html>
키보드나 마우스에 이벤트를 걸고 위아래좌우로 움직이면서 숫자를 쌓아 2048을 만드는 게임이다. 테이블에 tr,td를 그리고 그에 맞게 data를 맞춰주고, 이벤트 동작에 맞게 숫자를 더해간다. 이벤트 발생 시 랜덤으로 2를 추가해주는 함수를 넣어줬다.
up과 down 이벤트가 많이 어려웠는데 a4에 임의 데이터를 써가며 로직을 이해하며 코드를 작성했다.