summaryrefslogtreecommitdiff
path: root/interactor/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'interactor/index.html')
-rw-r--r--interactor/index.html213
1 files changed, 213 insertions, 0 deletions
diff --git a/interactor/index.html b/interactor/index.html
new file mode 100644
index 0000000..c861c82
--- /dev/null
+++ b/interactor/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