From b1b3cf82c0d0ccd6429145334c964e336858274a Mon Sep 17 00:00:00 2001
From: tomsmeding <tom.smeding@gmail.com>
Date: Tue, 20 Feb 2018 10:49:59 +0100
Subject: Botproxy

---
 botproxy.js  | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 package.json |   3 +-
 2 files changed, 118 insertions(+), 1 deletion(-)
 create mode 100755 botproxy.js

diff --git a/botproxy.js b/botproxy.js
new file mode 100755
index 0000000..1f64487
--- /dev/null
+++ b/botproxy.js
@@ -0,0 +1,116 @@
+#!/usr/bin/env node
+const io=require("socket.io-client");
+const child_process=require("child_process");
+
+let SERVER_URL=process.argv[3]?process.argv[3]:"http://localhost:15937";
+if(process.argv.length<3||process.argv.length>4){
+	console.log("Usage: ./botproxy.js <./bot> [http://server-url]");
+	process.exit(1);
+}
+const BOT_CMD=process.argv[2];
+
+function boardEmpty(bd){
+	for(const v of bd)if(v!=0)return false;
+	return true;
+}
+
+function boardDetectMove(prev,cur){
+	for(let i=0;i<prev.length;i++)if(prev[i]!=cur[i])return i;
+	return -1;
+}
+
+function encodeMove(idx,size){
+	return String.fromCharCode(65+idx%size)+(size-~~(idx/size));
+}
+
+function decodeMove(mv,size){
+	return size*(size-1-(mv.charCodeAt(1)-49))+mv.charCodeAt(0)-65;
+}
+
+function handleBotLine(line){
+	console.log(`PROXY: bot<- '${line.replace("\n","")}'`);
+	const idx=decodeMove(line,currentGame.size);
+	socket.emit("game_move",currentGame.id,idx);
+}
+
+let ME=null;
+let botproc=null;
+let currentGame=null;
+
+const socket=io(SERVER_URL);
+socket.on("connect",()=>{
+	socket.emit("my_info",(p)=>{
+		ME=p;
+		console.log(`PROXY: My name: '${ME.name}'`);
+	});
+});
+
+socket.on("err",(err)=>console.log(`ERROR: ${err}`));
+
+socket.on("game_create",(game)=>{
+	console.log(`PROXY: <- game_create ${JSON.stringify(game)}`);
+	if(game.size!=9){
+		console.log("PROXY: Invited for game with non-9 size!");
+		socket.emit("leave_game",game.id);
+		return;
+	}
+	currentGame=game;
+	botproc=child_process.spawn(BOT_CMD,{shell: true, stdio: ["pipe","pipe",process.stderr]});
+	let botbuf="";
+	botproc.stdout.on("data",(data)=>{
+		botbuf+=data.toString();
+		let idx=botbuf.indexOf("\n");
+		while(idx!=-1){
+			handleBotLine(botbuf.slice(0,idx));
+			botbuf=botbuf.slice(idx+1);
+			idx=botbuf.indexOf("\n");
+		}
+	});
+	botproc.stdout.on("end",()=>{
+		console.log("PROXY: Bot process exited!");
+		botproc.kill();
+		botproc=null;
+		if(currentGame)socket.emit("leave_game",currentGame.id);
+		socket.close();
+	});
+});
+
+socket.on("game_leave",(g,p)=>{
+	console.log(`PROXY: <- game_leave ${JSON.stringify(g)} ${JSON.stringify(p)}`);
+	if(g.id!=currentGame.id)return;
+	socket.emit("leave_game",g.id);
+	if(botproc)botproc.kill();
+	currentGame=null;
+});
+
+socket.on("game_turn",(g)=>{
+	console.log(`PROXY: <- game_turn ${JSON.stringify(g)}`);
+	if(g.id!=currentGame.id)return;
+	if(!botproc){
+		console.log("PROXY: game_turn while bot already died");
+		socket.emit("leave_game",g.id);
+		return;
+	}
+	const prevBoard=currentGame.board;
+	currentGame=g;
+	const mv=boardDetectMove(prevBoard,currentGame.board);
+	const towrite=mv==-1?"Start":encodeMove(mv,currentGame.size);
+	botproc.stdin.write(towrite+"\n");
+	console.log(`PROXY: ->bot '${towrite}'`);
+});
+
+socket.on("game_other_turn",(g)=>{
+	console.log(`PROXY: <- game_other_turn ${JSON.stringify(g)}`);
+	if(g.id!=currentGame.id)return;
+	currentGame=g;
+});
+
+socket.on("game_win",(g,p)=>{
+	console.log(`PROXY: <- game_win ${JSON.stringify(g)} ${JSON.stringify(p)}`);
+	if(g.id!=currentGame.id)return;
+	if(p.id==ME.id)console.log("PROXY: We won");
+	else console.log("PROXY: We lost");
+	socket.emit("leave_game",g.id);
+	if(botproc)botproc.kill();
+	socket.close();
+});
diff --git a/package.json b/package.json
index 564981d..6faf471 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
   "dependencies": {
     "express": "^4.16.2",
     "naampje": "^1.0.1",
-    "socket.io": "^2.0.4"
+    "socket.io": "^2.0.4",
+    "socket.io-client": "^2.0.4"
   }
 }
-- 
cgit v1.2.3-70-g09d2