Happy Last Day of #Codevember! Use the color controls to absorb nearby tiles — can you fill the whole board before running out of moves?
Based on a pen by @oboskeboo.
<main> | |
<controls> | |
<div class="new-game">New Game</div> | |
<div>Moves <span class="moves">0</span> / <span class="max-moves">30</span></div> | |
</controls> | |
<board></board> | |
<colors></colors> | |
<controls> | |
<div>Skill <span class="skill">0</span></div> | |
<div><input type="range" class="level" value="10" min="3" max="10" /></div> | |
</controls> | |
<game-over></game-over> | |
</main> |
Happy Last Day of #Codevember! Use the color controls to absorb nearby tiles — can you fill the whole board before running out of moves?
Based on a pen by @oboskeboo.
const $board = document.querySelector('board') | |
const $palette = document.querySelector('colors') | |
const $gameover = document.querySelector('game-over') | |
const $tally = document.querySelector('.moves') | |
const $cap = document.querySelector('.max-moves') | |
const $level = document.querySelector('.level') | |
const $skill = document.querySelector('.skill') | |
const colorArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] | |
let maxMoves = (colors, skill) => { | |
return Math.ceil((colors.length * 3.7 - (skill / 1.5)) / 5) * 5 | |
} | |
let running = false | |
let cell = '-x' | |
let moves = 0 | |
let skill = Math.round(colorArray.length/2) || $level.value | |
let cap = maxMoves(colorArray, skill) | |
let color | |
let shuffle = (a) => { | |
for (let i = a.length; i; i--) { | |
let j = Math.floor(Math.random() * i); | |
[a[i - 1], a[j]] = [a[j], a[i - 1]]; | |
} | |
return a | |
} | |
let setColors = (collection, n) => { | |
return n < 10 ? shuffle(collection).slice(0, n) : collection | |
} | |
let checkWin = (moves, cap) => { | |
let n = 0 | |
let msg = '' | |
if (moves <= cap) { | |
if ($board.childNodes[99].className.indexOf(cell) > -1) { | |
for (let i = 0; i < 100; i++) { | |
if ($board.childNodes[i].className.indexOf(cell) > -1) { | |
n++ | |
} | |
} | |
} | |
if (n === 100) { | |
msg = '<i class="new-game fa fa-smile-o"></i>' | |
skill++ | |
running = false | |
} else if (n < 100 && moves >= cap) { | |
msg = '<i class="new-game fa fa-frown-o"></i>' | |
skill-- | |
running = false | |
} | |
} else { | |
msg = '<i class="new-game fa fa-frown-o"></i>' | |
skill-- | |
running = false | |
} | |
if(!running) { | |
$gameover.innerHTML = msg | |
} | |
skill = skill < 3 ? 3 : (skill > 10 ? 10 : skill) | |
} | |
let checkColor = (color) => { | |
let nodes = $board.childNodes | |
let boo = '' | |
for(let x = 0; x < 100; x++) { | |
if(nodes[x].className.indexOf(cell) > -1) { | |
nodes[x].className = color + cell | |
if (x + 1 < 100 && nodes[x + 1].className === color) { | |
nodes[x + 1].className += cell | |
} | |
if (x + 10 < 100 && nodes[x + 10].className === color) { | |
nodes[x + 10].className += cell | |
} | |
if (x - 1 >= 0 && x % 10 > 0 && nodes[x - 1].className === color) { | |
nodes[x - 1].className += cell | |
} | |
if (x - 10 >= 0 && x % 10 > 0 && nodes[x - 10].className === color) { | |
nodes[x - 10].className += cell | |
} | |
} | |
} | |
} | |
let builder = (container, element, collection, count, randomize) => { | |
container.innerHTML = '' | |
count = count || collection.length | |
randomize = randomize || false | |
for (var i = 0; i < count; i++) { | |
let $child = document.createElement(element) | |
$child.className = randomize ? collection[Math.floor((Math.random() * collection.length))] : collection[i] | |
// $child.style.transitionDelay = Math.floor((Math.random() * 10)) * 100/5 + 'ms' | |
container.appendChild($child) | |
} | |
} | |
let newGame = () => { | |
$level.value = skill | |
$skill.innerText = skill | |
let colors = setColors(colorArray.slice(), skill) | |
moves = 0 | |
cap = maxMoves(colors, skill) | |
$tally.innerText = moves | |
$gameover.innerHTML = '' | |
running = true | |
$cap.innerText = cap | |
builder($palette, 'color', colors) | |
builder($board, 'tile', colors, 100, true) | |
color = $board.childNodes[0].className | |
$board.className = '' | |
$board.childNodes[0].className = color + cell | |
checkColor(color) | |
} | |
let play = (chip) => { | |
if (running && color !== chip){ | |
color = chip | |
if($board.className !== 'started') { | |
$board.className = 'started' | |
} | |
moves++ | |
$tally.innerText = moves | |
checkColor(chip) | |
checkWin(moves, cap) | |
} | |
} | |
document.addEventListener("DOMContentLoaded", () => { | |
newGame() | |
}, false) | |
$level.addEventListener('input', (e) => { | |
skill = e.target.value | |
newGame() | |
}, false) | |
document.addEventListener('click', (e) => { | |
let css = Array.from(e.target.classList) | |
if(e.target.tagName == 'COLOR') { | |
play(e.target.className) | |
} | |
else if(css.includes('new-game')) { | |
newGame() | |
} | |
}) |
@import url('https://fonts.googleapis.com/css?family=Bubblegum+Sans'); | |
/* colors */ | |
.a, .a-x {background: #573659;} | |
.b, .b-x {background: #ad4375;} | |
.c, .c-x {background: #fa7370;} | |
.d, .d-x {background: #f59231;} | |
.e, .e-x {background: #fecd5f;} | |
.f, .f-x {background: #9ccf5e;} | |
.g, .g-x {background: #3cad5b;} | |
.h, .h-x {background: #36cbbf;} | |
.i, .i-x {background: #1d839c;} | |
.j, .j-x {background: #2f506c;} | |
controls { | |
display: flex; | |
justify-content: space-between; | |
padding: 1em 0; | |
} | |
board { | |
display: flex; | |
flex-flow: row wrap; | |
height: 65vmin; | |
width: 65vmin; | |
border: 1ch solid; | |
} | |
tile { | |
flex: 0 1 6.5vmin; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
height: 6.5vmin; | |
transition: background 300ms linear; | |
} | |
board:not(.started) tile:first-of-type::after { | |
content: '\f005'; | |
font-size: 1.1em; | |
} | |
colors { | |
display: flex; | |
justify-content: space-between; | |
margin-top: 1ch; | |
/* border: 1ch solid; */ | |
} | |
color { | |
flex: 0 1 6.5vmin; | |
height: 6.5vmin; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
border-radius: .3em; | |
/* border: 1ch solid; */ | |
} | |
.new-game { | |
cursor: pointer; | |
} | |
main { | |
position: relative; | |
} | |
html, body {height: 100%} | |
html {font-size: 10px} | |
body { | |
margin: 0; | |
font-size: calc(1em + 1vmin); | |
font-family: 'Bubblegum Sans', Helvetica, FontAwesome, sans-serif; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
background: #212429; /*#353539;*/ | |
color: #fffced; | |
} | |
game-over { | |
pointer-events: none; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
font-size: 5em; | |
} | |
.fa { | |
pointer-events: auto; | |
} | |
/* debugging */ | |
/* | |
colors { | |
counter-reset: x; | |
} | |
color::after { | |
counter-increment: x; | |
content: counter(x); | |
content: attr(class); | |
} | |
board { | |
counter-reset: c; | |
} | |
tile::after { | |
counter-increment: c; | |
content: counter(c); | |
content: attr(class); | |
opacity: .4; | |
} | |
*/ |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" /> |