Skip to content

Instantly share code, notes, and snippets.

@slacktracer
Created November 13, 2021 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slacktracer/13f57974c1fc319e2913d36a03f5c74d to your computer and use it in GitHub Desktop.
Save slacktracer/13f57974c1fc319e2913d36a03f5c74d to your computer and use it in GitHub Desktop.
Infectio — a puzzle game #codevember
<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>

Infectio — a puzzle game #codevember

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.

A Pen by Jase on CodePen.

License.

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" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment