Created
February 17, 2019 16:09
-
-
Save jinhoyim/05ca6b8372ec576d3810285b2e66dbb7 to your computer and use it in GitHub Desktop.
한 붓 그리기 S80-Day1
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 lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> | |
<title>Document</title> | |
<style> | |
.block { | |
width: 80px; | |
height: 80px; | |
cursor: pointer; | |
} | |
.block-type0 { | |
background-image: url("img/0.png"); | |
} | |
.block-type1 { | |
background-image: url("img/1.png"); | |
} | |
.block-type2 { | |
background-image: url("img/2.png"); | |
} | |
.block-type3 { | |
background-image: url("img/3.png"); | |
} | |
.block-type4 { | |
background-image: url("img/4.png"); | |
} | |
.block-selected { | |
background-color: #ffff00; | |
} | |
</style> | |
</head> | |
<body> | |
<section style="text-align:center"> | |
<h1 style="color:#208AFB">한 붓 그리기</h1> | |
<table id="stage"></table> | |
</section> | |
<script> | |
"use strict"; | |
const Block = class { | |
constructor(type) { | |
this._type = type; | |
this._isDown = false; | |
} | |
static get numberOfTypes() { | |
return 5; | |
} | |
// css 클래스 목록 출력 | |
get classList() { | |
const classes = ["block", `block-type${this.type}`]; | |
if (this._isDown) classes.push("block-selected"); | |
return classes; | |
} | |
get type() { | |
return this._type; | |
} | |
down() { | |
this._isDown = true; | |
} | |
up() { | |
this._isDown = false; | |
} | |
}; | |
Block.GET = (type = parseInt(Math.random() * Block.numberOfTypes)) => new Block(type); | |
const Game = (_ => { | |
const column = 8, | |
row = 8, | |
blockSize = 80; | |
const data = []; | |
let table; | |
let startBlock, | |
currBlock, | |
selected = [], | |
isDown; | |
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 down = ({ pageX: x, pageY: y }) => { | |
if (isDown) return; | |
const curr = getBlock(x, y); | |
if (!curr) return; | |
isDown = true; | |
curr.down(); | |
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); | |
curr.down(); | |
} else if (selected[selected.length - 2] == curr) { | |
selected.pop().up(); | |
} | |
currBlock = curr; | |
render(); | |
}; | |
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 up = _ => (selected.length > 2 ? remove() : reset()); | |
const reset = _ => { | |
startBlock = currBlock = null; | |
selected.forEach(b => b.up()); | |
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 init = 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); | |
buildTable(); | |
render(); | |
}; | |
const el = tag => document.createElement(tag); | |
const buildTable = _ => { | |
table.innerHTML = ""; | |
data.forEach(row => | |
table.appendChild( | |
row.reduce((tr, block) => { | |
tr.appendChild(el("td")); | |
return tr; | |
}, el("tr")) | |
) | |
); | |
}; | |
const render = _ => { | |
let td; | |
data.forEach((row, rowIndex) => { | |
row.forEach((block, colIndex) => { | |
td = table.rows[rowIndex].cells[colIndex]; | |
td.className = ""; | |
if (block) { | |
td.classList.add(...block.classList); | |
} | |
}); | |
}); | |
}; | |
return init; | |
})(); | |
Game("#stage"); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment