Published
Edited
May 18, 2020
1 star
Insert cell
Insert cell
doc = html`
<div>
<div id="0" class="cell">${mkStack(3)}</div>
<div id="1" class="cell"></div>
<div id="2" class="cell"></div>
</div>
`
Insert cell
doc.querySelectorAll("button").forEach( b => b.onclick = handler )
Insert cell
Insert cell
handler = e => {
const i = Number(e.target.parentNode.id) // 지금 칸 인덱스 i
const m = btnSize(e.target) // 클릭한 버튼의 크기
if ( minSizeAt(i) < m ) { return } // 제일 작은 버튼이 아니면 그냥 끝냄 (이동 불가)
const i1 = nextIndex(i) // 다음 칸 인덱스 i1
const i2 = nextIndex(i1) // 다음다음 칸 인덱스 i2
const m1 = minSizeAt(i1) // 다음 칸의 가장 작은 버튼 크기 (비었으면 무지 큰 값)
const m2 = minSizeAt(i2) // 다음다음 칸의 가장 작은 버튼 크기 (비었으면 무지 큰 값)
if (m<m1) { // 다음 칸으로 옮겼을 때 가장 작은 크기임을 확인
doc.children[i1].prepend(e.target) // 다음 칸으로 이동시키고
return // 끝냄
}
if (m<m2) { // 다음다음 칸으로 옮겼을 때 가장 작은 크기임을 확인
doc.children[i2].prepend(e.target) // 다음다음 칸으로 이동시키고
return // 끝냄
}
}

// 주석은 제가 달아 놓은 겁니다
/* // 첫번째 제출답안 - 기본적으로 제가 작성한 답과 비슷한 로직
// 현재 칸에서 가장 작은 버튼인지를 if...와 else... 각각의 경우에 나누어 확인하는 것만 다름
handler = e => {
const i = Number(e.target.parentNode.id)
const i1 = nextIndex(i)
const i2 = nextIndex(i1)
const a = e.target.textContent.length

if (a < minSizeAt(i1) && minSizeAt(i) == a) {
doc.children[i1].prepend(e.target);
} else if(a < minSizeAt(i2) && minSizeAt(i) == a) {
doc.children[i2].prepend(e.target);
}
}
*/

/* // 두번째 제출답안 - 버튼 개수가 3개가 아닐 때 뿐만 아니라 칸의 개수가 3개가 아닐 경우까지 동작하는
// 문제 요구조건보다 더 일반적으로 동작하도록 제출된 좀 멋진 답안
handler = e => {
const i = Number(e.target.parentNode.id) // 지금 칸 인덱스 i
const s = Number(e.target.textContent.length) // 클릭된 버튼의 크기
const h = minSizeAt(i) // 현재 칸의 가장 작은 버튼 크기
if(s!=h){return;} // 가장 작은 버튼이 아니면 이동 불가이므로 끝냄

function findIndex(m) { // 재귀함수로 칸이 몇개이든 동작하도록 함 (참고: 반복문으로도 같은 기능 구현 가능)
const i1 = nextIndex(m) // 다음 칸에서도
if (minSizeAt(i1)>=h) return i1; // 크기가 가장 작으면 다음 칸 인덱스 i1 리턴
return findIndex((m+1) % 3); // 아니면 i1의 다음 칸을 시도 (이러다 원래 칸으로 돌아오면 어차피 그냥 거기가 거기)
}

doc.children[findIndex(i)].prepend(e.target)
}
*/
Insert cell
nextIndex = n => (n+1) % 3
Insert cell
minSizeAt = i => { // i번 칸에서 가장 작은 버튼의 사이즈 (없으면 MAX_SAFE_INTEGER)
let m = Number.MAX_SAFE_INTEGER
doc.children[i].querySelectorAll("button").forEach( b => m = Math.min(m,btnSize(b)) )
return m
}
Insert cell
btnSize = b => b.textContent.length // 버튼의 사이즈는 안에 적힌 M의 개수
Insert cell
mkStack = n => Array.from(Array(n).keys()).map( i => mkBtnM(i+1) ).join("")
Insert cell
mkBtnM = n => `<button style="display: block">${Array(n).fill("M").join("")}</button>`
Insert cell
style = html`
<style>
.cell { display: table-cell; vertical-align: bottom; width: 150px; height: 100px;
padding: 3px; border: 1px solid gray; }
</style>`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more