145 lines
4.1 KiB
Plaintext
145 lines
4.1 KiB
Plaintext
|
#!/usr/bin/env python
|
||
|
"""GTP engine intended for testing GTP controllers.
|
||
|
|
||
|
This provides an example of a GTP engine which does not use the gtp_states
|
||
|
module.
|
||
|
|
||
|
It supports the following GTP commands:
|
||
|
|
||
|
Standard
|
||
|
boardsize
|
||
|
clear_board
|
||
|
genmove
|
||
|
known_command
|
||
|
komi
|
||
|
list_commands
|
||
|
name
|
||
|
play
|
||
|
protocol_version
|
||
|
quit
|
||
|
version
|
||
|
|
||
|
Extensions:
|
||
|
gomill-force_error [error_type]
|
||
|
gomill-delayed_error <move_number> [error_type]
|
||
|
|
||
|
gomill-force_error immediately causes an error. error_type can be any of the
|
||
|
following:
|
||
|
error -- return a GTP error response (this is the default)
|
||
|
exit -- return a GTP error response and end the GTP session
|
||
|
internal -- propagate a Python exception to the GTP engine code
|
||
|
kill -- abruptly terminate the engine process
|
||
|
protocol -- send an ill-formed GTP response
|
||
|
|
||
|
gomill-delayed_error causes a later genmove command to produce an error. This
|
||
|
will happen the first time genmove is called for the move 'move_number' or
|
||
|
later, counting from the start of the game.
|
||
|
|
||
|
"""
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
|
||
|
from gomill import gtp_engine
|
||
|
from gomill.gtp_engine import GtpError, GtpFatalError
|
||
|
|
||
|
|
||
|
class Test_player(object):
|
||
|
"""GTP player used for testing controllers' error handling."""
|
||
|
def __init__(self):
|
||
|
self.delayed_error_move = None
|
||
|
self.delayed_error_args = None
|
||
|
self.move_count = 0
|
||
|
|
||
|
def handle_name(self, args):
|
||
|
return "GTP test player"
|
||
|
|
||
|
def handle_version(self, args):
|
||
|
return ""
|
||
|
|
||
|
def handle_genmove(self, args):
|
||
|
"""Handler for the genmove command.
|
||
|
|
||
|
This honours gomill-delayed_error, and otherwise passes.
|
||
|
|
||
|
"""
|
||
|
self.move_count += 1
|
||
|
if (self.delayed_error_move and
|
||
|
self.move_count >= self.delayed_error_move):
|
||
|
self.delayed_error_move = None
|
||
|
self.handle_force_error(self.delayed_error_args)
|
||
|
return "pass"
|
||
|
|
||
|
def handle_play(self, args):
|
||
|
self.move_count += 1
|
||
|
|
||
|
def handle_boardsize(self, args):
|
||
|
pass
|
||
|
|
||
|
def handle_clear_board(self, args):
|
||
|
pass
|
||
|
|
||
|
def handle_komi(self, args):
|
||
|
pass
|
||
|
|
||
|
def handle_force_error(self, args):
|
||
|
"""Handler for the gomill-force_error command."""
|
||
|
try:
|
||
|
arg = args[0]
|
||
|
except IndexError:
|
||
|
arg = "error"
|
||
|
if arg == "error":
|
||
|
raise GtpError("forced GTP error")
|
||
|
if arg == "exit":
|
||
|
raise GtpFatalError("forced GTP error; exiting")
|
||
|
if arg == "internal":
|
||
|
3 / 0
|
||
|
if arg == "kill":
|
||
|
os.kill(os.getpid(), 15)
|
||
|
if arg == "protocol":
|
||
|
sys.stdout.write("!! forced ill-formed GTP response\n")
|
||
|
sys.stdout.flush()
|
||
|
return
|
||
|
raise GtpError("unknown force_error argument")
|
||
|
|
||
|
def handle_delayed_error(self, args):
|
||
|
"""Handler for the gomill-delayed_error command."""
|
||
|
try:
|
||
|
move_number = gtp_engine.interpret_int(args[0])
|
||
|
except IndexError:
|
||
|
gtp_engine.report_bad_arguments()
|
||
|
self.delayed_error_move = move_number
|
||
|
self.delayed_error_args = args[1:]
|
||
|
|
||
|
def get_handlers(self):
|
||
|
return {
|
||
|
'name' : self.handle_name,
|
||
|
'version' : self.handle_version,
|
||
|
'genmove' : self.handle_genmove,
|
||
|
'play' : self.handle_play,
|
||
|
'boardsize' : self.handle_boardsize,
|
||
|
'clear_board' : self.handle_clear_board,
|
||
|
'komi' : self.handle_komi,
|
||
|
'gomill-force_error' : self.handle_force_error,
|
||
|
'gomill-delayed_error' : self.handle_delayed_error,
|
||
|
}
|
||
|
|
||
|
|
||
|
def make_engine(test_player):
|
||
|
"""Return a Gtp_engine_protocol which runs the specified Test_player."""
|
||
|
engine = gtp_engine.Gtp_engine_protocol()
|
||
|
engine.add_protocol_commands()
|
||
|
engine.add_commands(test_player.get_handlers())
|
||
|
return engine
|
||
|
|
||
|
def main():
|
||
|
try:
|
||
|
test_player = Test_player()
|
||
|
engine = make_engine(test_player)
|
||
|
gtp_engine.run_interactive_gtp_session(engine)
|
||
|
except (KeyboardInterrupt, gtp_engine.ControllerDisconnected):
|
||
|
sys.exit(1)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|