From e990ec04c64e2c6fc812718ee792d789bfe15f37 Mon Sep 17 00:00:00 2001 From: Sander Land Date: Sat, 2 May 2020 23:11:09 +0200 Subject: [PATCH] optimizations --- bots/ai2gtp.py | 37 +++++++++++++++++++++++++++++++++---- bots/engine_server.py | 2 +- bots/start_bot.py | 11 +++++++---- core/sgf_parser.py | 8 ++++---- gui/badukpan.py | 2 ++ katrain.py | 4 ++-- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/bots/ai2gtp.py b/bots/ai2gtp.py index 7466d4b..eb3d35f 100644 --- a/bots/ai2gtp.py +++ b/bots/ai2gtp.py @@ -17,6 +17,7 @@ else: port = int(sys.argv[2]) if len(sys.argv) > 2 else 8587 REPORT_SCORE_THRESHOLD = 1.5 MAX_WAIT_ANALYSIS = 10 +MAX_PASS = 3 # after opponent passes this many times, we always pass class Logger: @@ -88,20 +89,48 @@ while True: line = input() logger.log(f"GOT INPUT {line}", OUTPUT_ERROR) if "boardsize" in line: - _, size = line.split(" ") - game = Game(Logger(), engine, {"init_size": int(size)}) + _, *size = line.strip().split(" ") + if len(size) > 1: + size = f"{size[0]}:{size[1]}" + else: + size = int(size[0]) + game = Game(Logger(), engine, {"init_size": size}) logger.log(f"Init game {game.root.properties}", OUTPUT_ERROR) - if "komi" in line: + elif "komi" in line: _, komi = line.split(" ") game.root.set_property("KM", komi.strip()) game.root.set_property("RU", "chinese") logger.log(f"Setting komi {game.root.properties}", OUTPUT_ERROR) + elif "place_free_handicap" in line: + _, n = line.split(" ") + game.place_handicap_stones(int(n)) + gtp = [Move.from_sgf(m, game.board_size, "B").gtp() for m in game.root.get_list_property("AB")] + logger.log(f"Chose handicap placements as {gtp}", OUTPUT_ERROR) + print(f"= {' '.join(gtp)}\n") + sys.stdout.flush() + game.analyze_all_nodes() # re-evaluate root + continue + elif "set_free_handicap" in line: + _, *stones = line.split(" ") + game.root.set_property("AB", [Move.from_gtp(move.upper()).sgf(game.board_size) for move in stones]) + logger.log(f"Set handicap placements to {game.root.get_list_property('AB')}", OUTPUT_ERROR) elif "genmove" in line: logger.log(f"{ai_strategy} generating move", OUTPUT_ERROR) game.current_node.analyze(engine) malkovich_analysis(game.current_node) game.root.properties[f"P{game.current_node.next_player}"] = [f"KaTrain {ai_strategy}"] - move, node = ai_move(game, ai_strategy, ai_settings) + num_passes = sum([int(n.is_pass or False) for n in game.current_node.nodes_from_root[::-1][0 : 2 * MAX_PASS : 2]]) + bx, by = game.board_size + if num_passes >= MAX_PASS and game.current_node.depth - 2 * MAX_PASS >= bx + by: + logger.log(f"Forced pass as opponent is passing {MAX_PASS} times", OUTPUT_ERROR) + pol = game.current_node.policy + if not pol: + pol = ["??"] + print(f"DISCUSSION:OK, since you passed {MAX_PASS} times after the {bx+by}th move, I will pass as well [policy {pol[-1]:.3%}].", file=sys.stderr) + move = game.play(Move(None, player=game.next_player)).single_move + else: + move, node = ai_move(game, ai_strategy, ai_settings) + logger.log(f"Generated move {move}", OUTPUT_ERROR) print(f"= {move.gtp()}\n") sys.stdout.flush() malkovich_analysis(game.current_node) diff --git a/bots/engine_server.py b/bots/engine_server.py index 4ce57bb..300fa8d 100644 --- a/bots/engine_server.py +++ b/bots/engine_server.py @@ -12,7 +12,7 @@ from core.engine import KataGoEngine PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8587 ENGINE_SETTINGS = { - "katago": "../KataGo/cpp/katago", + "katago": "my/katago25", "model": "KataGo/models/b15-1.3.2.txt.gz", "config": "KataGo/analysis_config.cfg", "max_visits": 50, diff --git a/bots/start_bot.py b/bots/start_bot.py index 7121053..35e4df0 100755 --- a/bots/start_bot.py +++ b/bots/start_bot.py @@ -10,9 +10,12 @@ bot = sys.argv[1].strip() port = int(sys.argv[2]) if len(sys.argv) > 2 else 8587 MAXGAMES = 10 -GTP2OGS = "node ../gtp2ogs" -# GTP2OGS = "gtp2ogs" -BOT_SETTINGS = f" --maxconnectedgames {MAXGAMES} --maxhandicap 0 --fakerank 1k --boardsizes 19" +if True or bot in ["dev", "local"]: + GTP2OGS = "node ../gtp2ogs" +else: + GTP2OGS = "node ../stable-gtp2ogs" +BOT_SETTINGS = f" --maxconnectedgames {MAXGAMES} --maxhandicapunranked 25 --maxhandicapranked 1 --boardsizesranked 19 --boardsizesunranked all --komisranked automatic,5.5,6.5,7.5 --komisunranked all" + username = f"katrain-{bot}" @@ -37,6 +40,6 @@ if settings: GREETING += f" Settings: {settings_dump}." BYEMSG = "Thank you for playing. If you have any feedback, please message my admin! Play with these bots at any time by downloading KaTrain at github.com/sanderland/katrain" -cmd = f'{GTP2OGS} --debug --apikey {APIKEY} --username {username} --greeting "{GREETING}" --farewell "{BYEMSG}" {BOT_SETTINGS} --farewellscore --aichat --noclock --nopause --speeds blitz,live --persist --minrank 25k --komis automatic,6.5,7.5 -- python bots/ai2gtp.py {bot} {port}' +cmd = f'{GTP2OGS} --debug --apikey {APIKEY} --username {username} --greeting "{GREETING}" --farewell "{BYEMSG}" {BOT_SETTINGS} --farewellscore --aichat --noclock --nopause --speeds blitz,live --persist --minrank 25k -- python bots/ai2gtp.py {bot} {port}' print(f"starting bot {username} using server port {port} --> {cmd}") os.system(cmd) diff --git a/core/sgf_parser.py b/core/sgf_parser.py index 7254e99..bca1459 100644 --- a/core/sgf_parser.py +++ b/core/sgf_parser.py @@ -211,15 +211,15 @@ class SGFNode: @property def next_player(self): - if self.get_list_property("B") or self.get_list_property("AB"): + if "B" in self.properties or "AB" in self.properties: return "W" return "B" @property def player(self): - if self.get_list_property("B") or self.get_list_property("AB"): - return "B" - return "W" + if "W" in self.properties: + return "W" + return "B" class SGF: diff --git a/gui/badukpan.py b/gui/badukpan.py index aeee849..7eaacc3 100644 --- a/gui/badukpan.py +++ b/gui/badukpan.py @@ -1,6 +1,7 @@ import copy import math +from kivy.clock import Clock from kivy.graphics.context_instructions import Color from kivy.graphics.vertex_instructions import Ellipse, Line, Rectangle from kivy.uix.boxlayout import BoxLayout @@ -26,6 +27,7 @@ class BadukPanWidget(Widget): self.last_eval = 0 self.active_hints = [] self.show_pv_for = None + self.redraw_board_contents_trigger = Clock.create_trigger(self.draw_board_contents) Window.bind(mouse_pos=self.on_mouse_pos) # stone placement functions diff --git a/katrain.py b/katrain.py index 8d5f3a4..ca3ccfa 100644 --- a/katrain.py +++ b/katrain.py @@ -120,8 +120,8 @@ class KaTrainGui(BoxLayout): self.board_controls.engine_status_col = self.config("board_ui/engine_almost_done_col") # redraw if redraw_board: - Clock.schedule_once(self.board_gui.draw_board, -1) # main thread needs to do this - Clock.schedule_once(self.board_gui.draw_board_contents, -1) + Clock.schedule_once(self.board_gui.draw_board, -1) + self.board_gui.redraw_board_contents_trigger() self.controls.update_evaluation() def _message_loop_thread(self):