"""Tests for gtp_games.py""" import cPickle as pickle from gomill import gtp_controller from gomill import gtp_games from gomill import sgf from gomill.common import format_vertex from gomill_tests import test_framework from gomill_tests import gomill_test_support from gomill_tests import gtp_controller_test_support from gomill_tests import gtp_engine_fixtures from gomill_tests.gtp_engine_fixtures import Programmed_player def make_tests(suite): suite.addTests(gomill_test_support.make_simple_tests(globals())) for t in handicap_compensation_tests: suite.addTest(Handicap_compensation_TestCase(*t)) class Game_fixture(test_framework.Fixture): """Fixture managing a Gtp_game. Instantiate with the player objects (defaults to a Test_player) and optionally komi. attributes: game -- Gtp_game controller_b -- Gtp_controller controller_w -- Gtp_controller channel_b -- Testing_gtp_channel channel_w -- Testing_gtp_channel engine_b -- Test_gtp_engine_protocol engine_w -- Test_gtp_engine_protocol player_b -- player object player_w -- player object """ def __init__(self, tc, player_b=None, player_w=None, komi=0.0, board_size=9): self.tc = tc game = gtp_games.Game(board_size, komi=komi) game.set_player_code('b', 'one') game.set_player_code('w', 'two') if player_b is None: player_b = gtp_engine_fixtures.Test_player() if player_w is None: player_w = gtp_engine_fixtures.Test_player() engine_b = gtp_engine_fixtures.make_player_engine(player_b) engine_w = gtp_engine_fixtures.make_player_engine(player_w) channel_b = gtp_controller_test_support.Testing_gtp_channel(engine_b) channel_w = gtp_controller_test_support.Testing_gtp_channel(engine_w) controller_b = gtp_controller.Gtp_controller(channel_b, 'player one') controller_w = gtp_controller.Gtp_controller(channel_w, 'player two') game.set_player_controller('b', controller_b) game.set_player_controller('w', controller_w) self.game = game self.controller_b = controller_b self.controller_w = controller_w self.channel_b = channel_b self.channel_w = channel_w self.engine_b = channel_b.engine self.engine_w = channel_w.engine self.player_b = channel_b.engine.player self.player_w = channel_w.engine.player def check_moves(self, expected_moves): """Check that the game's moves are as expected. expected_moves -- list of pairs (colour, vertex) """ game_moves = [(colour, format_vertex(move)) for (colour, move, comment) in self.game.moves] self.tc.assertListEqual(game_moves, expected_moves) def run_score_test(self, b_score, w_score, allowed_scorers="bw"): """Run a game and let the players score it. b_score, w_score -- string for final_score to return If b_score or w_score is None, the player won't implement final_score. If b_score or w_score is an exception, the final_score will fail """ def handle_final_score_b(args): if b_score is Exception: raise b_score return b_score def handle_final_score_w(args): if w_score is Exception: raise w_score return w_score if b_score is not None: self.engine_b.add_command('final_score', handle_final_score_b) if w_score is not None: self.engine_w.add_command('final_score', handle_final_score_w) for colour in allowed_scorers: self.game.allow_scorer(colour) self.game.ready() self.game.run() def sgf_string(self): return gomill_test_support.scrub_sgf( self.game.make_sgf().serialise(wrap=None)) def test_game(tc): fx = Game_fixture(tc) tc.assertDictEqual(fx.game.players, {'b' : 'one', 'w' : 'two'}) tc.assertIs(fx.game.get_controller('b'), fx.controller_b) tc.assertIs(fx.game.get_controller('w'), fx.controller_w) fx.game.use_internal_scorer() fx.game.ready() tc.assertIsNone(fx.game.game_id) tc.assertIsNone(fx.game.result) fx.game.run() fx.game.close_players() tc.assertIsNone(fx.game.describe_late_errors()) tc.assertDictEqual(fx.game.result.players, {'b' : 'one', 'w' : 'two'}) tc.assertEqual(fx.game.result.player_b, 'one') tc.assertEqual(fx.game.result.player_w, 'two') tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.result.losing_colour, 'w') tc.assertEqual(fx.game.result.winning_player, 'one') tc.assertEqual(fx.game.result.losing_player, 'two') tc.assertEqual(fx.game.result.sgf_result, "B+18") tc.assertFalse(fx.game.result.is_forfeit) tc.assertIs(fx.game.result.is_jigo, False) tc.assertIsNone(fx.game.result.detail) tc.assertIsNone(fx.game.result.game_id) tc.assertEqual(fx.game.result.describe(), "one beat two B+18") result2 = pickle.loads(pickle.dumps(fx.game.result)) tc.assertEqual(result2.describe(), "one beat two B+18") tc.assertEqual(fx.game.describe_scoring(), "one beat two B+18") tc.assertEqual(result2.player_b, 'one') tc.assertEqual(result2.player_w, 'two') tc.assertIs(result2.is_jigo, False) tc.assertDictEqual(fx.game.result.cpu_times, {'one' : None, 'two' : None}) tc.assertListEqual(fx.game.moves, [ ('b', (0, 4), None), ('w', (0, 6), None), ('b', (1, 4), None), ('w', (1, 6), None), ('b', (2, 4), None), ('w', (2, 6), None), ('b', (3, 4), None), ('w', (3, 6), None), ('b', (4, 4), None), ('w', (4, 6), None), ('b', (5, 4), None), ('w', (5, 6), None), ('b', (6, 4), None), ('w', (6, 6), None), ('b', (7, 4), None), ('w', (7, 6), None), ('b', (8, 4), None), ('w', (8, 6), None), ('b', None, None), ('w', None, None)]) fx.check_moves([ ('b', 'E1'), ('w', 'G1'), ('b', 'E2'), ('w', 'G2'), ('b', 'E3'), ('w', 'G3'), ('b', 'E4'), ('w', 'G4'), ('b', 'E5'), ('w', 'G5'), ('b', 'E6'), ('w', 'G6'), ('b', 'E7'), ('w', 'G7'), ('b', 'E8'), ('w', 'G8'), ('b', 'E9'), ('w', 'G9'), ('b', 'pass'), ('w', 'pass'), ]) def test_unscored_game(tc): fx = Game_fixture(tc) tc.assertDictEqual(fx.game.players, {'b' : 'one', 'w' : 'two'}) tc.assertIs(fx.game.get_controller('b'), fx.controller_b) tc.assertIs(fx.game.get_controller('w'), fx.controller_w) fx.game.allow_scorer('b') # it can't score fx.game.ready() fx.game.run() fx.game.close_players() tc.assertIsNone(fx.game.describe_late_errors()) tc.assertDictEqual(fx.game.result.players, {'b' : 'one', 'w' : 'two'}) tc.assertIsNone(fx.game.result.winning_colour) tc.assertIsNone(fx.game.result.losing_colour) tc.assertIsNone(fx.game.result.winning_player) tc.assertIsNone(fx.game.result.losing_player) tc.assertEqual(fx.game.result.sgf_result, "?") tc.assertFalse(fx.game.result.is_forfeit) tc.assertIs(fx.game.result.is_jigo, False) tc.assertEqual(fx.game.result.detail, "no score reported") tc.assertEqual(fx.game.result.describe(), "one vs two ? (no score reported)") tc.assertEqual(fx.game.describe_scoring(), "one vs two ? (no score reported)") result2 = pickle.loads(pickle.dumps(fx.game.result)) tc.assertEqual(result2.describe(), "one vs two ? (no score reported)") tc.assertIs(result2.is_jigo, False) def test_jigo(tc): fx = Game_fixture(tc, komi=18.0) fx.game.use_internal_scorer() fx.game.ready() tc.assertIsNone(fx.game.result) fx.game.run() fx.game.close_players() tc.assertIsNone(fx.game.describe_late_errors()) tc.assertDictEqual(fx.game.result.players, {'b' : 'one', 'w' : 'two'}) tc.assertEqual(fx.game.result.player_b, 'one') tc.assertEqual(fx.game.result.player_w, 'two') tc.assertEqual(fx.game.result.winning_colour, None) tc.assertEqual(fx.game.result.losing_colour, None) tc.assertEqual(fx.game.result.winning_player, None) tc.assertEqual(fx.game.result.losing_player, None) tc.assertEqual(fx.game.result.sgf_result, "0") tc.assertIs(fx.game.result.is_forfeit, False) tc.assertIs(fx.game.result.is_jigo, True) tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.describe(), "one vs two jigo") tc.assertEqual(fx.game.describe_scoring(), "one vs two jigo") result2 = pickle.loads(pickle.dumps(fx.game.result)) tc.assertEqual(result2.describe(), "one vs two jigo") tc.assertEqual(result2.player_b, 'one') tc.assertEqual(result2.player_w, 'two') tc.assertIs(result2.is_jigo, True) def test_players_score_agree(tc): fx = Game_fixture(tc) fx.run_score_test("b+3", "B+3.0") tc.assertEqual(fx.game.result.sgf_result, "B+3") tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.describe_scoring(), "one beat two B+3") def test_players_score_agree_draw(tc): fx = Game_fixture(tc) fx.run_score_test("0", "0") tc.assertEqual(fx.game.result.sgf_result, "0") tc.assertIsNone(fx.game.result.detail) tc.assertIsNone(fx.game.result.winning_colour) tc.assertEqual(fx.game.describe_scoring(), "one vs two jigo") def test_players_score_disagree(tc): fx = Game_fixture(tc) fx.run_score_test("b+3.0", "W+4") tc.assertEqual(fx.game.result.sgf_result, "?") tc.assertEqual(fx.game.result.detail, "players disagreed") tc.assertIsNone(fx.game.result.winning_colour) tc.assertEqual(fx.game.describe_scoring(), "one vs two ? (players disagreed)\n" "one final_score: b+3.0\n" "two final_score: W+4") def test_players_score_disagree_one_no_margin(tc): fx = Game_fixture(tc) fx.run_score_test("b+", "W+4") tc.assertEqual(fx.game.result.sgf_result, "?") tc.assertEqual(fx.game.result.detail, "players disagreed") tc.assertEqual(fx.game.describe_scoring(), "one vs two ? (players disagreed)\n" "one final_score: b+\n" "two final_score: W+4") def test_players_score_disagree_one_jigo(tc): fx = Game_fixture(tc) fx.run_score_test("0", "W+4") tc.assertEqual(fx.game.result.sgf_result, "?") tc.assertEqual(fx.game.result.detail, "players disagreed") tc.assertIsNone(fx.game.result.winning_colour) tc.assertEqual(fx.game.describe_scoring(), "one vs two ? (players disagreed)\n" "one final_score: 0\n" "two final_score: W+4") def test_players_score_disagree_equal_margin(tc): # check equal margin in both directions doesn't confuse it fx = Game_fixture(tc) fx.run_score_test("b+4", "W+4") tc.assertEqual(fx.game.result.sgf_result, "?") tc.assertEqual(fx.game.result.detail, "players disagreed") tc.assertIsNone(fx.game.result.winning_colour) tc.assertEqual(fx.game.describe_scoring(), "one vs two ? (players disagreed)\n" "one final_score: b+4\n" "two final_score: W+4") def test_players_score_one_unreliable(tc): fx = Game_fixture(tc) fx.run_score_test("b+3", "W+4", allowed_scorers="w") tc.assertEqual(fx.game.result.sgf_result, "W+4") tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.describe_scoring(), "two beat one W+4") def test_players_score_one_cannot_score(tc): fx = Game_fixture(tc) fx.run_score_test(None, "W+4") tc.assertEqual(fx.game.result.sgf_result, "W+4") tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.describe_scoring(), "two beat one W+4") def test_players_score_one_fails(tc): fx = Game_fixture(tc) fx.run_score_test(Exception, "W+4") tc.assertEqual(fx.game.result.sgf_result, "W+4") tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.describe_scoring(), "two beat one W+4") def test_players_score_one_illformed(tc): fx = Game_fixture(tc) fx.run_score_test("black wins", "W+4.5") tc.assertEqual(fx.game.result.sgf_result, "W+4.5") tc.assertIsNone(fx.game.result.detail) tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.describe_scoring(), "two beat one W+4.5\n" "one final_score: black wins\n" "two final_score: W+4.5") def test_players_score_agree_except_margin(tc): fx = Game_fixture(tc) fx.run_score_test("b+3", "B+4.0") tc.assertEqual(fx.game.result.sgf_result, "B+") tc.assertEqual(fx.game.result.detail, "unknown margin") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.describe_scoring(), "one beat two B+ (unknown margin)\n" "one final_score: b+3\n" "two final_score: B+4.0") def test_players_score_agree_one_no_margin(tc): fx = Game_fixture(tc) fx.run_score_test("b+3", "B+") tc.assertEqual(fx.game.result.sgf_result, "B+") tc.assertEqual(fx.game.result.detail, "unknown margin") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.describe_scoring(), "one beat two B+ (unknown margin)\n" "one final_score: b+3\n" "two final_score: B+") def test_players_score_agree_one_illformed_margin(tc): fx = Game_fixture(tc) fx.run_score_test("b+3", "B+a") tc.assertEqual(fx.game.result.sgf_result, "B+") tc.assertEqual(fx.game.result.detail, "unknown margin") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.describe_scoring(), "one beat two B+ (unknown margin)\n" "one final_score: b+3\n" "two final_score: B+a") def test_players_score_agree_margin_zero(tc): fx = Game_fixture(tc) fx.run_score_test("b+0", "B+0") tc.assertEqual(fx.game.result.sgf_result, "B+") tc.assertEqual(fx.game.result.detail, "unknown margin") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.describe_scoring(), "one beat two B+ (unknown margin)\n" "one final_score: b+0\n" "two final_score: B+0") def test_claim(tc): def handle_genmove_ex_b(args): tc.assertIn('claim', args) if fx.player_b.row_to_play < 3: return fx.player_b.handle_genmove(args) return "claim" def handle_genmove_ex_w(args): return "claim" fx = Game_fixture(tc) fx.engine_b.add_command('gomill-genmove_ex', handle_genmove_ex_b) fx.engine_w.add_command('gomill-genmove_ex', handle_genmove_ex_w) fx.game.use_internal_scorer() fx.game.set_claim_allowed('b') fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "B+") tc.assertEqual(fx.game.result.detail, "claim") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.result.winning_player, 'one') tc.assertFalse(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.describe(), "one beat two B+ (claim)") tc.assertEqual(fx.game.describe_scoring(), "one beat two B+ (claim)") fx.check_moves([ ('b', 'E1'), ('w', 'G1'), ('b', 'E2'), ('w', 'G2'), ('b', 'E3'), ('w', 'G3'), ]) def test_forfeit_occupied_point(tc): moves = [ ('b', 'C3'), ('w', 'D3'), ('b', 'D4'), ('w', 'D4'), # occupied point ] fx = Game_fixture(tc, Programmed_player(moves), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "B+F") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.result.winning_player, 'one') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: two attempted move to occupied point d4") tc.assertEqual(fx.game.result.describe(), "one beat two B+F " "(forfeit: two attempted move to occupied point d4)") fx.check_moves(moves[:-1]) def test_forfeit_simple_ko(tc): moves = [ ('b', 'C5'), ('w', 'F5'), ('b', 'D6'), ('w', 'E4'), ('b', 'D4'), ('w', 'E6'), ('b', 'E5'), ('w', 'D5'), ('b', 'E5'), # ko violation ] fx = Game_fixture(tc, Programmed_player(moves), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "W+F") tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.result.winning_player, 'two') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: one attempted move to ko-forbidden point e5") fx.check_moves(moves[:-1]) def test_forfeit_illformed_move(tc): moves = [ ('b', 'C5'), ('w', 'F5'), ('b', 'D6'), ('w', 'Z99'), # ill-formed move ] fx = Game_fixture(tc, Programmed_player(moves), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "B+F") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.result.winning_player, 'one') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: two attempted ill-formed move z99") fx.check_moves(moves[:-1]) def test_forfeit_genmove_fails(tc): moves = [ ('b', 'C5'), ('w', 'F5'), ('b', 'fail'), # GTP failure response ] fx = Game_fixture(tc, Programmed_player(moves), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "W+F") tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.result.winning_player, 'two') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: failure response from 'genmove b' to player one:\n" "forced to fail") fx.check_moves(moves[:-1]) def test_forfeit_rejected_as_illegal(tc): moves = [ ('b', 'C5'), ('w', 'F5'), ('b', 'D6'), ('w', 'E4'), # will be rejected ] fx = Game_fixture(tc, Programmed_player(moves, reject=('E4', 'illegal move')), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "B+F") tc.assertEqual(fx.game.result.winning_colour, 'b') tc.assertEqual(fx.game.result.winning_player, 'one') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: one claims move e4 is illegal") fx.check_moves(moves[:-1]) def test_forfeit_play_failed(tc): moves = [ ('b', 'C5'), ('w', 'F5'), ('b', 'D6'), ('w', 'E4'), # will be rejected ] fx = Game_fixture(tc, Programmed_player(moves, reject=('E4', 'crash')), Programmed_player(moves)) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "W+F") tc.assertEqual(fx.game.result.winning_colour, 'w') tc.assertEqual(fx.game.result.winning_player, 'two') tc.assertTrue(fx.game.result.is_forfeit) tc.assertEqual(fx.game.result.detail, "forfeit: failure response from 'play w e4' to player one:\n" "crash") fx.check_moves(moves[:-1]) def test_same_player_code(tc): game = gtp_games.Game(board_size=9, komi=0) game.set_player_code('b', 'one') tc.assertRaisesRegexp(ValueError, "player codes must be distinct", game.set_player_code, 'w', 'one') def test_make_sgf(tc): fx = Game_fixture(tc) fx.game.use_internal_scorer() fx.game.ready() fx.game.run() fx.game.close_players() tc.assertMultiLineEqual(fx.sgf_string(), """\ (;FF[4]AP[gomill:VER]CA[UTF-8]DT[***]GM[1]KM[0]RE[B+18]SZ[9];B[ei];W[gi];B[eh];W[gh];B[eg];W[gg];B[ef];W[gf];B[ee];W[ge];B[ed];W[gd];B[ec];W[gc];B[eb];W[gb];B[ea];W[ga];B[tt];C[one beat two B+18]W[tt]) """) tc.assertMultiLineEqual(gomill_test_support.scrub_sgf( fx.game.make_sgf(game_end_message="zzzz").serialise(wrap=None)), """\ (;FF[4]AP[gomill:VER]CA[UTF-8]DT[***]GM[1]KM[0]RE[B+18]SZ[9];B[ei];W[gi];B[eh];W[gh];B[eg];W[gg];B[ef];W[gf];B[ee];W[ge];B[ed];W[gd];B[ec];W[gc];B[eb];W[gb];B[ea];W[ga];B[tt];C[one beat two B+18 zzzz]W[tt]) """) def test_game_id(tc): fx = Game_fixture(tc) fx.game.use_internal_scorer() fx.game.set_game_id("gitest") fx.game.ready() fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.game_id, "gitest") tc.assertMultiLineEqual(fx.sgf_string(), """\ (;FF[4]AP[gomill:VER]CA[UTF-8]DT[***]GM[1]GN[gitest]KM[0]RE[B+18]SZ[9];B[ei];W[gi];B[eh];W[gh];B[eg];W[gg];B[ef];W[gf];B[ee];W[ge];B[ed];W[gd];B[ec];W[gc];B[eb];W[gb];B[ea];W[ga];B[tt];C[one beat two B+18]W[tt]) """) def test_explain_last_move(tc): counter = [0] def handle_explain_last_move(args): counter[0] += 1 return "EX%d" % counter[0] fx = Game_fixture(tc) fx.engine_b.add_command('gomill-explain_last_move', handle_explain_last_move) fx.game.ready() fx.game.run() fx.game.close_players() tc.assertMultiLineEqual(fx.sgf_string(), """\ (;FF[4]AP[gomill:VER]CA[UTF-8]DT[***]GM[1]KM[0]RE[?]SZ[9];B[ei]C[EX1];W[gi];B[eh]C[EX2];W[gh];B[eg]C[EX3];W[gg];B[ef]C[EX4];W[gf];B[ee]C[EX5];W[ge];B[ed]C[EX6];W[gd];B[ec]C[EX7];W[gc];B[eb]C[EX8];W[gb];B[ea]C[EX9];W[ga];B[tt]C[EX10];C[one vs two ? (no score reported)]W[tt]) """) def test_fixed_handicap(tc): fh_calls = [] def handle_fixed_handicap(args): fh_calls.append(args[0]) return "C3 G7 C7" fx = Game_fixture(tc) fx.engine_b.add_command('fixed_handicap', handle_fixed_handicap) fx.engine_w.add_command('fixed_handicap', handle_fixed_handicap) fx.game.ready() fx.game.set_handicap(3, is_free=False) tc.assertEqual(fh_calls, ["3", "3"]) fx.game.run() fx.game.close_players() tc.assertEqual(fx.game.result.sgf_result, "B+F") tc.assertEqual(fx.game.result.detail, "forfeit: two attempted move to occupied point g7") fx.check_moves([ ('w', 'G1'), ('b', 'E1'), ('w', 'G2'), ('b', 'E2'), ('w', 'G3'), ('b', 'E3'), ('w', 'G4'), ('b', 'E4'), ('w', 'G5'), ('b', 'E5'), ('w', 'G6'), ('b', 'E6'), ]) tc.assertMultiLineEqual(fx.sgf_string(), """\ (;FF[4]AB[cc][cg][gc]AP[gomill:VER]CA[UTF-8]DT[***]GM[1]HA[3]KM[0]RE[B+F]SZ[9];W[gi];B[ei];W[gh];B[eh];W[gg];B[eg];W[gf];B[ef];W[ge];B[ee];W[gd];B[ed]C[one beat two B+F (forfeit: two attempted move to occupied point g7)]) """) def test_fixed_handicap_bad_engine(tc): fh_calls = [] def handle_fixed_handicap_good(args): fh_calls.append(args[0]) return "g7 c7 c3" def handle_fixed_handicap_bad(args): fh_calls.append(args[0]) return "C3 G3 C7" # Should be G7, not G3 fx = Game_fixture(tc) fx.engine_b.add_command('fixed_handicap', handle_fixed_handicap_good) fx.engine_w.add_command('fixed_handicap', handle_fixed_handicap_bad) fx.game.ready() tc.assertRaisesRegexp( gtp_controller.BadGtpResponse, "^bad response from fixed_handicap command to two: C3 G3 C7$", fx.game.set_handicap, 3, is_free=False) handicap_compensation_tests = [ # test code, handicap_compensation, result ('no', 'no', "B+53"), ('full', 'full', "B+50"), ('short', 'short', "B+51"), ] class Handicap_compensation_TestCase( gomill_test_support.Gomill_ParameterisedTestCase): test_name = "test_handicap_compensation" parameter_names = ('hc', 'result') def runTest(self): def handle_fixed_handicap(args): return "D4 K10 D10" fx = Game_fixture(self, board_size=13) fx.engine_b.add_command('fixed_handicap', handle_fixed_handicap) fx.engine_w.add_command('fixed_handicap', handle_fixed_handicap) fx.game.use_internal_scorer(handicap_compensation=self.hc) fx.game.set_handicap(3, is_free=False) fx.game.ready() fx.game.run() fx.game.close_players() self.assertEqual(fx.game.result.sgf_result, self.result)