diff options
Diffstat (limited to 'interactorindex.html')
| -rw-r--r-- | interactorindex.html | 228 | 
1 files changed, 228 insertions, 0 deletions
diff --git a/interactorindex.html b/interactorindex.html new file mode 100644 index 0000000..4593974 --- /dev/null +++ b/interactorindex.html @@ -0,0 +1,228 @@ +<!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:.15; +			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)]); +		if(checkwin(bd)!=-1)break; +	} 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; +						while(applymove_queue.length&&typeof applymove_queue[0]=="function"){ +							applymove_queue[0](); +							applymove_queue.shift(); +						} +						if(applymove_queue.length){ +							setTimeout(function(){ +								applymove(applymove_queue[0][0],applymove_queue[0][1]); +								applymove_queue.shift(); +							},50); +						} +					} +				} +				time++; +			},20); +		},350*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){ +	if(applymove_busy)applymove_queue.push(function(){ +		onturn=player; +		drawboard(bd,onturn); +	}); +	else { +		onturn=player; +		drawboard(bd,onturn); +	} +}); +socket.on("getusermove",function(){ +	if(applymove_busy)applymove_queue.push(getusermove); +	else getusermove(); +}); +socket.on("win",function(player){ +	setstatustext("<b><i>Player "+(player+1)+" won!</i></b>"); +}); +</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  | 
