diff options
author | tomsmeding <tom.smeding@gmail.com> | 2018-02-19 22:59:14 +0100 |
---|---|---|
committer | tomsmeding <tom.smeding@gmail.com> | 2018-02-19 22:59:14 +0100 |
commit | 0b4ed233c73ea41e0fbe4bb147fbfaf15fe4e55c (patch) | |
tree | 8b1a7e3d0b39c5b241bfb3faabebee87c361317c /capturego_server.js |
Initial
Diffstat (limited to 'capturego_server.js')
-rwxr-xr-x | capturego_server.js | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/capturego_server.js b/capturego_server.js new file mode 100755 index 0000000..b5d938e --- /dev/null +++ b/capturego_server.js @@ -0,0 +1,176 @@ +#!/usr/bin/env node + +const naampje=require("naampje"); + +const PORT=8080; + +// Game: {id: Int, size: Int, board: Board, onturn: Int, players: [Player]} +// 'onturn' is index into 'players', or -1 if game is finished +// Player: {id: Int, name: String, socket: SocketIO_Socket, games: [Game]} +// Board: [(0,1,-1) * (size*size)] +const games=new Map(); // game_id => Game +const players=new Map(); // player_id => Player + +{let id=0; function uniqid(){return id++;}} + +function mkPlayer(socket){ + const id=uniqid(); + let name; + while(true){try {name=naampje.name();} catch(e){continue;} break;} + return {id, name, socket, games: []}; +} + +function mkGame(size,players){ + const id=uniqid(); + const board=new Array(size*size).fill(0); + return {id, size, board, onturn: 0, players}; +} + +function safePlayer(p){ + return {id: p.id, name: p.name, games: p.games.map(g=>g.id)}; +} + +function safeGame(g){ + return {id: g.id, size: g.size, board: g.board, onturn: g.onturn, players: g.players.map(safePlayer)}; +} + +function playerLeavesGame(player,game){ + game.onturn=-1; + const newp=[]; + for(const p of game.players){ + if(p!=player){ + p.socket.emit("game_leave",safeGame(game),safePlayer(player)); + newp.push(p); + } + } + if(newp.length==0)games.delete(game.id); + else game.players=newp; +} + +// Returns winning player (0 or 1) or -1 if none yet +function gameBoardFinished(game){ + const B=game.board,S=game.size; + for(let i=0;i<S*S;i++){ + if(B[i]==0)continue; + const flags=new Array(S*S).fill(false); + const queue=[i]; + let nb0=false; + while(queue.length){ + const at=queue.shift(),x=at%S,y=~~(at/S); + flags[at]=true; + if(x>0&&!flags[at-1]){if(B[at-1]==B[i])queue.push(at-1); else if(B[at-1]==0){nb0=true; break;}} + if(y>0&&!flags[at-S]){if(B[at-S]==B[i])queue.push(at-S); else if(B[at-S]==0){nb0=true; break;}} + if(x<S-1&&!flags[at+1]){if(B[at+1]==B[i])queue.push(at+1); else if(B[at+1]==0){nb0=true; break;}} + if(y<S-1&&!flags[at+S]){if(B[at+S]==B[i])queue.push(at+S); else if(B[at+S]==0){nb0=true; break;}} + } + if(!nb0)return 1-B[i]==1?1:0; + } + return -1; +} + + +const app=require("express")(); +const httpServer=require("http").Server(app); +const io=require("socket.io")(httpServer); +httpServer.listen(PORT,()=>console.log(`Listening on port ${PORT}`)); + + +app.get("/",(req,res)=>{ + res.sendFile(__dirname+"/index.html"); +}); + +io.on("connection",(socket)=>{ + const player=mkPlayer(socket); + console.log(`connect ${player.id}`); + players.set(player.id,player); + for(const p of players.values()){ + if(p!=player)p.socket.emit("player_list_change"); + } + + socket.on("my_info",(cb)=>{ + if(typeof cb!="function")return; + cb(safePlayer(player)); + }); + + socket.on("player_info",(pi,cb)=>{ + if(typeof cb!="function")return; + const p=players.get(pi); + if(!p)cb(null); + else cb(safePlayer(p)); + }); + + socket.on("list_players",(cb)=>{ + if(typeof cb!="function")return; + const l=[]; + for(const p of players.values()){ + l.push(safePlayer(p)); + } + cb(l); + }); + + socket.on("disconnect",()=>{ + console.log(`disconnect ${player.id}`); + for(const g of player.games)playerLeavesGame(player,g); + players.delete(player.id); + for(const p of players.values()){ + p.socket.emit("player_list_change"); + } + }); + + socket.on("create_game",(otherid,size)=>{ + const otherp=players.get(+otherid); + if(!otherp){ + socket.emit("err",`Player with id ${otherid} not found`); + return; + } + if(typeof size!="number"||isNaN(size)||size<5||size>99||size%1!=0)return; + + const arr=Math.random()<0.5?[player,otherp]:[otherp,player]; + const game=mkGame(size,arr); + player.games.push(game); + otherp.games.push(game); + games.set(game.id,game); + + for(const p of game.players){ + p.socket.emit("game_create",safeGame(game)); + } + game.players[0].socket.emit("game_turn",safeGame(game)); + game.players[1].socket.emit("game_other_turn",safeGame(game)); + }); + + socket.on("leave_game",(gi)=>{ + const g=games.get(gi); + if(!g)return; + if(player.games.indexOf(g)==-1)return; + playerLeavesGame(player,g); + }); + + socket.on("game_move",(gi,idx)=>{ + const g=games.get(gi); + if(!g)return; + if(player.games.indexOf(g)==-1)return; + if(typeof idx!="number"||isNaN(idx)||idx<0||idx>=g.size*g.size||idx%1!=0){ + socket.emit("err","Invalid position sent"); + return; + } + if(g.players[g.onturn]!=player){ + socket.emit("err","Not on turn"); + return; + } + if(g.board[idx]!=0){ + socket.emit("err","Position already taken"); + return; + } + g.board[idx]=[1,-1][g.onturn]; + const win=gameBoardFinished(g) + if(win!=-1){ + for(const p of g.players){ + p.socket.emit("game_win",safeGame(g),safePlayer(g.players[win])); + } + } else { + g.onturn=1-g.onturn; + g.players[g.onturn].socket.emit("game_turn",safeGame(g)); + g.players[1-g.onturn].socket.emit("game_other_turn",safeGame(g)); + } + }); +}); |