diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | fiforead.cpp | 16 | ||||
| -rw-r--r-- | gameserver/gameserver.html | 18 | ||||
| -rwxr-xr-x | gameserver/gameserver.js | 1 | ||||
| -rw-r--r-- | humanbot.cpp | 254 | ||||
| -rw-r--r-- | humanbot_index.html | 543 | ||||
| -rwxr-xr-x | humanbot_server.js | 74 | 
7 files changed, 903 insertions, 6 deletions
@@ -9,6 +9,9 @@ randino  photon  charm +fiforead +humanbot +  viewcompetition  *.o diff --git a/fiforead.cpp b/fiforead.cpp new file mode 100644 index 0000000..6da0ae1 --- /dev/null +++ b/fiforead.cpp @@ -0,0 +1,16 @@ +#include <iostream> +#include <fstream> +#include <cassert> + +using namespace std; + +int main(int argc,char **argv){ +	if(argc!=2){ +		cerr<<"Pass fifo name as argument."<<endl; +		return 1; +	} +	ifstream fifo(argv[1]); +	assert(fifo.good()); +	while(!!fifo)cout<<(char)fifo.get()<<flush; +	return 0; +} diff --git a/gameserver/gameserver.html b/gameserver/gameserver.html index 7fc27fc..fdce5a8 100644 --- a/gameserver/gameserver.html +++ b/gameserver/gameserver.html @@ -39,6 +39,7 @@ function preinit(){  		var spaceidx=msg.indexOf(" "),  		    cmd=msg.slice(0,spaceidx),  		    arg=JSON.parse(msg.slice(spaceidx+1)); +		var alerttext;  		console.log(cmd,arg);  		if(cmd=="nick"){  			nick=arg; @@ -96,10 +97,11 @@ function preinit(){  		} else if(cmd=="game_win"){  			bgcell(neuidx).classList.add("win");  			if(arg==imPlayer){ -				alert("You have won the game!"); +				alerttext="You have won the game!";  			} else { -				alert("You have lost the game! Better luck next time."); +				alerttext="You have lost the game! Better luck next time.";  			} +			setTimeout(function(){alert(alerttext);},canclick?500:1000);  		} else alert("Unrecognised message "+msg);  	});  	ws.addEventListener("open",function(){ @@ -242,14 +244,18 @@ function enableClicking(en,disneu){  	en=en?true:false;  	disneu=disneu?true:false;  	for(i=0;i<8;i++){ -		document.getElementById("input_neudir"+i)[en&&!disneu?"removeAttribute":"setAttribute"]("disabled"); -		document.getElementById("input_dir"+i)[en?"removeAttribute":"setAttribute"]("disabled"); +		if(en&&!disneu)document.getElementById("input_neudir"+i).removeAttribute("disabled"); +		else document.getElementById("input_neudir"+i).setAttribute("disabled",""); +		if(en)document.getElementById("input_dir"+i).removeAttribute("disabled"); +		else document.getElementById("input_dir"+i).setAttribute("disabled","");  	}  	l=document.getElementsByName("inputstoneradio");  	for(i=0;i<l.length;i++){ -		l[i][en&&(imPlayer==-1||board[i]==imPlayer)?"removeAttribute":"setAttribute"]("disabled"); +		if(en&&(imPlayer==-1||board[i]==imPlayer))l[i].removeAttribute("disabled"); +		else l[i].setAttribute("disabled","");  	} -	document.getElementById("input_domovebtn")[en?"removeAttribute":"setAttribute"]("disabled"); +	if(en)document.getElementById("input_domovebtn").removeAttribute("disabled"); +	else document.getElementById("input_domovebtn").setAttribute("disabled","");  	clickenabled=[en,disneu];  } diff --git a/gameserver/gameserver.js b/gameserver/gameserver.js index 8ab4bbc..a9233e9 100755 --- a/gameserver/gameserver.js +++ b/gameserver/gameserver.js @@ -225,6 +225,7 @@ function handleMessage(conn,msg){  		c2.ws.send("other_turn "+JSON.stringify(mv));  		won=checkWin(game.board,3-game.onturn); //player that just moved  		if(won){ +			saveFinishedBoard(game.board);  			conn.ws.send("game_win "+won);  			c2.ws.send("game_win "+won);  			games.splice(findby(games,"id",conn.gameid),1); diff --git a/humanbot.cpp b/humanbot.cpp new file mode 100644 index 0000000..5902e24 --- /dev/null +++ b/humanbot.cpp @@ -0,0 +1,254 @@ +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cassert> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/stat.h> + +#define S (5) + +using namespace std; + +bool should_flip_board=false; + +struct Move; +class Board; + +Move protocol_get_move(istream &s); +void protocol_put_move(ostream &s,Move m); + +int index_deltas[8][2]={{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}}; + +struct Move{ +	int neudir,from,dir; +	string str(void){ +		stringstream ss; +		ss<<neudir<<' '<<from<<' '<<dir; +		return ss.str(); +	} +}; + +class Board{ +public: +	int grid[S*S]; +	int neuidx; +	Board(void):neuidx(S*(S/2)+S/2){ +		memset(grid,0,S*S*sizeof(int)); +		grid[S*(S/2)+S/2]=3; +		for(int i=0;i<S;i++){ +			grid[i]=1; +			grid[S*(S-1)+i]=2; +		} +	} +	int moved(int at,int dir){ +		int x=at%S,y=at/S,x2,y2; +		while(true){ +			x2=x+index_deltas[dir][0]; +			y2=y+index_deltas[dir][1]; +			if(x2<0||x2>=S||y2<0||y2>=S||grid[S*y2+x2]!=0)return S*y+x; +			x=x2; +			y=y2; +		} +	} +	bool move(int at,int dir){ +		int newat=moved(at,dir); +		if(newat==at)return false; +		grid[newat]=grid[at]; +		grid[at]=0; +		if(grid[newat]==3)neuidx=newat; +		return true; +	} +	void undomove(int at,int dir){ +		int movedidx=moved(at,dir); +		movedidx+=S*index_deltas[dir][1]+index_deltas[dir][0]; +		grid[at]=grid[movedidx]; +		grid[movedidx]=0; +		if(grid[at]==3)neuidx=at; +	} +	bool isvalid(Move mv){ +		int oldneuidx=neuidx; +		//cerr<<"Called isvalid with move "; +		//protocol_put_move(cerr,mv); +		//print(); +		if(!move(oldneuidx,mv.neudir)){ +			//undomove(oldneuidx,mv.neudir); +			return false; +		} +		if(!move(mv.from,mv.dir)){ +			//undomove(mv.from,mv.dir); +			undomove(oldneuidx,mv.neudir); +			return false; +		} +		undomove(mv.from,mv.dir); +		undomove(oldneuidx,mv.neudir); +		return true; +	} +	void print(void){ +		int x,y; +		if(should_flip_board){ +			for(y=S-1;y>=0;y--){ +				for(x=S-1;x>=0;x--)cerr<<grid[S*y+x]<<' '; +				cerr<<endl; +			} +		} else { +			for(y=0;y<S;y++){ +				for(x=0;x<S;x++)cerr<<grid[S*y+x]<<' '; +				cerr<<endl; +			} +		} +	} +}; + + +void restart_server(void); +void kill_server(void); + +ofstream othermovefifo; +ifstream mynewmovefifo; + +Move calculate_move(Board &bd){ +	cerr<<"c_m: restarting server..."<<endl; +	restart_server(); +	cerr<<"c_m: Waiting for move from fifo..."<<endl; +	Move mv=protocol_get_move(mynewmovefifo); +	cerr<<"c_m: Got move from fifo."<<endl; +	return mv; +} + +long server_pid=-1; +int server_port=-1; + +void setup_server(void){ +	unlink(".humanbot__.__othermove.fifo"); +	assert(mkfifo(".humanbot__.__othermove.fifo",0666)==0); + +	unlink(".humanbot__.__mynewmove.fifo"); +	assert(mkfifo(".humanbot__.__mynewmove.fifo",0666)==0); + +	server_port=42000+rand()%1000; + +	restart_server(); + +	//only now can we do this, 'cause unix doesn't let a fifo exist with only one end +	othermovefifo.open(".humanbot__.__othermove.fifo",ofstream::out|ofstream::app); +	mynewmovefifo.open(".humanbot__.__mynewmove.fifo"); +	cerr<<"Opened fifo's!"<<endl; +} + +void restart_server(void){ +	if(server_pid!=-1)kill_server(); +	pid_t cpid=fork(); +	assert(cpid!=-1); +	if(cpid==0){ //child +		cerr<<"Child!"<<endl; +		server_pid=(long)getpid(); +		char *portstr; +		asprintf(&portstr,"%d",server_port); +		assert(!!portstr); +		execl("/usr/bin/env","node","./humanbot_server.js",portstr,NULL); +		perror("execlp"); +		exit(1); +	} +	cerr<<"Parent!"<<endl; +} + +void kill_server(void){ +	kill(server_pid,SIGTERM); //stay friendly +	usleep(100*1000); //100ms +	kill(server_pid,SIGINT); +	usleep(1000*1000); //1s +} + + +inline int flip_index(int idx){ +	return S*(S-1-idx/S)+S-1-idx%S; +} +inline int flip_dir(int dir){ +	return dir==-1?-1:(dir+4)%8; +} + +Move protocol_get_move(istream &s){ +	Move m; +	/*char c=s.peek(); +	if(c=='q'||c=='Q')exit(0);*/ +	cerr<<"Sleeping."<<endl; +	system("sleep 10"); +	s>>m.neudir>>m.from>>m.dir; +	if(should_flip_board){ +		m.neudir=flip_dir(m.neudir); +		m.from=flip_index(m.from); +		m.dir=flip_dir(m.dir); +	} +	cerr<<"Got: "; +	protocol_put_move(cerr,m); +	s.ignore(1024,'\n'); +	return m; +} + +void protocol_put_move(ostream &s,Move m){ +	if(should_flip_board){ +		s<<flip_dir(m.neudir)<<' '<<flip_index(m.from)<<' '<<flip_dir(m.dir)<<endl; +	} else { +		s<<m.neudir<<' '<<m.from<<' '<<m.dir<<endl; +	} +} + +int main(void){ +	Board bd; +	Move mv; +	string line; +	struct timeval tv; +	gettimeofday(&tv,NULL); +	cerr<<"seed="<<(1000000*tv.tv_sec+tv.tv_usec)<<endl; +	srand(1000000*tv.tv_sec+tv.tv_usec); +	//srand(1430130052185291); +	setup_server(); +	getline(cin,line); +	if(line=="go"){ +		othermovefifo<<"go"<<endl; +		should_flip_board=false; +		//mv.neudir=-1; mv.from=1; mv.dir=3; +		mv=calculate_move(bd); +		bd.move(mv.from,mv.dir); +		protocol_put_move(cout,mv); +	} else { +		if(line!="nogo")cerr<<"no0b "<<line<<" not in (go,nogo)"<<endl; +		othermovefifo<<"nogo"<<endl; +		should_flip_board=true; +		mv=protocol_get_move(cin); +		protocol_put_move(othermovefifo,mv); +		bd.move(mv.from,mv.dir); +		bd.print(); +		mv=calculate_move(bd); +		if(!bd.isvalid(mv)){ +			cerr<<"calculate_move gave invalid move "<<mv.str()<<endl; +			return 1; +		} +		bd.move(bd.neuidx,mv.neudir); +		bd.move(mv.from,mv.dir); +		protocol_put_move(cout,mv); +	} +	while(true){ +		bd.print(); +		mv=protocol_get_move(cin); +		protocol_put_move(othermovefifo,mv); +		bd.move(bd.neuidx,mv.neudir); +		bd.move(mv.from,mv.dir); +		bd.print(); +		mv=calculate_move(bd); +		if(!bd.isvalid(mv)){ +			cerr<<"calculate_move gave invalid move "<<mv.str()<<endl; +			return 1; +		} +		bd.move(bd.neuidx,mv.neudir); +		bd.move(mv.from,mv.dir); +		protocol_put_move(cout,mv); +	} +	return 0; +} diff --git a/humanbot_index.html b/humanbot_index.html new file mode 100644 index 0000000..7d05c7a --- /dev/null +++ b/humanbot_index.html @@ -0,0 +1,543 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Game</title> +<script> +var S=5; +var PLAYERS=["Player 1","Player 2"]; +var MOVES=[];//[[-1,1,3],[7,23,0],[0,0,3]]; + + +var moveidx=0; +var neuidxhist=[]; + +var board=Array.apply(null,new Array(S*S)).map(function(){return 0;}); +var fgcells=board.map(function(){return null;}); +var neuidx; + +var canclick=false; + +var imPlayer=-1; + +var othermovefifo_interval=null; + +var clickenabled=[false,false]; +var input_neudir_choice=null,input_dir_choice=null,input_stone_choice=null; + +function init(){ +	var tr,td,y,x,e,span, +	    movelisttbody, +	    header=document.getElementById("header"), +	    status=document.getElementById("status"), +	    movelist=document.getElementById("movelist"), +	    bgtbody=document.getElementById("bgtbody"); + +	document.title="Game: "+PLAYERS[0]+" vs "+PLAYERS[1]; + +	header.appendChild(document.createTextNode("Game: ")); +	span=document.createElement("span"); +	span.classList.add("celltypeclr"); span.classList.add("celltypeclr_1"); +	span.appendChild(document.createTextNode(PLAYERS[0])); +	header.appendChild(span); +	header.appendChild(document.createTextNode(" vs ")); +	span=document.createElement("span"); +	span.classList.add("celltypeclr"); span.classList.add("celltypeclr_2"); +	span.appendChild(document.createTextNode(PLAYERS[1])); +	header.appendChild(span); + + +	e=document.createElement("table"); +	movelisttbody=document.createElement("tbody"); +	movelisttbody.id="movelisttbody"; +	tr=document.createElement("tr"); +	td=document.createElement("td"); td.innerHTML="Player"; tr.appendChild(td); +	td=document.createElement("td"); td.innerHTML="Neutron"; tr.appendChild(td); +	td=document.createElement("td"); td.innerHTML="Stone"; tr.appendChild(td); +	movelisttbody.appendChild(tr); +	e.appendChild(movelisttbody); +	movelist.appendChild(e); + +	tr=document.createElement("tr"); +	td=document.createElement("td"); +	td.setAttribute("colspan","3"); +	td.innerHTML=" "; +	tr.appendChild(td); +	(function(tr){ +		tr.addEventListener("click",function(ev){ +			if(moveidx==0)return; +			while(moveidx>0)prevmove(true); +			setselectedmovelistline(0); +		}); +	})(tr); +	tr.classList.add("selected"); +	movelisttbody.appendChild(tr); + +	MOVES.forEach(function(mv,i){ +		addmovelistrow(mv,i); +	}); + + +	var inputstonetbody=document.getElementById("inputstonetbody"); +	for(y=0;y<S;y++){ +		tr=document.createElement("tr"); +		for(x=0;x<S;x++){ +			td=document.createElement("td"); +			e=document.createElement("input"); +			e.setAttribute("type","radio"); +			e.setAttribute("name","inputstoneradio"); +			e.addEventListener("click",(function(x,y){return function(){ +				input_stone_choice=S*y+x; +			};})(x,y)); +			td.appendChild(e); +			tr.appendChild(td); +		} +		inputstonetbody.appendChild(tr); +	} + + +	for(y=0;y<S;y++){ +		tr=document.createElement("tr"); +		for(x=0;x<S;x++){ +			td=document.createElement("td"); +			td.classList.add("bgcell"); +			td.innerHTML=S*y+x; +			tr.appendChild(td); +		} +		bgtbody.appendChild(tr); +	} +	for(x=0;x<S;x++){ +		board[x]=1; +		e=makefgcell(x,1); +		fgcells[x]=e; +		document.body.appendChild(e); + +		board[S*(S-1)+x]=2; +		e=makefgcell(S*(S-1)+x,2); +		fgcells[S*(S-1)+x]=e; +		document.body.appendChild(e); +	} +	neuidx=S*~~(S/2)+~~(S/2); +	board[neuidx]=3; +	e=makefgcell(neuidx,3); +	fgcells[neuidx]=e; +	document.body.appendChild(e); + +	setnextenabled(MOVES.length>0); +	setprevenabled(false); +	canclick=true; + +	othermovefifo_interval=setInterval(function(){ +		if(clickenabled[0]||clickenabled[1])return; +		var xhr=new XMLHttpRequest(); +		xhr.addEventListener("readystatechange",function(){ +			if(this.readyState!=4)return; +			console.log("othermove",this.status,this.responseText); +			if(this.status!=200)return; +			if(this.responseText=="go"){ +				enableClicking(true,true); //2nd true is to disable neutron dir +				imPlayer=1; +			} else if(this.responseText=="nogo"){ +				enableClicking(false); +				imPlayer=2; +			} else { +				var mv=JSON.parse(this.responseText); +				MOVES.push(mv); +				addmovelistrow(mv); +				nextmove(); +				enableClicking(true); +			} +		}); +		xhr.open("GET",location.protocol+"//"+location.host+"/othermove"); +		xhr.send(); +	},1500); + +	enableClicking(false); +} + +function enableClicking(en,disneu){ +	var i,l; +	en=en?true:false; +	disneu=disneu?true:false; +	for(i=0;i<8;i++){ +		document.getElementById("input_neudir"+i)[en&&!disneu?"removeAttribute":"setAttribute"]("disabled"); +		document.getElementById("input_dir"+i)[en?"removeAttribute":"setAttribute"]("disabled"); +	} +	l=document.getElementsByName("inputstoneradio"); +	for(i=0;i<l.length;i++){ +		l[i][en&&(imPlayer==-1||board[i]==imPlayer)?"removeAttribute":"setAttribute"]("disabled"); +	} +	document.getElementById("input_domovebtn")[en?"removeAttribute":"setAttribute"]("disabled"); +	clickenabled=[en,disneu]; +} + +function addmovelistrow(mv,i/*optional*/){ +	var tr,td; +	var movelisttbody=document.getElementById("movelisttbody"); +	var i=i!=undefined?i:movelisttbody.children.length; +	tr=document.createElement("tr"); + +	td=document.createElement("td"); +	td.innerHTML=i%2+1; +	tr.appendChild(td); + +	td=document.createElement("td"); +	if(mv[0]==-1)td.innerHTML=" "; +	else td.innerHTML=arrowfor(mv[0]); +	tr.appendChild(td); + +	td=document.createElement("td"); +	td.innerHTML=mv[1]+": "+arrowfor(mv[2]); +	tr.appendChild(td); + +	tr.addEventListener("click",(function(target){return function(ev){ +		if(moveidx==target)return; +		while(moveidx<target)nextmove(true); +		while(moveidx>target)prevmove(true); +		setselectedmovelistline(i+1); +	};})(i+1)); + +	movelisttbody.appendChild(tr); +} + +function setselectedmovelistline(i){ +	var movelist=document.getElementById("movelist"); +	movelist.querySelectorAll("tr.selected")[0].classList.remove("selected"); +	document.getElementById("movelist").getElementsByTagName("tr")[i+1].classList.add("selected"); +} + +function arrowfor(dir){ +	return "&#x"+[2191,2197,2192,2198,2193,2199,2190,2196][dir]+";"; +} + +function bgcell(idx){ +	return document.getElementById("bgtbody").children[idx/S|0].children[idx%S]; +} +function fgcellposition(idx){ +	var rect=bgcell(idx).getBoundingClientRect(), +	    scrolltop=window.pageYOffset||document.documentElement.scrollTop; +	return [rect.left,rect.top+scrolltop]; +} +function movefgcell(e,idx){ +	var pos=fgcellposition(idx); +	e.style.left=pos[0]+"px"; +	e.style.top=pos[1]+"px"; +	e.cell_index=idx; +} +function makefgcell(idx,type){ //type in [1,2,3] +	var pos=fgcellposition(idx), +	    e=document.createElement("div"); +	e.classList.add("fgcell"); +	e.classList.add("celltype_"+type); +	e.setAttribute("style","left:"+pos[0]+"px;top:"+pos[1]+"px;"); +	e.cell_index=idx; +	e.appendChild(document.createElement("div")); +	return e; +} + +var index_deltas=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]]; +function indexafterslide(from,dir,overshoot){ +	var x=from%S,y=~~(from/S),x2,y2; +	while(true){ +		x2=x+index_deltas[dir][0]; +		y2=y+index_deltas[dir][1]; +		if(x2<0||x2>=S||y2<0||y2>=S||board[S*y2+x2]!=0){ +			if(overshoot)return S*y2+x2; +			else return S*y+x; +		} +		x=x2; +		y=y2; +	} +} + +function setnextenabled(en){ +	document.getElementById("nextmovebtn").disabled=!en; +} +function setprevenabled(en){ +	document.getElementById("prevmovebtn").disabled=!en; +} + +function nextmove(notimeout){ +	var newidx; +	if(moveidx==MOVES.length||!canclick)return false; + +	if(MOVES[moveidx][0]!=-1){ +		neuidxhist.push(neuidx); +		newidx=indexafterslide(neuidx,MOVES[moveidx][0]); +		movefgcell(fgcells[neuidx],newidx); +		board[newidx]=board[neuidx]; +		board[neuidx]=0; +		fgcells[newidx]=fgcells[neuidx]; +		fgcells[neuidx]=null; +		neuidx=newidx; + +		if(moveidx==MOVES.length-1)bgcell(neuidx).classList.add("win"); +	} + +	newidx=indexafterslide(MOVES[moveidx][1],MOVES[moveidx][2]); +	if(MOVES[moveidx][0]!=-1&&!notimeout){ +		setTimeout( +			(function(e,idx){return function(){ +				movefgcell(e,idx); +				canclick=true; +			};})(fgcells[MOVES[moveidx][1]],newidx), +			500 +		); +		canclick=false; +	} else { +		movefgcell(fgcells[MOVES[moveidx][1]],newidx); +	} +	board[newidx]=board[MOVES[moveidx][1]]; +	board[MOVES[moveidx][1]]=0; +	fgcells[newidx]=fgcells[MOVES[moveidx][1]]; +	fgcells[MOVES[moveidx][1]]=null; + +	moveidx++; +	setprevenabled(true); +	if(moveidx==MOVES.length)setnextenabled(false); +	if(!notimeout)setselectedmovelistline(moveidx); +	return true; +} +function prevmove(notimeout){ +	var item,oldneuidx,newidx,winGlowIdxToRemove=null; +	if(moveidx==0||!canclick)return false; +	moveidx--; + +	if(MOVES[moveidx][0]!=-1&&moveidx==MOVES.length-1)winGlowIdxToRemove=neuidx; + +	newidx=indexafterslide(MOVES[moveidx][1],MOVES[moveidx][2],true); +	board[MOVES[moveidx][1]]=board[newidx]; +	board[newidx]=0; +	fgcells[MOVES[moveidx][1]]=fgcells[newidx]; +	fgcells[newidx]=null; +	movefgcell(fgcells[MOVES[moveidx][1]],MOVES[moveidx][1]); + +	if(MOVES[moveidx][0]!=-1){ +		oldneuidx=neuidxhist.pop(); +		board[oldneuidx]=board[neuidx]; +		board[neuidx]=0; +		fgcells[oldneuidx]=fgcells[neuidx]; +		fgcells[neuidx]=null; +		if(notimeout){ +			movefgcell(fgcells[oldneuidx],oldneuidx); +			if(winGlowIdxToRemove!=null)bgcell(winGlowIdxToRemove).classList.remove("win"); +		} else { +			setTimeout( +				(function(e,idx){return function(){ +					movefgcell(e,idx); +					canclick=true; +					if(winGlowIdxToRemove!=null)bgcell(winGlowIdxToRemove).classList.remove("win"); +				};})(fgcells[oldneuidx],oldneuidx), +				500 +			); +			canclick=false; +		} +		neuidx=oldneuidx; +	} + +	setnextenabled(true); +	if(moveidx==0)setprevenabled(false); +	if(!notimeout)setselectedmovelistline(moveidx); +	return true; +} + + +function input_neudir(dir){ +	var i; +	for(i=0;i<8;i++){ +		if(i==dir)document.getElementById("input_neudir"+i).classList.add("selected"); +		else document.getElementById("input_neudir"+i).classList.remove("selected"); +	} +} + +function input_dir(dir){ +	var i; +	for(i=0;i<8;i++){ +		if(i==dir)document.getElementById("input_dir"+i).classList.add("selected"); +		else document.getElementById("input_dir"+i).classList.remove("selected"); +	} +} + +function input_domove(){ +	var i,l,mv=[-1,-1,-1]; +	for(i=0;i<8;i++){ +		if(document.getElementById("input_neudir"+i).classList.contains("selected")){ +			mv[0]=i; +			break; +		} +	} +	for(i=0;i<8;i++){ +		if(document.getElementById("input_dir"+i).classList.contains("selected")){ +			mv[2]=i; +			break; +		} +	} +	l=document.getElementsByName("inputstoneradio"); +	for(i=0;i<l.length;i++){ +		if(l[i].checked){ +			mv[1]=i; +			break; +		} +	} +	if(mv[0]==-1&&!clickenabled[1]){alert("Neutron direction not set!");return;} +	if(mv[1]==-1){alert("Stone choice not set!");return;} +	if(mv[2]==-1){alert("Stone direction not set!");return;} +	var clickenabledcache=clickenabled; +	enableClicking(false); +	var xhr=new XMLHttpRequest(); +	xhr.addEventListener("readystatechange",function(){ +		if(this.readyState!=4)return; +		console.log("mynewmove",this.status,this.responseText); +		if(this.status!=200){ +			alert("Failed to submit move!"); +			enableClicking.apply(this,clickenabledcache); +		} else { +			MOVES.push(mv); +			addmovelistrow(mv); +			nextmove(); +		} +	}); +	xhr.open("POST",location.protocol+"//"+location.host+"/mynewmove"); +	xhr.send(JSON.stringify(mv)); +} + + +window.addEventListener("load",init,false); +</script> +<style> +body{ +	font-family:Georgia,Times,Serif; +	font-size:15px; +} + +table#bgtab{ +	border-spacing:4px; +} +td.bgcell{ +	width:80px; +	height:80px; +	border:3px #ddd solid; +	border-radius:12px; +	transition:background-color 0.6s ease 0.2s, box-shadow 0.6s ease 0.2s, -webkit-box-shadow 0.6s ease 0.2s; + +	text-align:right; +	vertical-align:bottom; +	font-size:14px; +} +td.bgcell.win{ +	background-color:#8f8; +	        box-shadow:inset 0 0 6px #6e6; +	-webkit-box-shadow:inset 0 0 6px #6e6; +} +div.fgcell{ +	position:absolute; +	width:82px; +	height:82px; +	border:3px rgba(0,0,0,0) solid; +	text-align:center; +	transition:left 0.6s ease 0s, top 0.6s ease 0s; +} + +div.fgcell > div{ +	height:75%; +	margin:10px; +	border-radius:30px; +} + +h1#header{ +	letter-spacing:0.5px; +} +span.celltypeclr{ +	border-radius:5px; +	padding:4px; +} + +div#status{ +	font-size:16px; +	font-weight:bold; +} + +div.fgcell.celltype_1 > div{background-color:#ddd;} +span.celltypeclr_1         {background-color:#ddd;} +div.fgcell.celltype_2 > div{background-color:#2a2a2a;} +span.celltypeclr_2         {background-color:#2a2a2a;color:#eee;} +div.fgcell.celltype_3 > div{background-color:#11e;} + +div#movelist{ +	border:1px black solid; +	width:500px; +	height:200px; +	overflow-y:scroll; +} +div#movelist table{ +	border-spacing:0; +	width:100%; +} +div#movelist tr:first-child{ +	font-weight:bold; +	background-color:#ccc; +} +div#movelist tr:first-child > td{ +	border-bottom:1px black solid; +} +div#movelist tr:nth-child(odd){background-color:#e4e4e4;} +div#movelist tr:nth-child(even){background-color:#fff;} +div#movelist tr:nth-child(n+2):hover{background-color:#bbf;cursor:pointer;} +div#movelist tr.selected{ +	background-color:#afa; +} + +input[type=button].selected{ +	background-color:#aaf; +} +</style> +</head> +<body> +<h1 id="header"></h1> +<table id="bgtab" style="display:inline-block"><tbody id="bgtbody"></tbody></table> +<table id="inputneudirtab" style="display:inline-block"><tbody id="inputneudirtbody"> +	<tr> +		<td><input type="button" id="input_neudir7" value="↖" onclick="input_neudir(7)"></td> +		<td><input type="button" id="input_neudir0" value="↑" onclick="input_neudir(0)"></td> +		<td><input type="button" id="input_neudir1" value="↗" onclick="input_neudir(1)"></td> +	</tr> +	<tr> +		<td><input type="button" id="input_neudir6" value="←" onclick="input_neudir(6)"></td> +		<td>Neu</td> +		<td><input type="button" id="input_neudir2" value="→" onclick="input_neudir(2)"></td> +	</tr> +	<tr> +		<td><input type="button" id="input_neudir5" value="↙" onclick="input_neudir(5)"></td> +		<td><input type="button" id="input_neudir4" value="↓" onclick="input_neudir(4)"></td> +		<td><input type="button" id="input_neudir3" value="↘" onclick="input_neudir(3)"></td> +	</tr> +</tbody></table> +<table id="inputdirtab" style="display:inline-block;margin-left:20px"><tbody id="inputdirtbody"> +	<tr> +		<td><input type="button" id="input_dir7" value="↖" onclick="input_dir(7)"></td> +		<td style="text-align:center"><input type="button" id="input_dir0" value="↑" onclick="input_dir(0)"></td> +		<td><input type="button" id="input_dir1" value="↗" onclick="input_dir(1)"></td> +	</tr> +	<tr> +		<td><input type="button" id="input_dir6" value="←" onclick="input_dir(6)"></td> +		<td> +			<table id="inputstonetab" style="display:inline-block"><tbody id="inputstonetbody"></tbody></table> +		</td> +		<td><input type="button" id="input_dir2" value="→" onclick="input_dir(2)"></td> +	</tr> +	<tr> +		<td><input type="button" id="input_dir5" value="↙" onclick="input_dir(5)"></td> +		<td style="text-align:center"><input type="button" id="input_dir4" value="↓" onclick="input_dir(4)"></td> +		<td><input type="button" id="input_dir3" value="↘" onclick="input_dir(3)"></td> +	</tr> +</tbody></table> +<div style="display:inline-block;margin-left:10px"> +	<input type="button" id="input_domovebtn" value="Do move" onclick="input_domove()"> +	<br> +</div> +<br> +<input type="button" id="prevmovebtn" onclick="prevmove()" value="←"> +<input type="button" id="nextmovebtn" onclick="nextmove()" value="→"><br> +<div id="movelist" style="margin-top:30px"></div> +</body> +</html> diff --git a/humanbot_server.js b/humanbot_server.js new file mode 100755 index 0000000..3f38f66 --- /dev/null +++ b/humanbot_server.js @@ -0,0 +1,74 @@ +#!/usr/bin/env node +var http=require("http"),fs=require("fs"); +var PORT=+process.argv[2]; +var movequeue=[]; +var httpserver=http.createServer(function(req,res){ +	var reqbody=""; +	console.log("req: "+req.url); +	if(req.url=="/othermove"){ +		if(movequeue.length){ +			res.writeHead(200,{"Content-Type":"application/json"}); +			res.end(movequeue.shift()); +		} else { +			res.writeHead(503,{"Content-Type":"text/plain"}); +			res.end("No move to unqueue"); +		} +	} else if(req.url=="/mynewmove"){ +		req.on("data",function(data){reqbody+=data;}); +		req.on("end",function(){ +			var mv; +			console.log("mynewmove: reqbody = "+reqbody); +			try {mv=JSON.parse(reqbody);} +			catch(e){mv=null;} +			if(mv==null|| +				!Array.isArray(mv)|| +				mv.length!=3|| +				!mv.map(function(v){ +					return typeof(v)=="number"&&v%1==0; +				}).reduce(function(a,b){return a&&b;}) +			){ +				res.writeHead(400,{"Content-Type":"text/plain"}); +				res.end("400 Bad request"); +				return; +			} +			mynewmovefifo.write(mv.join(" ")+"\n",function(){ +				console.log("server: ACTUALLY written new move to fifo"); +			}); +			res.writeHead(200,{"Content-Type":"text/plain"}); +			res.end("true"); +		}); +	} else if(req.url=="/"){ +		res.writeHead(200,{"Content-Type":"text/html"}); +		res.end(String(fs.readFileSync("humanbot_index.html"))); +	} else { +		res.writeHead(404,{"Content-Type":"text/plain"}); +		res.end("Nothing here..."); +	} +}); +var httpserverlisteninterval=setInterval(function(){ +	try { +		httpserver.listen(PORT); +		console.log("Server running at port "+PORT+". (http://localhost:"+PORT+")"); +		clearInterval(httpserverlisteninterval); +	} catch(e){} +},10); + +var othermovefifo,mynewmovefifo,othermovefifo_buffer=""; +othermovefifo=fs.createReadStream(".humanbot__.__othermove.fifo"); +othermovefifo.on("data",function(data){ +	var idx,v; +	othermovefifo_buffer+=data; +	idx=othermovefifo_buffer.indexOf("\n"); +	if(idx!=-1){ +		v=othermovefifo_buffer.slice(0,idx); +		if(v!="go"&&v!="nogo")v="["+v.replace(/ /g,",")+"]"; +		movequeue.push(v); +		othermovefifo_buffer=othermovefifo_buffer.slice(idx+1); +	} +}); +othermovefifo.on("end",function(){ +	console.log("othermovefifo closed. Exiting."); +	process.exit(); +}); +mynewmovefifo=fs.createWriteStream(".humanbot__.__mynewmove.fifo",{flags:"a"}); +console.log("Fifo's opened.");  | 
