-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrand_gtp.py
executable file
·120 lines (93 loc) · 4.45 KB
/
rand_gtp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python2
import sys, shlex
from collections import namedtuple, OrderedDict
from random import random
from bisect import bisect
from ConfigParser import ConfigParser
from gomill import gtp_controller, gtp_engine, gtp_proxy
def weighted_choice(choices):
weights, values = zip(*choices)
total = 0
cum_weights = []
for w in weights:
total += w
cum_weights.append(total)
return values[bisect(cum_weights, random() * total)]
Engine = namedtuple('Engine', 'name weight command analyze')
class Rand_GTP(gtp_proxy.Gtp_proxy):
def __init__(self, engine):
super(Rand_GTP, self).__init__()
self.set_back_end_subprocess(engine.command)
self.engine.add_command('name', lambda args: 'Random GTP')
self.engine.add_command('version', lambda args: '0.0')
self.engine.add_command('genmove', self._handle_genmove)
self.engine.add_command('showboard', self._handle_showboard)
self.engine.add_command('place_free_handicap', self._handle_place_free_handicap)
self._engines = [(engine, self.controller)]
def add_additional_engine(self, engine):
try:
channel = gtp_controller.Subprocess_gtp_channel(engine.command)
except gtp_controller.GtpChannelError, e:
raise gtp_proxy.BackEndError('can\'t launch back end command: %s\n%s' % (e, engine.command), cause = e)
controller = gtp_controller.Gtp_controller(channel, engine.name)
self._engines.append((engine, controller))
def run(self):
self._engines = OrderedDict([(e[0].name, e) for e in sorted(self._engines, key=lambda x: x[0].weight)])
return super(Rand_GTP, self).run()
def pass_command(self, command, args):
for engine, controller in self._engines.values():
# TODO: proper handling of commands which return data
# (e.g. final_score etc.) and of commands not supported by all engines.
print >>sys.stderr, engine.name, command, args
r = self._send_command(controller, command, args)
if r:
return r
def _send_command(self, controller, command, args = None):
tmp = self.controller
self.controller = controller
value = super(Rand_GTP, self).pass_command(command, args or [])
self.controller = tmp
return value
def _handle_genmove(self, args):
executor = weighted_choice(((e[0].weight, e) for e in self._engines.values()))
for engine, controller in self._engines.values():
print >>sys.stderr, engine.name, 'showboard'
print >>sys.stderr, self._send_command(controller, 'showboard', [])
value = self._send_command(executor[1], 'genmove', args)
print >>sys.stderr, 'Passing genmove to %s: %s' % (executor[0].name, value)
for engine, controller in self._engines.values():
if controller != executor[1] and value.lower() != 'resign':
self._send_command(controller, 'play', args + [value])
if engine.analyze is not None:
analyze = self._send_command(controller, engine.analyze)
print >>sys.stderr, 'Analysis from %s: %s' % (engine.name, analyze)
return value
def _handle_showboard(self, args):
for engine, controller in self._engines.values():
print >>sys.stderr, 'Showboard from', engine.name
print >>sys.stderr, self._send_command(controller, 'showboard', [])
def _handle_place_free_handicap(self, args):
value = None
for engine, controller in self._engines.values():
if value is None:
value = self._send_command(controller, 'place_free_handicap', args).split()
else:
self._send_command(controller, 'set_free_handicap', value)
return ' '.join(value)
if __name__ == "__main__":
conf = ConfigParser()
conf.read([sys.argv[1]])
engines = conf.sections()
print >>sys.stderr, 'Engines:', engines
def _make_engine(name):
return Engine(name = name,
weight = conf.getint(name, 'weight'),
command = shlex.split(conf.get(name, 'command')),
analyze = conf.get(name, 'analyze') if conf.has_option(name, 'analyze') else None)
r = Rand_GTP(_make_engine(engines[0]))
for engine in engines[1:]:
r.add_additional_engine(_make_engine(engine))
try:
r.run()
except KeyboardInterrupt:
sys.exit(1)