diff options
author | tomsmeding <hallo@tomsmeding.nl> | 2015-12-05 20:40:32 +0100 |
---|---|---|
committer | tomsmeding <hallo@tomsmeding.nl> | 2015-12-05 20:40:32 +0100 |
commit | 1954ed67ef61c509560418a9d2da58083b822996 (patch) | |
tree | 870237504df86fcdd6cfaab2948e73e7211cf95d /index.js |
Initial enzo
Diffstat (limited to 'index.js')
-rwxr-xr-x | index.js | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/index.js b/index.js new file mode 100755 index 0000000..d2432ac --- /dev/null +++ b/index.js @@ -0,0 +1,248 @@ +#!/usr/bin/env node + +"use strict"; + +var app=require("express")(), + http=require("http").Server(app), + io=require("socket.io")(http), + fs=require("fs"), + spawn=require("child_process").spawn, + mkdirp=require("mkdirp"), + C=require("./common.js"); + + +var HTTPPORT=8090; + +var uniqid=(function(){ + var id=0; + return function(){return id++;}; +})(); + +app.get("/",function(req,res){ + res.sendFile(__dirname+"/index.html"); +}); + +["index.html","common.js"].forEach(function(fname){ + app.get("/"+fname,function(req,res){ + res.sendFile(__dirname+"/"+fname); + }); +}); + +function Game(_np){ + if(!(this instanceof Game))return new Game(_np); + this.bd=emptyboard(); + this.np=np; + this.onturn=0; +} +Game.prototype.applymove=function(player,pos){ + if(this.onturn!=player)return false; + var x=pos%C.W,y=~~(pos/C.W); + if(this.bd[y][x].n&&this.bd[y][x].c!=player)return false; + this.bd[y][x].c=player; + this.bd[y][x].n++; + this.bd=C.stabilise(this.bd); + do this.onturn=(this.onturn+1)%this.np; + while C.countballs(this.bd,this.onturn)==0; + return true; +}; +Game.prototype.checkwin=function(){ + if(C.countballs(this.bd)<this.np)return -1; + return C.checkwin(this.bd); +}; + +var connlist=[]; //sorted on id, because uniqid is strictly increasing +var rooms={}; //{<roomid>: {ids:[id's], game:Game}} + +function findid(id){ + var lo=0,mid,hi=connlist.length-1; + if(connlist[lo].id==id)return lo; + if(connlist[hi].id==id)return hi; + while(lo<hi){ + mid=lo+(hi-lo)/2|0; + if(connlist[mid].id==id)return mid; + if(connlist[mid].id<id)lo=mid+1; + else hi=mid-1; + } + if(hi<lo||connlist[lo].id!=id)return -1; //not found + return lo; +} + +function findname(name){ + var i; + for(i=0;i<connlist.length;i++)if(connlist[i].name==name)return i; + return -1; +} + +io.on("connection",function(conn){ + var obj={ + id:uniqid(), + name:"user", + conn:conn, + rooms:[], + pending:[] + }; + obj.name+=obj.id; + connlist.push(obj); + conn.emit("me",[obj.id,obj.name]); + io.emit("userlist",connlist.map(function(o){return [o.id,o.name];})); + + conn.on("disconnect",function(){ + var idx=findid(obj.id); + if(idx==-1)return; //WAT + obj.pending.forEach(function(pendid){ + io.to(pendid).emit("roomdestroy",pendid); + rooms[pendid].ids.forEach(function(id){ + var o=connlist[findid(id)]; + o.conn.leave(pendid); + o.rooms.splice(o.rooms.indexOf(pendid),1); + }); + delete rooms[pendid]; + }); + obj.rooms.forEach(function(roomid){ + io.to(roomid).emit("roomdestroy",roomid); + rooms[roomid].ids.forEach(function(id){ + var o=connlist[findid(id)]; + o.conn.leave(roomid); + o.rooms.splice(o.rooms.indexOf(roomid),1); + }); + delete rooms[roomid]; + }); + connlist.splice(idx,1); + io.emit("userlist",connlist.map(function(o){return [o.id,o.name];})); + }); + conn.on("me",function(cb){ + cb([obj.id,obj.name]); + }); + conn.on("setnick",function(nick){ + var i; + if(C.validatenick(nick)){ + if(findname(nick)!=-1){ + i=1; + while(findname(nick+"_"+i)!=-1)i++; + nick+="_"+i; + } + obj.name=nick; + conn.emit("me",[obj.id,obj.name]); + io.emit("userlist",connlist.map(function(o){return [o.id,o.name];})); + } else conn.emit("message","That's an invalid nick!"); + }); + conn.on("userlist",function(cb){ + cb(connlist.map(function(o){return [o.id,o.name];})); + }); + conn.on("rooms",function(cb){ + cb(obj.rooms); + }); + conn.on("createroom",function(ids){ //give all id's, except your own + var myidx=findid(obj.id); + var indices=ids.map(function(id){return findid(id);}).filter(function(id){return id!=-1;}); + if(indices.length==0){ + conn.emit("message","Room too small; can only create rooms with 2 or more people"); + return; + } + var roomid="room_"+uniqid(); + rooms[roomid]={ids:[obj.id],game:null}; + connlist[myidx].rooms.push(roomid); + conn.emit("room",roomid,[[obj.id,obj.name]]); + conn.join(roomid); + indices.forEach(function(idx){ + connlist[idx].conn.emit("roominvite",roomid,[obj.id,obj.name]); + connlist[idx].pending.push(roomid); + }); + }); + conn.on("inviteaccept",function(roomid){ + var idx=obj.pending.indexOf(roomid); + if(idx!=-1)obj.pending.splice(idx,1); + if(idx==-1||rooms[roomid]==undefined){ + conn.emit("message","Cannot accept non-existent invitation"); + return; + } + obj.rooms.push(roomid); + conn.emit("room",roomid,rooms[roomid].ids.map(function(id){ + return [id,connlist[findid(id)].name]; + })); + conn.join(roomid); + io.to(roomid).emit("roomjoin",roomid,[obj.id,obj.name]); + rooms[roomid].ids.push(obj.id); + }); + function guardroomid(roomid){ + if(obj.rooms.indexOf(roomid)==-1){ + conn.emit("message","No member of that room!"); + return false; + } + return true; + } + conn.on("roomdestroy",function(roomid){ + if(!guardroomid(roomid))return; + io.to(roomid).emit("roomdestroy",roomid); + rooms[roomid].ids.forEach(function(id){ + var o=connlist[findid(id)]; + o.conn.leave(roomid); + o.rooms.splice(o.rooms.indexOf(roomid),1); + }); + delete rooms[roomid]; + }); + conn.on("roomusers",function(roomid,cb){ + if(!guardroomid(roomid)){ + cb(false); + return; + } + cb(rooms[roomid].ids.map(function(id){ + return [id,connlist[findid(id)].name]; + })); + }); + conn.on("roomchat",function(roomid,message){ + if(!guardroomid(roomid))return; + io.to(roomid).emit("roomchat",roomid,[obj.id,obj.name],message); + }); + conn.on("roomcreategame",function(roomid){ + if(!guardroomid(roomid))return; + if(rooms[roomid].game!=null){ + conn.emit("message","Room already has a running game"); + return; + } + rooms[roomid].game=new Game(rooms[roomid].ids.length); + io.to(roomid).emit("roomcreategame",roomid); + connlist[findid(rooms[roomid].ids[0])].conn.emit("roomgameturn",roomid,0); + }); + conn.on("roomhasgame",function(roomid,cb){ + if(!guardroomid(roomid))return; + cb(rooms[roomid].game!=null); + }); + function guardroomgame(roomid){ + if(rooms[roomid].game==null){ + conn.emit("message","No game in that room!"); + return false; + } + return true; + } + conn.on("roomgameusers",function(roomid,cb){ + if(!guardroomid(roomid)||!guardroomgame(roomid)){ + cb(false); + return; + } + cb(rooms[roomid].ids.map(function(id){ + return [id,connlist[findid(id)].name]; + })); + }); + conn.on("roomgameboard",function(roomid,cb){ + if(!guardroomid(roomid)||!guardroomgame(roomid)){ + cb(false); + return; + } + cb(rooms[roomid].game.bd); + }); + conn.on("roomgameplace",function(roomid,pos){ + if(!guardroomid(roomid)||!guardroomgame(roomid))return; + var playeridx=rooms[roomid].ids.indexOf(obj.id); + if(!rooms[roomid].game.applymove(pos,playeridx)){ + conn.emit("message","Invalid move!"); + return; + } + io.to(roomid).emit("roomgameplace",roomid,pos,playeridx); + connlist[findid(rooms[roomid].ids[rooms[roomid].game.onturn])].conn.emit("roomgameturn",roomid,rooms[roomid].game.onturn); + }); +}); + +http.listen(HTTPPORT,function(){ + console.log("Listening on http://localhost:"+HTTPPORT); +}); |