<div id='top-bar' class='top-bar bar'>
<a href='#' id='sz-decr' class='ctrl sz-ctrl'>-</a>
<span id='sz-lbl' class='lbl-area'>5</span>
<a href='#' id='sz-incr' class='ctrl sz-ctrl'>+</a>
<a href='#' id='gen' class='ctrl big-btn'>Generate New</a>
</div>
<div id='game-area' class='game-area bar'>
<div id='settings-bar' class='bar'>
<ul id='next' class='next bar bar-comp'></ul>
<span id='free' class='free lbl-area bar-comp'>
Free cells:
</span>
<span id='pts' class='pts lbl-area bar-comp'>
Score:
</span>
</div>
<div id='grid' class='grid bar gridcomp'></div>
<div>
<a href='#' id='start' class='ctrl big-btn start'>Start!</a>
</div>
</div>
html {
font: 85%/1.5 Helvetica, sans-serif;
}
.top-bar {
background: palegreen;
}
.bar, .ctrl {
box-shadow: 1px 1px 3px;
text-align: center;
}
.bar:not(.next) {
margin: .75em auto;
padding: .25em .5em;
}
.ctrl, .lbl-area, .next, .next *, .gridcomp:not(.gridrow) {
display: inline-block;
vertical-align: middle;
}
.ctrl {
position: relative;
height: 1.5em;
background:
linear-gradient(palegreen, lawngreen) 0 50%;
background-size: 1px 100%;
color: darkolivegreen;
text-shadow: 0 1px 0 lemonchiffon;
text-decoration: none;
transition: .35s;
}
.ctrl:hover, .ctrl:focus {
background-size: 1px 120%;
color: black;
text-shadow: 0 1px 0 white;
}
.ctrl:active {
top: 1px;
box-shadow: inset 1px 1px 3px;
}
.sz-ctrl {
width: 1.5em;
border-radius: 50%;
font-weight: 900;
}
.big-btn, .lbl-area {
padding: 0 .8em;
margin: .25em 1em;
border-radius: .15em;
}
.lbl-area {
min-width: 6.5em;
border: solid 1px grey;
box-shadow: 0 1px 0 white;
}
.game-area {
background: linear-gradient(mintcream -66%, limegreen 133%);
}
.next {
padding: 0;
margin: .5em;
}
.sym, .gridcell {
width: 1.3em;
height: 1.3em;
font: 700 2.5em/1.3 Helvetica, sans-serif;
}
.next li:not(:first-child),
.gridcell:not(:first-child) {
border-left: solid 1px grey;
}
.gridrow:not(:first-child) {
border-top: solid 1px grey;
}
.gridcomp, .grid.gridcomp {
padding: 0;
margin: 0;
}
.gridcell {
position: relative;
background: lightgreen;
cursor: pointer;
}
.pulse {
z-index: 9;
box-shadow: 1px 1px 3px;
animation: puls 1s infinite alternate;
}
@keyframes puls {
to { transform: scale(1.09); }
}
.start { margin: 1em; }
var sym = ['❆', '❅', '❄', '✵', '✣', '✪', '☆', '✧', '☸', '♫', '☼', '♪', '❖', '✜', '☢', '☊'],
nxtsym = [],
gridstate = [],
started = false,
onhold = null;
var topbar = document.getElementById('top-bar'),
gridszel = document.getElementById('sz-lbl'),
gsdecr = document.getElementById('sz-decr'),
gsincr = document.getElementById('sz-incr'),
gen = document.getElementById('gen'),
nxt = document.getElementById('next'),
freeel = document.getElementById('free'),
ptsel = document.getElementById('pts'),
gridel = document.getElementById('grid'),
start = document.getElementById('start');
var initUsedSym = function() {
var used = [], symsz = sym.length;
for(var i = 0; i < usedsymsz; i++) {
var tmp = Math.round(Math.random()*(symsz-1));
while(used.indexOf(sym[tmp]) != -1) {
tmp = Math.round(Math.random()*(symsz-1));
}
used.push(sym[tmp]);
}
return used;
};
var gridsz = parseInt(gridszel.innerHTML, 10),
nextsz = Math.round(gridsz/3),
scorelinesz = Math.ceil(gridsz/2),
usedsymsz = Math.round(gridsz*.75),
usedsym = initUsedSym(),
free = gridsz*gridsz,
score = 0;
var initNext = function() {
var txt = '';
nxtsym = [];
for(var i = 0; i < nextsz; i++) {
var r = Math.round(Math.random()*(usedsymsz-1));
nxtsym.push(usedsym[r]);
txt += "<li><span class='sym sym-" + r + "'>" + usedsym[r] + "</span></li>";
}
nxt.innerHTML = txt;
};
initNext();
var initGrid = function() {
var txt = '';
onhold = null;
for(var i = 0; i < gridsz; i++) {
txt += "<div id='gridrow-" + i + "' class='gridcomp gridrow'>";
for(var j = 0; j < gridsz; j++) {
gridstate[i*gridsz + j] = null;
txt +=
"<div id='gridcell-" + i + "-" + j + "' class='gridcomp gridcell'></div>";
}
txt += "</div>"
}
gridel.innerHTML = txt;
};
initGrid();
var initFree = function() {
var t = 'Free cels: ' + free;
freeel.innerHTML = t;
};
initFree();
var initPts = function() {
var t = 'Score: ' + score;
ptsel.innerHTML = t;
};
initPts();
topbar.addEventListener('click', function(e){
var target = e.target;
if(target == gsdecr) {
if(gridsz > 3) gridszel.innerHTML = --gridsz;
return;
}
if(target == gsincr) {
if(gridsz < 17) gridszel.innerHTML = ++gridsz;
return;
}
if(target == gen) {
nextsz = Math.round(gridsz/3),
scorelinesz = Math.ceil(gridsz/2),
usedsymsz = Math.round(gridsz*.75),
usedsym = initUsedSym(),
free = gridsz*gridsz,
score = 0;
initNext();
initFree();
initPts();
initGrid();
started = false;
}
}, false);
var nextS = function() {
for(var i = 0; i < nextsz; i++) {
if (free === 0) {
alert("game over!");
return;
}
var t = Math.round(Math.random()*(gridsz*gridsz-1)),
col, row, cell;
while(gridstate[t] != null) {
t = Math.round(Math.random()*(gridsz*gridsz-1));
}
--free;
freeel.innerHTML = 'Free cells: ' + free;
gridstate[t] = nxtsym[i];
col = t%gridsz;
row = (t - col)/gridsz;
cell = document.getElementById("gridcell-" + row + "-" + col);
cell.innerHTML = nxtsym[i];
}
initNext();
};
start.addEventListener('click', function(){
if(started) initNext();
initGrid();
nextS();
started = true;
console.log(gridstate);
}, false);
var check1Fill = function(idx, csym, advance) {
console.log('checkfor ' + idx + '/' + csym);
var count = 1, cidx = idx-1, lidx = idx-1, ridx = idx+1;
console.log('will check left & right of ' + idx);
console.log('start from ' + idx);
while(cidx%gridsz !== (gridsz-1) && gridstate[cidx] == csym) {
console.log('going left');
console.log('have ' + csym + ' at ' + cidx);
count++;
lidx = cidx--;
}
console.log('at ' + lidx + ': ' + gridstate[lidx]);
if(gridstate[lidx] != csym) lidx++;
cidx = idx+1;
while(cidx%gridsz !== 0 && gridstate[cidx] == csym) {
console.log('going right');
console.log('have ' + csym + ' at ' + cidx);
count++;
ridx = cidx++;
}
console.log('at ' + ridx + ': ' + gridstate[ridx]);
if(gridstate[ridx] != csym) ridx--;
console.log('between ' + lidx + ' & ' + ridx);
console.log(count + ' vs min is ' + scorelinesz);
if(count >= scorelinesz) {
score += 10 + (count - scorelinesz);
ptsel.innerHTML = 'Score: ' + score;
for(var i = lidx; i <= ridx; i++) {
gridstate[i] = null;
++free;
freeel.innerHTML = 'Free cells: ' + free;
var c = i%gridsz,
r = (i-c)/gridsz,
cel = document.getElementById('gridcell-' + r + '-' + c);
console.log('clean ' + i + ' gridcell-' + r + '-' + c);
cel.innerHTML = '';
}
return true;
}
return false;
};
var checkFill = function(idx, csym) {
if(check1Fill(idx, csym, 1)) return true;
if(check1Fill(idx, csym, gridsz)) return true;
if(check1Fill(idx, csym, gridsz+1)) return true;
return false;
};
grid.addEventListener('click', function(e){
if(!started) return;
var target = e.target,
elid = target.id,
idparts = elid.split('-'),
row = parseInt(idparts[1], 10),
col = parseInt(idparts[2], 10),
cid = row*gridsz + col;
if(onhold == null && gridstate[cid] == null)
return;
if(onhold != null) {
var prevcol = onhold%gridsz,
prevrow = (onhold - prevcol)/gridsz,
prevclicked = document.getElementById('gridcell-' + prevrow + '-' + prevcol);
prevclicked.classList.remove('pulse');
if(gridstate[cid] != null) {
onhold = cid;
console.log('hold ' + onhold);
target.classList.add('pulse');
return;
}
prevclicked.innerHTML = '';
var csym = gridstate[onhold];
target.innerHTML = csym;
gridstate[cid] = csym;
gridstate[onhold] = null;
onhold = null;
if(!checkFill(cid, csym)){
nextS();
var gl = gridstate.length;
for(var i = 0; i < gl; i++) {
if(i%gridsz <= scorelinesz) continue;
csym = gridstate[i];
if(csym != null) checkFill(i, csym);
}
}
return;
}
if(gridstate[cid] != null) {
onhold = cid;
console.log('hold ' + onhold);
target.classList.add('pulse');
return;
}
}, false);
This Pen doesn't use any external CSS resources.