diff options
Diffstat (limited to 'gameserver/gameserver.js')
-rwxr-xr-x | gameserver/gameserver.js | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/gameserver/gameserver.js b/gameserver/gameserver.js new file mode 100755 index 0000000..ddc6f0b --- /dev/null +++ b/gameserver/gameserver.js @@ -0,0 +1,251 @@ +#!/usr/bin/env node + +"use strict"; + +var fs=require("fs"), + http=require("http"), + util=require("util"), + assert=require("assert"), + WebSocketServer=require("ws").Server, + Naampje=require("naampje").name; +var HTTPPORT=83,WSPORT=8383; + +var conns=[],games=[]; + +var genid=(function(){ + var $=1; + return function(){return $++;}; +})(); + +function findby(a,key,val){ + for(var i=0;i<a.length;i++)if(a[i][key]==val)return i; + return -1; +} + +function nickIsTaken(nick){ + var i; + for(i=0;i<conns.length;i++)if(conns[i].nick==nick)return true; + return false; +} + +function numberiseNick(nick){ + var i; + for(i=0;;i++){ + if(!nickIsTaken(nick+i))return nick+i; + } +} + +function gennick(){ + var i,nick; + for(i=0;i<10;i++){ + nick=Naampje(); + if(!nickIsTaken(nick))break; + } + if(i<10)return nick; + else return numberiseNick(nick); +} + +function Connection(ws){ + if(!(this instanceof Connection))return new Connection(ws); + this.id=genid(); + this.nick=gennick(); + this.ws=ws; + this.gameid=null; +} + +function Game(c1,c2){ + if(!(this instanceof Game))return new Game(c1,c2); + this.id=genid(); + this.i1=c1.id; + this.i2=c2.id; + this.board=[1,1,1,1,1, + 0,0,0,0,0, + 0,0,3,0,0, + 0,0,0,0,0, + 2,2,2,2,2]; + this.onturn=1; //1 or 2 + this.firstmove=true; //in first move, neudir==-1 +} + +function saveFinishedBoard(bd){ + var fname=process.hrtime(); + if(fs.existsSync("winboards")){ + if(!fs.lstatPath("winboards").isDirectory()){ + console.log("winboards is not a directory. Bleh."); + return; + } + } else { + fs.mkdirSync("winboards"); + } + fname="winboards/"+fname[0]+("000000000"+fname[1]).slice(-9)+".txt"; + if(fs.existsSync(fname)){ //don't think this'll happen often + console.log("saveFinishedBoard: file '"+fname+"' already exists!"); + return; + } + fs.writeFileSync(fname,bd.join("")); +} + +var idxAfterSlide__xy_deltas=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]]; +function idxAfterSlide(bd,idx,dir){ + var x=idx%5,y=~~(idx/5),x2,y2,d=idxAfterSlide__xy_deltas[dir],dx=d[0],dy=d[1]; + while(true){ + x2=x+dx; y2=y+dy; + if(x2<0||x2>=5||y2<0||y2>=5||bd[5*y2+x2]!=0)return 5*y+x; + x=x2; y=y2; + } +} + +function applyMove(bd,mv){ + var neuidx=-1,newidx,i; + bd=bd.slice(); + for(i=0;i<25;i++)if(bd[i]==3){neuidx=i;break;} + assert(neuidx!=-1); + if(mv[0]!=-1){ + newidx=idxAfterSlide(bd,neuidx,mv[0]); + bd[newidx]=3; + bd[neuidx]=0; + } + if(mv[1]!=-1&&mv[2]!=-1){ + newidx=idxAfterSlide(bd,mv[1],mv[2]); + bd[newidx]=bd[mv[1]]; + bd[mv[1]]=0; + } + return bd; +} + +function moveIsLegal(bd,mv,forpl){ + var neuidx=-1,newidx,i; + if(bd[mv[1]]!=forpl)return false; + for(i=0;i<25;i++)if(bd[i]==3){neuidx=i;break;} + assert(neuidx!=-1); + if(mv[0]!=-1){ + newidx=idxAfterSlide(bd,neuidx,mv[0]); + if(newidx==neuidx)return false; + } + newidx=idxAfterSlide(applyMove(bd,[mv[0],-1,-1]),mv[1],mv[2]); + if(newidx==mv[1])return false; + return true; +} + +function handleMessage(conn,msg){ + var cmd=msg.split(" "),list,i,game,c2,mv; + switch(cmd[0]){ + case "nick": + conn.ws.send("nick \""+conn.nick+"\""); + break; + /*case "list_free_users": + list=[]; + for(i=0;i<conns.length;i++)if(conns[i].gameid==null)list.push(conns[i].nick); + conn.ws.send("list_free_users "+JSON.stringify(list)); + break;*/ + case "game_create": + c2=cmd.slice(1).join(" "); + if(conn.gameid!=null){ + conn.ws.send("game_create [false,\"Already in a game\"]"); + break; + } + if(c2==conn.nick){ + conn.ws.send("game_create [false,\"Cannot create a game with yourself\"]"); + break; + } + c2=findby(conns,"nick",c2); + if(c2==-1){ + conn.ws.send("game_create [false,\"Non-existent nick\"]"); + break; + } + c2=conns[c2]; + if(c2.gameid!=null){ + conn.ws.send("game_create [false,\"Other already in a game\"]"); + break; + } + console.log("new game between "+conn.nick+" and "+c2.nick); + game=new Game(conn,c2); + conn.gameid=game.id; + c2.gameid=game.id; + games.push(game); + conn.ws.send("game_create true"); + c2.ws.send("joined_game true"); + conn.ws.send("your_turn false"); + break; + case "game_info": + if(conn.gameid==null){ + conn.ws.send("game_info null"); + break; + } + game=games[findby(games,"id",conn.gameid)]; + conn.ws.send("game_info "+JSON.stringify([ + [ + conns[findby(conns,"id",game.i1)].nick, + conns[findby(conns,"id",game.i2)].nick + ], + game.board, + game.onturn + ])); + break; + case "game_doturn": //neudir stoneidx stonedir + if(conn.gameid==null){ + conn.ws.send("game_doturn [false,\"Not in a game\"]"); + break; + } + game=games[findby(games,"id",conn.gameid)]; + mv=[+cmd[1],+cmd[2],+cmd[3]]; + if(mv[0]==undefined||isNaN(mv[0])||mv[0]%1!=0|| + (game.firstmove ? mv[0]!=-1 : mv[0]<0||mv[0]>=8) || + mv[1]==undefined||isNaN(mv[1])||mv[1]%1!=0||mv[1]<0||mv[1]>=25|| + mv[2]==undefined||isNaN(mv[2])||mv[2]%1!=0||mv[2]<0||mv[2]>=8){ + conn.ws.send("game_doturn [false,\"Invalid move\"]"); + break; + } + if(!moveIsLegal(game.board,mv,game.onturn)){ + conn.ws.send("game_doturn [false,\"Illegal move\"]"); + break; + } + game.board=applyMove(game.board,mv); + console.log("new board:"); + console.log(game.board); + game.onturn=3-game.onturn; + conn.ws.send("game_doturn "+JSON.stringify([true,mv])); + c2=conns[findby(conns,"id",conn.id==game.i1?game.i2:game.i1)]; + c2.ws.send("your_turn "+JSON.stringify(mv)); + game.firstmove=false; + break; + default: + conn.ws.send("error "+cmd[0]); + break; + } +} + +new WebSocketServer({port:WSPORT}).on("connection",function(ws){ + var conn=new Connection(ws); + conns.push(conn); + ws.on("message",function(msg){ + console.log(msg,util.inspect(conn,{depth:0})); + handleMessage(conn,msg); + }); + ws.on("open",function(){ + //hi! + }); + ws.on("close",function(){ + if(conn.gameid!=null){ + var gameidx=findby(games,"id",conn.gameid); + var game=games[gameidx]; + var otherplayeridx=findby(conns,"id",game.i1==conn.id?game.i2:game.i1) + console.log("otherplayeridx="+otherplayeridx); + conns[otherplayeridx].gameid=null; + conn.gameid=null; + games.splice(gameidx,1); + } + }); +}); +console.log("Websocket server started on port "+WSPORT+"."); + +http.createServer(function(req,res){ + if(req.url=="/"){ + res.writeHead(200,{"Content-Type":"text/html"}); + res.end(String(fs.readFileSync("gameserver.html"))); + } else { + res.writeHead(404,{"Content-Type":"text/plain"}); + res.end("404 Not found"); + } +}).listen(HTTPPORT); +console.log("HTTP server started on port "+HTTPPORT+"."); |