Last active
February 17, 2019 15:40
-
-
Save yunseop-kim/7f7c6d25d8a8496f5c28e4e4241d2ea7 to your computer and use it in GitHub Desktop.
codespitz-s80-01
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Summer's Tower</title> | |
</head> | |
<body> | |
<style> | |
@keyframes blink { | |
50% { | |
opacity: 0.7; | |
} | |
} | |
.blink { | |
animation: blink 1s linear infinite; | |
} | |
table { | |
border-collapse: collapse; | |
margin: 30px auto 0 | |
} | |
td { | |
background-size: contain; | |
background-position: center; | |
background-repeat: no-repeat; | |
user-select: none; | |
touch-callout: none | |
} | |
</style> | |
<section style="text-align:center"> | |
<h1 style="color:#208AFB">BSIDE TOWER JAM</h1> | |
<table id="stage"></table> | |
</section> | |
<script> | |
'use strict'; | |
const Game = (() => { | |
const Block = class { | |
static GET(type = parseInt(Math.random() * 5)) { return new Block(type); } | |
constructor(type) { | |
this._type = type; | |
} | |
get image() { return `url('http://www.bsidesoft.com/summer/project/07_tower/img/block${this._type}.png')`; } | |
get type() { return this._type; } | |
} | |
const column = 8, row = 8, blockSize = 80; | |
const data = []; | |
let table; | |
let startBlock, currBlock, isDown; | |
const selected = []; | |
const getBlock = (x, y) => { | |
const { top: T, left: L } = table.getBoundingClientRect(); | |
if (x < L || x > (L + blockSize * row) || y < T || y > (T + blockSize * column)) return null; | |
return data[parseInt((y - T) / blockSize)][parseInt((x - L) / blockSize)]; | |
}; | |
const isNext = curr => { | |
let r0, c0, r1, c1, cnt = 0; | |
data.some((row, i) => { | |
let j; | |
if ((j = row.indexOf(currBlock)) != -1) r0 = i, c0 = j, cnt++; | |
if ((j = row.indexOf(curr)) != -1) r1 = i, c1 = j, cnt++; | |
return cnt == 2; | |
}); | |
return curr != currBlock && Math.abs(r0 - r1) == 1 || Math.abs(c0 - c1) == 1; | |
}; | |
const reset = _ => { | |
startBlock = currBlock = null; | |
selected.length = 0; | |
isDown = false; | |
render(); | |
}; | |
const remove = _ => { | |
data.forEach(r => { //데이터삭제 | |
selected.forEach(v => { | |
let i; | |
if ((i = r.indexOf(v)) != -1) r[i] = null; | |
}); | |
}); | |
render(); | |
setTimeout(drop, 300); | |
}; | |
const drop = _ => { | |
let isNext = false; | |
for (let j = 0; j < column; j++) { | |
for (let i = row - 1; i > -1; i--) { | |
if (!data[i][j] && i) { | |
let k = i, isEmpty = true; | |
while (k--) if (data[k][j]) { | |
isEmpty = false; | |
break; | |
} | |
if (isEmpty) break; | |
isNext = true; | |
while (i--) { | |
data[i + 1][j] = data[i][j]; | |
data[i][j] = null; | |
} | |
break; | |
} | |
} | |
} | |
render(); | |
isNext ? setTimeout(drop, 300) : readyToFill(); | |
}; | |
const fills = []; | |
let fillCnt = 0; | |
const readyToFill = _ => { | |
fills.length = 0; | |
data.some(row => { | |
if (row.indexOf(null) == -1) return true; | |
const r = [...row].fill(null); | |
fills.push(r); | |
row.forEach((v, i) => !v && (r[i] = Block.GET())); | |
}); | |
fillCnt = 0; | |
setTimeout(fill, 300); | |
}; | |
const fill = _ => { | |
if (fillCnt > fills.length) { | |
isDown = false; | |
return; | |
} | |
for (let i = 0; i < fillCnt; i++) { | |
fills[fills.length - i - 1].forEach((v, j) => { | |
if (v) data[fillCnt - i - 1][j] = v; | |
}); | |
} | |
fillCnt++; | |
render(); | |
setTimeout(fill, 300); | |
}; | |
const down = ({ pageX: x, pageY: y }) => { | |
if (isDown) return; | |
const curr = getBlock(x, y); | |
if (!curr) return; | |
isDown = true; | |
selected.length = 0; | |
selected[0] = startBlock = currBlock = curr; | |
render(); | |
}; | |
const move = ({ pageX: x, pageY: y }) => { | |
if (!isDown) return; | |
const curr = getBlock(x, y); | |
if (!curr || curr.type != startBlock.type || !isNext(curr)) return; | |
if (selected.indexOf(curr) == -1) selected.push(curr); | |
else if (selected[selected.length - 2] == curr) selected.pop(); | |
currBlock = curr; | |
render(); | |
}; | |
const up = _ => selected.length > 2 ? remove() : reset(); | |
const el = tag => document.createElement(tag) | |
const cellStyle = block => ` | |
${block ? `background:${block.image};` : ""} | |
${selected.includes(block) ? "background-color: yellow;" : ""} | |
width:${blockSize}px; | |
height:${blockSize}px; | |
cursor:pointer;`; | |
const render = _ => { | |
if (table.innerHTML === '') { | |
data.forEach(row => table.appendChild(row.reduce((tr, block) => { | |
tr.appendChild(el('td')).style.cssText = cellStyle(block); | |
return tr; | |
}, el('tr')))); | |
} else { | |
data.forEach((row, i) => { | |
const tr = table.childNodes[i]; | |
tr.childNodes.forEach((td, j) => { | |
const block = row[j]; | |
td.style.cssText = cellStyle(block); | |
}) | |
}) | |
} | |
}; | |
return tid => { | |
table = document.querySelector(tid); | |
for (let i = 0; i < row; i++) { | |
const r = []; | |
data.push(r); | |
for (let j = 0; j < column; j++) r[j] = Block.GET(); | |
} | |
table.addEventListener('mousedown', down); | |
table.addEventListener('mouseup', up); | |
table.addEventListener('mouseleave', up); | |
table.addEventListener('mousemove', move); | |
render(); | |
}; | |
})(); | |
Game('#stage'); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment