pygo/gomill/examples/gtp_test_player

145 lines
4.1 KiB
Plaintext
Raw Permalink Normal View History

#!/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()