diff options
Diffstat (limited to 'index.html')
-rw-r--r-- | index.html | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..c861c82 --- /dev/null +++ b/index.html @@ -0,0 +1,213 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Interactor for Chain Reaction</title> +<script src="/socket.io/socket.io.js"></script> +<script src="/common.js"></script> +<script> +var CVSH=500; + +var COLOURS=["#00F","#F00","#0CC"]; + +var socket=io(); +var CELLSZ=~~(CVSH/(H+1)); +var CVSW=CELLSZ*(W+1); +var CELL0X=~~(CVSW/2-W/2*CELLSZ)+.5,CELL0Y=~~(CVSH/2-H/2*CELLSZ)+.5; +var bd; + +var cvs,ctx; + +var onturn; + +var usercanmove; + +function init(){ + cvs=document.getElementById("cvs"); + cvs.width=CVSW; + cvs.height=CVSH; + ctx=cvs.getContext("2d"); + cvs.addEventListener("click",function(ev){ + if(!usercanmove)return; + var bbox=ev.target.getBoundingClientRect(); + var cx=ev.clientX-bbox.left,cy=ev.clientY-bbox.top; + var x=~~((cx-CELL0X)/CELLSZ),y=~~((cy-CELL0Y)/CELLSZ); + if(x<0||y<0||x>=W||y>=H)return; + if(bd[y][x].n&&bd[y][x].c!=onturn)return; + applymove(W*y+x,onturn); + socket.emit("usermove",W*y+x); + usercanmove=false; + setstatustext("<i>Waiting for other move...</i>"); + }); + onturn=0; + usercanmove=false; + bd=emptyboard(); + drawboard(bd,onturn); + setstatustext("<i>Initialised.</i>"); +} + +function drawboard(bd,clr){ + var x,y,i,angle,radius; + ctx.clearRect(0,0,CVSW,CVSH); + ctx.strokeStyle=COLOURS[+clr]; + ctx.beginPath(); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + ctx.moveTo(CELL0X+x*CELLSZ,CELL0Y+y*CELLSZ); + ctx.lineTo(CELL0X+(x+1)*CELLSZ,CELL0Y+y*CELLSZ); + ctx.lineTo(CELL0X+(x+1)*CELLSZ,CELL0Y+(y+1)*CELLSZ); + ctx.lineTo(CELL0X+x*CELLSZ,CELL0Y+(y+1)*CELLSZ); + ctx.lineTo(CELL0X+x*CELLSZ,CELL0Y+y*CELLSZ); + } + } + ctx.stroke(); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + ctx.fillStyle=COLOURS[bd[y][x].c]; + angle=1/bd[y][x].n*2*Math.PI; + radius=bd[y][x].n==1?0:.12; + for(i=0;i<bd[y][x].n;i++){ + ctx.beginPath(); + ctx.arc( + CELL0X+(x+.5+radius*Math.cos(angle*i))*CELLSZ, + CELL0Y+(y+.5+radius*Math.sin(angle*i))*CELLSZ, + CELLSZ*.2,0,2*Math.PI,1); + ctx.fill(); + } + } + } +} + +function stabiliseanims(bd){ + var anims=[],stage; + var newbd; + var x,y,nnei,quo; + do { + stage=[]; + newbd=bdcopy(bd); + for(y=0;y<H;y++){ + for(x=0;x<W;x++){ + nnei=(y>0)+(x>0)+(y<H-1)+(x<W-1); + if(bd[y][x].n>=nnei){ + quo=~~(bd[y][x].n/nnei); + newbd[y][x].n-=quo*nnei; + if(y>0) { + newbd[y-1][x].n+=quo; newbd[y-1][x].c=bd[y][x].c; + stage.push([W*y+x,W*(y-1)+x]); + } + if(x>0) { + newbd[y][x-1].n+=quo; newbd[y][x-1].c=bd[y][x].c; + stage.push([W*y+x,W*y+x-1]); + } + if(y<H-1){ + newbd[y+1][x].n+=quo; newbd[y+1][x].c=bd[y][x].c; + stage.push([W*y+x,W*(y+1)+x]); + } + if(x<W-1){ + newbd[y][x+1].n+=quo; newbd[y][x+1].c=bd[y][x].c; + stage.push([W*y+x,W*y+x+1]); + } + } + } + } + bd=newbd; + anims.push([stage,bdcopy(bd)]); + } while(stage.length); + return anims; +} + +var applymove_queue=[]; +var applymove_busy=false; + +function applymove(idx,c){ + assert(idx>=0&&idx<W*H); + applymove_busy=true; + bd[~~(idx/W)][idx%W].n++; + bd[~~(idx/W)][idx%W].c=c; + drawboard(bd,onturn); + var anims=stabiliseanims(bd); + anims.forEach(function(pair,i){ + var stage=pair[0],newbd=pair[1]; + var finalstage=i==anims.length-1; + setTimeout(function(){ + var time=0; + var interval=setInterval(function(){ + var i,fx,fy,tx,ty; + for(i=0;i<stage.length;i++){ + fx=stage[i][0]%W; fy=~~(stage[i][0]/W); + bd[fy][fx].n--; + } + drawboard(bd,onturn); + for(i=0;i<stage.length;i++){ + fx=stage[i][0]%W; fy=~~(stage[i][0]/W); + tx=stage[i][1]%W; ty=~~(stage[i][1]/W); + ctx.fillStyle=COLOURS[bd[fy][fx].c]; + ctx.beginPath(); + ctx.arc( + CELL0X+(fx*(1-time/10)+tx*time/10+.5)*CELLSZ, + CELL0Y+(fy*(1-time/10)+ty*time/10+.5)*CELLSZ, + CELLSZ*.2,0,2*Math.PI,1); + ctx.fill(); + } + if(time==10){ + clearInterval(interval); + bd=newbd; + drawboard(bd,onturn); + if(finalstage){ + applymove_busy=false; + if(applymove_queue.length){ + setTimeout(function(){ + applymove(applymove_queue[0][0],applymove_queue[0][1]); + applymove_queue.shift(); + },50); + } + } + } + time++; + },30); + },500*i+1); + }); +} + +function queueapplymove(idx,c){ + if(applymove_busy)applymove_queue.push([idx,c]); + else applymove(idx,c); +} + +function getusermove(){ + usercanmove=true; + setstatustext("<b>Your turn!</b>"); +} + +function setstatustext(text){ + var elem=document.getElementById("statustext"); + elem.innerHTML=text; +} + +function assert(cond){if(!cond)throw new Error("Assertion failed");} + + +socket.on("emptyboard",function(){ + bd=emptyboard(); +}); +socket.on("applymove",function(obj){ + queueapplymove(obj.index,obj.player); +}); +socket.on("alert",function(text){ + alert(text); +}); +socket.on("setonturn",function(player){ + onturn=player; + drawboard(bd,onturn); +}); +socket.on("getusermove",function(){ + getusermove(); +}); +</script> +</head> +<body onload="init()"> +<h3>Interactor for Chain Reaction</h3> +<canvas id="cvs"></canvas><br> +<span id="statustext"></span> +</body> +</html>
\ No newline at end of file |