diff options
author | tomsmeding <tom.smeding@gmail.com> | 2016-12-23 21:40:46 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2016-12-23 21:40:46 +0100 |
commit | c8a692cf39979962c72e8d3ec9108b85105feeb0 (patch) | |
tree | 7bee3cf35e72bffcf0112573964c6057568b2925 | |
parent | 864bce4ebdc625468969891b36784490448ceea3 (diff) |
-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."); |