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" /> |