aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2017-03-04 23:48:07 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2017-03-04 23:48:07 +0800
commitbdbf0454f4d464eed3939a6bf7cb05452f21b15b (patch)
tree255c02eecbec53e0b915662fd0ceb9beb0640b35
parentf27966a7caab0f4891746f6abef8d4337b87e767 (diff)
downloadminesweeperjs-bdbf0454f4d464eed3939a6bf7cb05452f21b15b.tar.xz
Initial upload.
-rw-r--r--README.md6
-rw-r--r--colors-day.css16
-rw-r--r--colors-night.css16
-rwxr-xr-xcommon.css42
-rw-r--r--index.html171
-rw-r--r--minesweeper.js423
-rw-r--r--panel.css51
-rw-r--r--panel.js48
8 files changed, 773 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4ca9a7a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# minesweeperjs
+A fancy minesweeper in your browser with a "multimine" mode
+
+Try it live [here](https://chrisoft.org/minesweeper/).
+
+The code is pretty ugly as _I don't know JS_. Feel free to improve it.
diff --git a/colors-day.css b/colors-day.css
new file mode 100644
index 0000000..8be76b3
--- /dev/null
+++ b/colors-day.css
@@ -0,0 +1,16 @@
+body {
+ background: #FFF;
+ color: #000;
+}
+#panel li a.active {
+background-color:#CEC;
+}
+#panel li a:hover:not(.active) {
+background-color:#DFD;
+}
+#panel {
+background-color:#EEE;
+}
+#content .block {
+border: 1px solid #333;
+}
diff --git a/colors-night.css b/colors-night.css
new file mode 100644
index 0000000..6ff2c60
--- /dev/null
+++ b/colors-night.css
@@ -0,0 +1,16 @@
+body {
+ background: #090933;
+ color: #FFF;
+}
+#panel li a.active {
+background-color:#449;
+}
+#panel li a:hover:not(.active) {
+background-color:#338;
+}
+#panel {
+background-color:#116;
+}
+#content .block {
+border: 1px solid #338;
+}
diff --git a/common.css b/common.css
new file mode 100755
index 0000000..066b69f
--- /dev/null
+++ b/common.css
@@ -0,0 +1,42 @@
+.CTitle {
+ font-family: 'FreeMono', 'Courier New', Courier, monospace;
+}
+.TText {
+ font-family: 'FreeMono', 'Courier New', Courier, monospace;
+}
+a:link {
+color:#1194FF;
+text-decoration:none;
+}
+a:visited {
+color:#20ACFF;
+text-decoration:none;
+}
+a:hover {
+color:#3FBFFF;
+text-decoration:none;
+}
+a:active {
+color:#CCCCFF;
+text-decoration:none;
+}
+div.comment{
+ border:1px solid #CCC;
+ margin:1em;
+}
+div.author{
+ text-align:right;
+ padding-right:0.5em;
+ padding-bottom:0.5em;
+}
+div.floatingl {
+ left: 0px;
+ bottom: -10px;
+ position: fixed;
+}
+div.floatingr {
+ right: 0px;
+ bottom: -10px;
+ position: fixed;
+ transform: rotateY(180deg);
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..3c814ec
--- /dev/null
+++ b/index.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<meta name="viewport" content="width=device-width">
+<title>Chrisoft::Minesweeper</title>
+<link rel="icon" href="../favicon.png">
+<link rel="stylesheet" type="text/css" href="common.css">
+<link rel="stylesheet" type="text/css" href="panel.css">
+<script type="text/javascript" src="panel.js"></script>
+<script type="text/javascript" src="minesweeper.js"></script>
+<style>
+div#OptionsContainer
+{
+ text-align:center;
+ margin:auto;
+}
+button
+{
+ border:none;
+ color:white;
+ padding:0.5em 2em;
+ text-align:center;
+ background-color:#4A4;
+ transition-duration: 0.2s;
+}
+button:hover
+{
+ background-color:#6C6;
+}
+button.off
+{
+ background-color:#A44;
+}
+button.off:hover
+{
+ background-color:#C66;
+}
+button.disabled:hover, button.disabled
+{
+ background-color:#888;
+}
+div#containerDiv
+{
+ margin:auto;
+ position:relative;
+}
+div.clickable
+{
+ position:absolute;
+ text-align:center;
+ border:1px black solid;
+}
+div.overlay
+{
+ pointer-events:none;
+ display:table;
+ position:absolute;
+ text-align:center;
+}
+div.trans
+{
+ transition:100ms;
+}
+div.modal
+{
+ background-color:rgba(0,0,0,0.6);
+ color:#FFF;
+ width:60%;
+ min-height:40%;
+ position:absolute;
+ left:50%;
+ top:50%;
+ transform:translate(-50%,-50%);
+ transition:100ms;
+ font-size:1.4em;
+ padding:1em;
+}
+@media(max-width:768px)
+{
+ div.modal{width:90%;min-height:60%;font-size:1.2em;}
+}
+div.mine{background-color:rgba(255,192,0,0.6);}
+div.detonated{background-color:rgba(255,0,0,0.6);}
+div.flag{background-color:rgba(0,255,0,0.6);}
+div.flagw{background-color:rgba(255,0,255,0.6);}
+div.dug{background-color:rgba(160,160,192,0.8);}
+div.normal{background-color:rgba(128,128,160,0.6);}
+.one{color:#00f;}
+.two{color:#008000;}
+.three{color:#f00;}
+.four{color:#000080;}
+.five{color:#800000;}
+.six{color:#008080;}
+.seven{color:#000;}
+.eight{color:#7e7e7e;}
+</style>
+</head>
+<body onload="init();">
+<script type="text/javascript" language="javascript">
+var thm=document.cookie.replace(new RegExp("(?:(?:^|.*;\\s*)thm\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1");
+link = document.createElement( "link" );
+switch(thm)
+{
+ case "day":
+ link.href = "colors-day.css";
+ break;
+ case "night":
+ link.href = "colors-night.css";
+ break;
+ case "auto":
+ default:
+ var c=new Date();
+ if(c.getHours()>=6&&c.getHours()<18)
+ {link.href = "colors-day.css";}
+ else
+ {link.href = "colors-night.css";}
+ break;
+}
+link.type="text/css";
+link.rel="stylesheet";
+document.getElementsByTagName("head")[0].appendChild(link);
+</script>
+<div id="panel" class="TText">
+ <ul id="panellist">
+ <li><a href="/"><h1>Chrisoft</h1></a></li>
+ <li><h3>Minesweeper</h3></li>
+ <li>
+ Difficulty:
+ <select id="bsize">
+ <option value="1">Easy</option>
+ <option value="2">Normal</option>
+ <option value="3">Hard</option>
+ </select>
+ </li>
+ <li>Multimine:
+ <button id="multim" onclick="multiminetoggle();" class="off">Off</button>
+ </li>
+ <li>Effects:
+ <button id="efx" onclick="efxtoggle();">On</button>
+ </li>
+ <li>Sounds:
+ <button id="sfx" onclick="sfxtoggle();">On</button>
+ </li>
+ <li><a href="javascript:void(0);" onclick="document.getElementById('help').style.opacity='1';document.getElementById('help').style.zIndex='1000';">Help</a></li>
+ <li>version: 0.8.7+b1</li>
+</div>
+<div id="OptionsContainer" class="TText">
+ <button id="start" onclick="gameInit();">New Game</button>
+ <button id="st" onclick="systemtest();" style="display:none;" class="disabled">I'm ready, dismantle the mines!</button>
+ <br>Mines:<span id="mines"></span>
+</div>
+<div id="containerDiv">
+</div>
+<div class="modal TText" style="opacity:0;text-align:center;z-index:-999;" id="result" onclick="this.style.opacity='0';this.style.zIndex='-999';">
+</div>
+<div class="modal TText" style="opacity:0;z-index:-999;" id="help" onclick="this.style.opacity='0';this.style.zIndex='-999';">
+ <p>
+ Left click / tap and hold on untouched cell = reveal cell<br>
+ Right click / tap on untouched cell = toggle flag in cell<br>
+ Right click / tap on revealed cell = reveal surrounding cells if feasible<br>
+ </p>
+ <p>
+ In multimine mode, there might be multiple (6 max) mines in a single cell.
+ Use right click or short tap to increase flag count, left click or long tap
+ to decrease flag count. To finish a multimine game, you have to flag all cells
+ with mines correctly and click the "I'm ready, dismantle the mines!" button.
+ </p>
+</div>
+</body>
+</html>
diff --git a/minesweeper.js b/minesweeper.js
new file mode 100644
index 0000000..99730fe
--- /dev/null
+++ b/minesweeper.js
@@ -0,0 +1,423 @@
+//Chris Xiong 2017
+//The MIT License
+var dimpx,dimx,dimy,cc,firstclick;
+var boardn=null;
+var boards=null;
+var boarde=null;
+var ismobile,effects=true,multimine=false,sfxe=true;
+var dead,st,solved,animating;
+var dx=[-1,-1,-1, 0, 0, 1, 1, 1];
+var dy=[-1, 0, 1,-1, 1,-1, 0, 1];
+var classes=["one","two","three","four","five","six","seven","eight"];
+var queue=[],newqueue=[],flags=[];
+var mines=[],detx,dety,cmines=[],sfx=[];
+function randomInt(min,max)
+{
+ seed*=214013;seed+=2531011;seed&=0xffffffff;
+ return min+(seed^seed>>15)%(max-min+1);
+}
+function efxtoggle()
+{
+ effects=!effects;
+ document.getElementById('efx').classList.toggle('off');
+ document.getElementById('efx').innerHTML=effects?"On":"Off";
+ for(var i=0;i<dimx;++i)
+ for(var j=0;j<dimy;++j)
+ if(effects)boarde[i][j].overlay.classList.add('trans');
+ else boarde[i][j].overlay.classList.remove('trans');
+}
+function sfxtoggle()
+{
+ sfxe=!sfxe;
+ document.getElementById('sfx').classList.toggle('off');
+ document.getElementById('sfx').innerHTML=effects?"On":"Off";
+}
+function multiminetoggle()
+{
+ multimine=!multimine;
+ document.getElementById('multim').classList.toggle('off');
+ document.getElementById('multim').innerHTML=multimine?"On":"Off";
+ gameInit();
+}
+function init()
+{
+ if( navigator.userAgent.match(/Android/i)
+ || navigator.userAgent.match(/webOS/i)
+ || navigator.userAgent.match(/iPhone/i)
+ || navigator.userAgent.match(/iPad/i)
+ || navigator.userAgent.match(/iPod/i)
+ || navigator.userAgent.match(/BlackBerry/i)
+ || navigator.userAgent.match(/Windows Phone/i)
+ )
+ ismobile=true;
+ setupevents();
+ gameInit();
+ document.getElementById("bsize").onchange=function(){gameInit();};
+}
+function playsound(s,v)
+{
+ if(!sfxe)return;var f=false,i;
+ for(i=0;i<sfx.length;++i)if(!sfx[i])break;
+ if(i==sfx.length){sfx.push(new Audio(s));}
+ else sfx[i]=new Audio(s);
+ sfx[i].id=i;sfx[i].volume=v?v:.5;
+ sfx[i].onended=function(){sfx[this.id]=null;}
+ sfx[i].play();
+}
+function gameInit(custx,custy,ccc)
+{
+ if((custx&&custx>40)||(custy&&custy>40)||(ccc&&custx&&custy&&(ccc>custx*custy-9)))
+ {console.log("Are you insane?");return;}
+ firstclick=true;dead=false;solved=false;for(var i=0;i<7;++i)flags[i]=cmines[i]=0;
+ document.getElementById("result").style.opacity="0";
+ document.getElementById("result").style.zIndex="-999";animating=false;
+ for(var nd=document.getElementById("containerDiv");nd.hasChildNodes();nd.removeChild(nd.lastChild));
+ if(document.getElementById("bsize").value=="1")
+ {dimx=9;dimy=9;cc=10;}
+ if(document.getElementById("bsize").value=="2")
+ {dimx=16;dimy=16;cc=40;}
+ if(document.getElementById("bsize").value=="3")
+ {dimx=16;dimy=30;cc=99;}
+ if(custx&&custy&&ccc){dimx=custx;dimy=custy;cc=ccc;}
+ if((window.innerWidth>window.innerHeight)^(dimx<dimy))
+ {var t=dimx;dimx=dimy;dimy=t;}
+ updateflags();sfx=[];
+ seed=Math.floor(Math.random()*2000000000);
+ if(multimine)document.getElementById("st").style.display="inline-block";
+ else document.getElementById("st").style.display="none";
+ document.getElementById("st").classList.add("disabled");
+ boardn=new Array(dimx+4);for(var i=0;i<dimx+4;++i){
+ boardn[i]=new Array(dimy+4);
+ for(var j=0;j<dimy+4;++j)boardn[i][j]=0;
+ }
+ if(window.innerWidth/dimy*dimx>window.innerHeight*0.8)
+ {
+ dimpx=window.innerHeight*(ismobile?0.9:0.8);
+ document.getElementById("containerDiv").style.width=dimpx/dimx*dimy+"px";
+ document.getElementById("containerDiv").style.height=dimpx+"px";
+ }
+ else
+ {
+ dimpx=window.innerWidth*(ismobile?0.9:0.8);
+ document.getElementById("containerDiv").style.width=dimpx+"px";
+ document.getElementById("containerDiv").style.height=dimpx/dimy*dimx+"px";
+ }
+ boards=new Array(dimx+4);for(var i=0;i<dimx+4;++i)boards[i]=new Array(dimy+4);
+ boarde=new Array(dimx+4);for(var i=0;i<dimx+4;++i)boarde[i]=new Array(dimy+4);
+ for(var i=0;i<dimx;++i)
+ for(var j=0;j<dimy;++j)
+ {
+ boards[i][j]=0;
+ boarde[i][j]=document.createElement('div');
+ boarde[i][j].classList.add("clickable");
+ boarde[i][j].style.top=(i*100/dimx)+'%';
+ boarde[i][j].style.left=(j*100/dimy)+'%';
+ boarde[i][j].x=i;boarde[i][j].y=j;
+ boarde[i][j].style.width=(95/dimy)+"%";
+ boarde[i][j].style.height=(95/dimx)+"%";
+ boarde[i][j].classList.add('normal');
+
+ boarde[i][j].overlay=document.createElement('div');
+ boarde[i][j].overlay.classList.add("overlay");
+ boarde[i][j].overlay.style.top=(i*100/dimx)+'%';
+ boarde[i][j].overlay.style.left=(j*100/dimy)+'%';
+ boarde[i][j].overlay.style.width=(95/dimy)+"%";
+ boarde[i][j].overlay.style.height=(95/dimx)+"%";
+ boarde[i][j].overlay.style.opacity="0";
+ boarde[i][j].overlay.style.transform="scale(2,2)";
+ if(effects)boarde[i][j].overlay.classList.add("trans");
+
+ boarde[i][j].span=document.createElement('span');
+ boarde[i][j].span.style.display="table-cell";
+ boarde[i][j].span.style.fontWeight="bold";
+ boarde[i][j].span.style.verticalAlign="middle";
+ boarde[i][j].span.style.userSelect="none";
+ boarde[i][j].span.classList.add("TText");
+ boarde[i][j].overlay.appendChild(boarde[i][j].span);
+ boarde[i][j].onclick=mclick;
+ boarde[i][j].oncontextmenu=rclick;
+ document.getElementById("containerDiv").appendChild(boarde[i][j]);
+ document.getElementById("containerDiv").appendChild(boarde[i][j].overlay);
+ }
+}
+function genmines(sx,sy)
+{
+ mines=[];var s=[];
+ for(var i=0;i<dimx;++i)
+ for(var j=0;j<dimy;++j)
+ if(Math.abs(sx-i)>=2||Math.abs(sy-j)>=2)s.push(i*dimy+j);
+ for(var i=0;i<cc;++i)
+ {
+ var t=randomInt(0,s.length-1);
+ var v=s[t];
+ var x=Math.trunc(v/dimy),y=v%dimy;
+ s.splice(t,1);
+ boardn[x][y]=-1;mines.push(new pair(x,y));
+ if(multimine)
+ {
+ var rnd=randomInt(1,100);
+ if(rnd>32)--boardn[x][y];
+ if(rnd>57)--boardn[x][y];
+ if(rnd>77)--boardn[x][y];
+ if(rnd>87)--boardn[x][y];
+ if(rnd>95)--boardn[x][y];
+ }
+ ++cmines[-boardn[x][y]];
+ for(var j=0;j<8;++j)
+ {
+ var cx=x+dx[j],cy=y+dy[j];
+ if(cx>=0&&cx<dimx&&cy>=0&&cy<dimy&&boardn[cx][cy]>=0)
+ boardn[cx][cy]-=boardn[x][y];
+ }
+ }st=new Date();updateflags();
+}
+function mclick(e)
+{
+ e.preventDefault();
+ if(dead||solved||animating)return;
+ var x=this.x,y=this.y;
+ if(ismobile)
+ {
+ if(multimine)
+ {if(boards[x][y]>=0)flag(x,y);}
+ else{if(boards[x][y]==1)deflag(x,y);else if(boards[x][y]==0)flag(x,y);}
+ if(boards[x][y]==-1)autodig(x,y);
+ }
+ else
+ {
+ if(boards[x][y]==0)dig(x,y);
+ else if(boards[x][y]==-1)autodig(x,y);
+ else if(multimine&&boards[x][y]>0)deflag(x,y);
+ }
+}
+function rclick(e)
+{
+ e.preventDefault();
+ if(dead||solved||animating)return;
+ var x=this.x,y=this.y;
+ if(ismobile)
+ {
+ if(boards[x][y]==0)dig(x,y);
+ else if(multimine&&boards[x][y]>0)deflag(x,y);
+ }
+ else
+ {
+ if(multimine)
+ {if(boards[x][y]>=0)flag(x,y);}
+ else{if(boards[x][y]==1)deflag(x,y);else if(boards[x][y]==0)flag(x,y);}
+ }
+}
+function checksolved()
+{
+ for(var i=0;i<dimx;++i)
+ for(var j=0;j<dimy;++j)
+ if(boardn[i][j]>=0&&boards[i][j]!=-1)return false;
+ return true;
+}
+var pair=function(_x,_y){this.x=_x;this.y=_y;}
+pair.prototype.toString=function()
+{
+ return this.x+","+this.y;
+}
+function dfs(x,y)
+{
+ if(boards[x][y]!=0)return;
+ newqueue.push(new pair(x,y));
+ boards[x][y]=-1;animating=true;bfs(1);
+}
+function bfs(s)
+{
+ q=newqueue.slice(0);newqueue=[];
+ if(s)playsound('ding.ogg');
+ for(var i=0;i<q.length;++i)
+ {
+ var x=q[i].x,y=q[i].y;
+ if(boardn[x][y]<0){die(x,y);return;}
+ if(boardn[x][y]>0)
+ {
+ boarde[x][y].span.innerHTML=boardn[x][y];
+ boarde[x][y].span.classList.add(classes[(boardn[x][y]-1)%8]);
+ }
+ boarde[x][y].overlay.style.opacity="1";
+ boarde[x][y].overlay.style.transform="scale(1,1)";
+ boarde[x][y].overlay.classList.add("dug");
+ if(boardn[x][y]==0)
+ {
+ for(var j=0;j<8;++j)
+ {
+ var c=new pair(x+dx[j],y+dy[j]);
+ if(c.x>=0&&c.x<dimx&&c.y>=0&&c.y<dimy&&boards[c.x][c.y]==0)
+ {newqueue.push(c);boards[c.x][c.y]=-1;}
+ }
+ }
+ }
+ if(newqueue.length){if(effects)setTimeout(bfs,50,1);else bfs(0);}
+ else
+ {
+ animating=false;
+ if(checksolved())
+ {
+ if(!multimine)
+ {
+ showresult(1);
+ }else document.getElementById("st").classList.remove("disabled");
+ }
+ }
+}
+function dig(x,y)
+{
+ if(firstclick){genmines(x,y);firstclick=false;}
+ if(boards[x][y]==0)dfs(x,y);
+}
+function autodig(x,y)
+{
+ if(boards[x][y]!=-1)return;
+ var c=0;
+ for(var i=0;i<8;++i)
+ {
+ var cx=x+dx[i],cy=y+dy[i];
+ if(cx>=0&&cx<dimx&&cy>=0&&cy<=dimy&&boards[cx][cy]>0)c+=boards[cx][cy];
+ }
+ if(c==boardn[x][y])
+ {
+ newqueue=[];
+ for(var i=0;i<8;++i)
+ {
+ var cx=x+dx[i],cy=y+dy[i];
+ if(cx>=0&&cx<dimx&&cy>=0&&cy<=dimy)
+ {
+ if(multimine&&boardn[cx][cy]<0&&boards[cx][cy]!=-boardn[cx][cy])
+ {die(cx,cy);return;}
+ if(boards[cx][cy]==0){newqueue.push(new pair(cx,cy));boards[cx][cy]=-1;}
+ }
+ }
+ if(newqueue.length){animating=true;bfs(1);}
+ }
+}
+function flag(x,y)
+{
+ --flags[boards[x][y]];boards[x][y]++;
+ if(multimine){if(boards[x][y]>6)boards[x][y]=6;boarde[x][y].span.innerHTML=boards[x][y];}
+ else{if(boards[x][y]>1)boards[x][y]=1;boarde[x][y].span.innerHTML="X";}
+ ++flags[boards[x][y]];
+ boarde[x][y].overlay.classList.add('flag');
+ boarde[x][y].overlay.style.opacity="1";
+ boarde[x][y].overlay.style.transform="scale(1,1)";
+ updateflags();
+}
+function deflag(x,y)
+{
+ --flags[boards[x][y]];--boards[x][y];++flags[boards[x][y]];
+ boarde[x][y].span.innerHTML=boards[x][y];
+ if(boards[x][y]==0)
+ {
+ boarde[x][y].span.innerHTML="";
+ boarde[x][y].classList.remove('flag');
+ boarde[x][y].classList.add('normal');
+ boarde[x][y].overlay.style.opacity="0";
+ boarde[x][y].overlay.style.transform="scale(2,2)";
+ }
+ updateflags();
+}
+function updateflags()
+{
+ if(multimine)
+ {
+ var s="";
+ for(var i=1;i<7;++i)s=s+" x"+i+" "+flags[i]+"/"+cmines[i];
+ document.getElementById("mines").innerHTML=s;
+ }
+ else
+ {document.getElementById("mines").innerHTML=flags[1]+"/"+cmines[1];}
+}
+function cmp(x,y)
+{
+ return (Math.abs(x.x-detx)+Math.abs(x.y-dety))-(Math.abs(y.x-detx)+Math.abs(y.y-dety));
+}
+function die(x,y)
+{
+ if(dead||boardn[x][y]>=0)return;
+ dead=true;detx=x;dety=y;mines.sort(cmp);
+ for(var i=0;i<dimx;++i)
+ for(var j=0;j<dimy;++j)
+ if(boards[i][j]>0&&boards[i][j]!=-boardn[i][j]&&(i!=x||j!=y))
+ {
+ boarde[i][j].overlay.classList.remove('flag');
+ boarde[i][j].overlay.classList.add('flagw');
+ boarde[i][j].span.innerHTML="<s>"+boarde[i][j].span.innerHTML+"</s>";
+ }
+ boarde[x][y].overlay.classList.add('detonated');
+ boarde[x][y].overlay.classList.remove('flag');
+ boarde[x][y].overlay.style.opacity="1";
+ boarde[x][y].overlay.style.transform="scale(1,1)";
+ if(multimine)
+ {
+ if(-boardn[x][y]!=boards[x][y]&&boards[x][y]>0)
+ boarde[x][y].span.innerHTML="<s>"+boards[x][y]+"</s>"+(boardn[x][y]<0?-boardn[x][y]:"");
+ else boarde[x][y].span.innerHTML=-boardn[x][y];
+ }
+ var st=1;if(mines[1].toString()!=new pair(x,y).toString)st=0;
+ playsound('explode.ogg');
+ if(effects)setTimeout(dieproc,10,st);else dieproc(st);
+ window.navigator.vibrate([200,100,300]);
+}
+function dieproc(p)
+{
+ if(!dead||p>=mines.length){if(p>=mines.length)showresult(0);document.getElementById("containerDiv").style.transform="none";return;}
+ var x=mines[p].x,y=mines[p].y;if(effects&&(p%5==0))playsound('explode.ogg',.2);
+ if(boards[x][y]!=-boardn[x][y])
+ {
+ boarde[x][y].overlay.classList.add('mine');
+ boarde[x][y].overlay.classList.remove('flag');
+ }
+ boarde[x][y].overlay.style.opacity="1";
+ boarde[x][y].overlay.style.transform="scale(1,1)";
+ if(multimine)
+ {
+ if(-boardn[x][y]!=boards[x][y]&&boards[x][y]>0)
+ boarde[x][y].span.innerHTML="<s>"+boards[x][y]+"</s>"+(boardn[x][y]<0?-boardn[x][y]:"");
+ else boarde[x][y].span.innerHTML=-boardn[x][y];
+ }
+ if(effects)
+ document.getElementById("containerDiv").style.transform="translate("+(Math.random()*10-5)+"px,"+(Math.random()*10-5)+"px)";
+ if(!effects||(cc>40&&(p&1)))dieproc(p+1);else setTimeout(dieproc,10,p+1);
+}
+function systemtest()
+{
+ if(document.getElementById("st").classList.contains("disabled")||solved||dead)return;
+ for(var i=0;i<dimx;++i)for(var j=0;j<dimy;++j)
+ if(boardn[i][j]<0&&boards[i][j]!=-boardn[i][j]){die(i,j);return;}
+ showresult(1);
+}
+function t()
+{
+ switch(document.getElementById('bsize').value)
+ {
+ case "1":return "easy";
+ case "2":return "normal";
+ case "2":return "hard";
+ }
+}
+function showresult(w)
+{
+ if(w)
+ {
+ solved=true;document.getElementById('result').style.opacity="1";document.getElementById('result').style.zIndex="1000";
+ document.getElementById('result').innerHTML=
+ "You solved this "+t()+(multimine?" multimine":"")+" field in "+
+ ((new Date()).getTime()-st.getTime())/1000.+" seconds!<br>Click or tap anywhere in the dialog to close it.";
+ }
+ else
+ {
+ var cs=0,ccor=0,uc=0;
+ for(var i=0;i<dimx;++i)for(var j=0;j<dimy;++j)
+ {
+ if(boards[i][j]==-boardn[i][j]&&boardn[i][j]<0)ccor+=boards[i][j];
+ if(boardn[i][j]<0)cs-=boardn[i][j];
+ if(boards[i][j]==-1&&boardn[i][j]>=0)++uc;
+ }
+ document.getElementById('result').style.opacity="1";document.getElementById('result').style.zIndex="1000";
+ document.getElementById('result').innerHTML=
+ "Game Over!<br>You uncovered "+(100*uc/(dimx*dimy-cc)).toFixed(2)+"% of the field and located "+(100*ccor/cs).toFixed(2)+"% mines correctly.<br>Click or tap anywhere in the dialog to close it."
+ }
+}
diff --git a/panel.css b/panel.css
new file mode 100644
index 0000000..2b1066a
--- /dev/null
+++ b/panel.css
@@ -0,0 +1,51 @@
+#panel ul{
+padding:0;
+list-style-type:none;
+}
+#panel li h1 {
+position:relative;
+left:-0.6em;
+margin:0;
+font-weight:normal;
+}
+#panel li h3 {
+position:relative;
+left:-0.3em;
+margin:0;
+font-weight:normal;
+}
+#panel li {
+display:block;
+padding-left:1.5em;
+padding-top:0.5em;
+padding-bottom:0.5em;
+}
+#panel {
+width: 16em;
+height:100%;
+position:fixed;
+top:0;
+left:0;
+transition:left 0.4s;
+z-index:999;
+}
+#panel .themesw {
+text-align:center;
+padding-top:0.5em;
+}
+#content {
+margin-left: 16em;
+}
+#content p{text-indent:2em;}
+#content h2{font-weight:normal;}
+#content h3{font-weight:normal;}
+#content .block {
+display: none;
+padding: 1em;
+}
+@media all
+{
+ #panel{left:-15em;}
+ #content{margin-left:1em;}
+ #msgform{width:auto;margin:1em;}
+}
diff --git a/panel.js b/panel.js
new file mode 100644
index 0000000..1f02c5f
--- /dev/null
+++ b/panel.js
@@ -0,0 +1,48 @@
+var fold=true;
+function setupevents()
+{
+ window.ontouchstart=function(e)
+ {
+ x1=e.touches[0].screenX;
+ y1=e.touches[0].screenY;
+ }
+ window.ontouchmove=function(e)
+ {
+ x2=e.touches[0].screenX;
+ y2=e.touches[0].screenY;
+ }
+ window.ontouchend=function(e)
+ {
+ x2=e.changedTouches[0].screenX;
+ y2=e.changedTouches[0].screenY;
+ if(Math.abs(x1-x2)<20&&Math.abs(y1-y2)<20)
+ {
+ if(x2<document.getElementById("panel").getClientRects()[0].right&&fold)
+ {document.getElementById("panel").style.left="0";fold=false;}
+ if(x2>document.getElementById("panel").getClientRects()[0].right&&!fold)
+ {document.getElementById("panel").style.left="-15em";fold=true;}
+ }
+ if(x2-x1>window.innerWidth*0.2)
+ {document.getElementById("panel").style.left="0";fold=false;}
+ if(x1-x2>window.innerWidth*0.2)
+ {document.getElementById("panel").style.left="-15em";fold=true;}
+ }
+ document.getElementById("panel").onmouseenter=function()
+ {
+ if(fold)
+ {document.getElementById("panel").style.left="0";fold=false;}
+ }
+ document.getElementById("panel").onmouseleave=function()
+ {
+ if(!fold)
+ {document.getElementById("panel").style.left="-15em";fold=true;}
+ }
+}
+function unsetevents()
+{
+ window.ontouchstart=undefined;
+ window.ontouchmove=undefined;
+ window.ontouchend=undefined;
+ document.getElementById("panel").onmouseenter=undefined;
+ document.getElementById("panel").onmouseleave=undefined;
+}