mjaiをプロコンっぽい入出力でやれるpythonスクリプト
標準入力から取って、標準出力に出すだけでよくなりました。
python2.7で動作確認。*1
こんな感じで起動します。
python mjai-stdio.py mjsonp://localhost:11600/default ./a.out
a.outのソースコードは、こんな感じで書ける。
#include <iostream> #include <sstream> using namespace std; int id; int main() { while(true) { string line; getline(cin, line); stringstream ss(line); string type; ss >> type; if(type == "hello") { string protocol; int protocol_version; ss >> protocol >> protocol_version; cout << "join tsumogiri default" << endl; } else if(type == "start_game") { ss >> id; cout << "none" << endl; } else if(type == "end_game") { break; } else if(type == "tsumo") { int actor; string pai; ss >> actor >> pai; if(actor == id) { cout << "dahai " << id << " " << pai << " true" << endl; } else { cout << "none" << endl; } } else if(type == "error") { break; } else { cout << "none" << endl; } } return 0; }
入力のフォーマットは(書く元気が無いので)、mjai-stdio.pyを見るか、上のC++コードのを動かした時のログhttps://gist.github.com/ca9db0581fef1c231520を見れば微妙にわかるかも。*2
元のプロトコル自体は、http://d.hatena.ne.jp/wistery_k/20120915/1347733419を参照してください。
mjai-stdio.pyは以下。
import urlparse import json import sys from socket import * import subprocess from collections import OrderedDict def m(list): return "%d %s" % (len(list), ' '.join(list)) def b(bool): return 'true' if bool else 'false' def eb(str): if str == 'true': return True elif str == 'false': return False else: assert false, "should not happen" def decode(a): t = a['type'] if t == 'hello': return "hello %s %d" % ("mjptp", a['protocol_version']) elif t == 'start_game': return "start_game %d %s" % (a['id'], m(a['names'])) elif t == "start_kyoku": return "start_kyoku %s %d %d %d %d %s %s" % (a['bakaze'], a['kyoku'], a['honba'], a['kyotaku'], a['oya'], a['dora_marker'], m(map(m, a['tehais']))) elif t == 'tsumo': return "tsumo %d %s" % (a['actor'], a['pai']) elif t == 'dahai': return "dahai %d %s %s" % (a['actor'], a['pai'], b(a['tsumogiri'])) elif t == 'reach': return "reach %d" % a['actor'] elif t == 'reach_accepted': return "reach_accepted %d %s %s" % (a['actor'], m(map(str, a['deltas'])), m(map(str, a['scores']))) elif t == 'pon': return "pon %d %d %s %s" % (a['actor'], a['target'], a['pai'], m(a['consumed'])) elif t == 'chi': return "chi %d %d %s %s" % (a['actor'], a['target'], a['pai'], m(a['consumed'])) elif t == 'ankan': return "ankan %d %d %s %s" % (a['actor'], a['target'], a['pai'], m(a['consumed'])) elif t == 'daiminkan': return "daiminkan %d %d %s %s" % (a['actor'], a['target'], a['pai'], m(a['consumed'])) elif t == 'kakan': return "kakan %d %s" % (a['actor'], a['pai']) elif t == 'hora': return "hora %d %d %s %s %s %s %d %d %d %s %s" % (a['actor'], a['target'], a['pai'], m(a['uradora_markers']), m(a['hora_tehais']), m(map(lambda yn: "%s %d" % (yn[0], yn[1]), a['yakus'])), a['fu'], a['fan'], a['hora_points'], m(map(str, a['deltas'])), m(map(str, a['scores']))) elif t == 'ryukyoku': return "ryukyoku %s %s %s %s %s" % (a['reason'], m(map(m, a['tehais'])), m(map(b, a['tenpais'])), m(map(str, a['deltas'])), m(map(str, a['scores']))) elif t == 'end_kyoku': return "end_kyoku" elif t == 'end_game': return "end_game" elif t == 'error': return "error %s" % a['message'] else: assert false, "should not happen" def encode(line): st = line.split() t = st[0] if t == 'none': return OrderedDict([('type','none')]) elif t == 'join': return OrderedDict([('type','join'), ('name',st[1]), ('room',st[2])]) elif t == 'dahai': return OrderedDict([('type','dahai'), ('actor',int(st[1])), ('pai',st[2]), ('tsumogiri',eb(st[3]))]) elif t == 'reach': return OrderedDict([('type','reach'), ('actor',int(st[1]))]) elif t == 'hora': return OrderedDict([('type','hora'), ('actor',int(st[1])), ('target',int(st[2])), ('pai',st[3])]) elif t == 'pon': return OrderedDict([('type','pon'), ('actor',int(st[1])), ('target',int(st[2])), ('pai',st[3]), ('consumed',st[4:])]) elif t == 'chi': return OrderedDict([('type','chi'), ('actor',int(st[1])), ('target',int(st[2])), ('pai',st[3]), ('consumed',st[4:])]) elif t == 'ankan': return OrderedDict([('type','ankan'), ('actor',int(st[1])), ('target',int(st[2])), ('pai',st[3]), ('consumed',st[4:])]) elif t == 'daiminkan': return OrderedDict([('type','daiminkan'), ('actor',int(st[1])), ('target',int(st[2])), ('pai',st[3]), ('consumed',st[4:])]) elif t == 'kakan': return OrderedDict([('type','kakan'), ('actor',int(st[1])), ('pai',st[2])]) else: assert false, "should not happen" def start(host, port, room, program): p = subprocess.Popen(program, stdin=subprocess.PIPE, stdout=subprocess.PIPE) sock = socket(AF_INET, SOCK_STREAM) sock.connect((host, port)) try: for line in sock.makefile(): if not line: break print "<-\t%s" % line.rstrip() action = json.loads(line) p.stdin.write(decode(action) + '\n') resline = p.stdout.readline() if not resline: break res = json.dumps(encode(resline), sort_keys=False) print "->\t%s" % res sock.send(res + '\n') except: sock.close() p.kill() raise def main(args): if len(args) < 2: print "please specify an URI and a command." print "usage: python mjai-stdio.py mjsonp://localhost:11600/default ./a.out" return o = urlparse.urlparse(args[0]) start(o.hostname, o.port, o.path[1:], args[1:]) main(sys.argv[1:])
decode, encodeあたりのタイピングゲーが辛かった。。