From bbb3146a7a413bd508b459fc9692397b131703fa Mon Sep 17 00:00:00 2001 From: Sander Land Date: Sat, 18 Apr 2020 11:57:24 +0200 Subject: [PATCH] config etc --- engine.py | 14 +++++++++++--- gui/__init__.py | 13 ++++++++++++- gui/kivyutils.py | 9 +++++++++ gui/popups.py | 47 ++++++++++++++++++++++++++++++++++++----------- katrain.kv | 14 +++++++++++--- katrain.py | 10 ++++++---- 6 files changed, 85 insertions(+), 22 deletions(-) diff --git a/engine.py b/engine.py index a6a49a3..5e910b7 100644 --- a/engine.py +++ b/engine.py @@ -17,6 +17,10 @@ class KataGoEngine: RULESETS = {"jp": "japanese", "cn": "chinese", "ko": "korean", "aga": "aga"} RULESETS.update({v: v for v in RULESETS.values()}) + @staticmethod + def get_rules(node): + return KataGoEngine.RULESETS.get(str(node.ruleset).lower(), "japanese") + def __init__(self, katrain, config): self.katrain = katrain self.command = f"{config['katago']} analysis -model {config['model']} -config {config['config']} -analysis-threads {config['threads']}" @@ -43,10 +47,14 @@ class KataGoEngine: self.base_priority += 1 self.queries = {} - def shutdown(self): + def shutdown(self, finish=False): + if finish: + while self.queries: + time.sleep(0.1) process = getattr(self, "katago_process") if process: process.terminate() + self.katago_process = None def is_idle(self): return not self.queries @@ -85,7 +93,7 @@ class KataGoEngine: query = { "id": query_id, - "rules": self.RULESETS.get(str(analysis_node.ruleset).lower(), "japanese"), + "rules": self.get_rules(analysis_node), "priority": self.base_priority + priority, "analyzeTurns": [len(moves)], "maxVisits": max(min_visits, visits), @@ -97,6 +105,6 @@ class KataGoEngine: } self.queries[query_id] = (callback, time.time()) if self.katago_process: - self.katrain.log(f"Sending query {query_id}: {str(query)[:80]}", OUTPUT_DEBUG) + self.katrain.log(f"Sending query {query_id}: {str(query)}", OUTPUT_DEBUG) self.katago_process.stdin.write((json.dumps(query) + "\n").encode()) self.katago_process.stdin.flush() diff --git a/gui/__init__.py b/gui/__init__.py index a601ede..46060ce 100644 --- a/gui/__init__.py +++ b/gui/__init__.py @@ -1,4 +1,15 @@ from gui.badukpan import BadukPanWidget from gui.controls import Controls -from gui.kivyutils import BWCheckBoxHint, CensorableLabel, CensorableScoreLabel, CheckBoxHint, LabelledFloatInput, LabelledIntInput, StyledButton +from gui.kivyutils import ( + BWCheckBoxHint, + CensorableLabel, + CensorableScoreLabel, + CheckBoxHint, + LabelledFloatInput, + LabelledIntInput, + StyledButton, + LabelledSpinner, + LabelledCheckBox, + LabelledTextInput, +) from gui.popups import LoadSGFPopup diff --git a/gui/kivyutils.py b/gui/kivyutils.py index fdd6b69..ab1887c 100644 --- a/gui/kivyutils.py +++ b/gui/kivyutils.py @@ -6,6 +6,7 @@ import re from kivy.uix.button import Button from kivy.uix.checkbox import CheckBox +from kivy.uix.spinner import Spinner from kivy.uix.textinput import TextInput @@ -45,6 +46,14 @@ class LabelledCheckBox(CheckBox): return bool(self.active) +class LabelledSpinner(Spinner): + input_property = StringProperty("") + + @property + def input_value(self): + return self.text + + class LabelledFloatInput(LabelledTextInput): signed = BooleanProperty(True) pat = re.compile("[^0-9-]") diff --git a/gui/popups.py b/gui/popups.py index 927a11c..a3d41b9 100644 --- a/gui/popups.py +++ b/gui/popups.py @@ -1,13 +1,15 @@ from kivy.uix.boxlayout import BoxLayout import os - +from constants import OUTPUT_DEBUG, OUTPUT_ERROR from kivy.uix.floatlayout import FloatLayout from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.textinput import TextInput +from engine import KataGoEngine from game import Game, GameNode -from gui.kivyutils import LabelledFloatInput, LabelledIntInput, LabelledTextInput, StyledButton, LabelledCheckBox +from gui.kivyutils import LabelledFloatInput, LabelledIntInput, LabelledTextInput, StyledButton, LabelledCheckBox, \ + LabelledSpinner class InputParseError(Exception): @@ -23,7 +25,7 @@ class QuickConfigGui(BoxLayout): self.set_properties(self, initial_values) def collect_properties(self, widget): - if isinstance(widget, LabelledTextInput): + if isinstance(widget, (LabelledTextInput, LabelledSpinner)): try: ret = {widget.input_property: widget.input_value} except Exception as e: @@ -36,7 +38,7 @@ class QuickConfigGui(BoxLayout): return ret def set_properties(self, widget, properties): - if isinstance(widget, LabelledTextInput): + if isinstance(widget, (LabelledTextInput, LabelledSpinner)): key = widget.input_property if key in properties: widget.text = str(properties[key]) @@ -49,8 +51,16 @@ class LoadSGFPopup(BoxLayout): class NewGamePopup(QuickConfigGui): + def __init__(self, katrain, popup, properties, **kwargs): + properties["RU"] = KataGoEngine.get_rules(katrain.game.root) + super().__init__(katrain, popup, properties) + self.rules_spinner.values = list(set(self.katrain.engine.RULESETS.values())) + self.rules_spinner.text = properties["RU"] + def new_game(self): - new_root = GameNode(properties={**Game.DEFAULT_PROPERTIES, **self.collect_properties(self)}) + properties = self.collect_properties(self) + self.katrain.log(f"New game settings: {properties}", OUTPUT_DEBUG) + new_root = GameNode(properties={**Game.DEFAULT_PROPERTIES, **properties}) self.katrain("new-game", None, new_root) self.popup.dismiss() @@ -80,7 +90,6 @@ class ConfigPopup(QuickConfigGui): cat.add_widget(Label(text=k1, bold=True)) for k2, v in d.items(): cat.add_widget(Label(text=f"{k2}:")) - print(v, v.__class__, self.type_to_widget_class(v)) cat.add_widget(self.type_to_widget_class(v)(text=str(v), input_property=f"{k1}/{k2}")) if props_in_col[0] <= props_in_col[1]: cols[0].add_widget(cat) @@ -93,13 +102,29 @@ class ConfigPopup(QuickConfigGui): col_container.add_widget(cols[0]) col_container.add_widget(cols[1]) self.add_widget(col_container) - self.save_button = StyledButton(text="Update Settings", on_press=lambda _: self.update_config(), size_hint=(1, 0.05)) + self.save_button = StyledButton(text="Apply Settings", on_press=lambda _: self.update_config(), size_hint=(1, 0.05)) # apply & save? self.add_widget(self.save_button) - def update_config(self): + def update_config(self, save_to_file=False): + updated_cat = [] try: - print(self.collect_properties(self)) + for k, v in self.collect_properties(self).items(): + k1, k2 = k.split("/") + if self.config[k1][k2] != v: + self.katrain.log(f"Updating setting {k} = {v}", OUTPUT_DEBUG) + updated_cat.append(k1) + self.config[k1][k2] = v + # if save_to_file: # TODO + # self.katrain._config_store.put() self.popup.dismiss() except InputParseError as e: - self.save_button.text = str(e) - print(e) + self.save_button.text = str(e) # TODO: nicer error + self.katrain.log(e, OUTPUT_ERROR) + return + + if "engine" in updated_cat: + self.katrain.log("Restarting Engine after settings change") + old_engine = self.katrain.engine + self.katrain.engine = KataGoEngine(self.katrain, self.config["engine"]) + self.katrain.game.engine = self.katrain.engine + old_engine.shutdown(finish=True) diff --git a/katrain.kv b/katrain.kv index b2aa081..b4c880a 100644 --- a/katrain.kv +++ b/katrain.kv @@ -195,6 +195,7 @@ orientation: 'vertical' + rules_spinner: rules_spinner BoxLayout: size_hint: 1, 0.9 orientation: 'horizontal' @@ -205,24 +206,31 @@ Label: text: "Size" size_hint: 0.5, 0.1 - IntInput: + LabelledIntInput: text: '19' size_hint: 0.5, 0.1 input_property: 'SZ' Label: text: "Handicap" size_hint: 0.5, 0.1 - IntInput: + LabelledIntInput: text: '0' size_hint: 0.5, 0.1 input_property: 'HA' Label: text: "Komi" size_hint: 0.5, 0.1 - FloatInput: + LabelledFloatInput: text: '6.5' size_hint: 0.5, 0.1 input_property: 'KM' + Label: + text: "Ruleset" + size_hint: 0.5, 0.1 + LabelledSpinner: + size_hint: 0.5, 0.1 + input_property: 'RU' + id: rules_spinner Label: text: " " size_hint: 0.5, 0.6 diff --git a/katrain.py b/katrain.py index f35c76a..4798305 100644 --- a/katrain.py +++ b/katrain.py @@ -15,6 +15,7 @@ from constants import OUTPUT_DEBUG, OUTPUT_ERROR, OUTPUT_EXTRA_DEBUG, OUTPUT_INF from engine import KataGoEngine from game import Game, IllegalMoveException, KaTrainSGF, Move from gui import * +from gui import LabelledSpinner from gui.popups import NewGamePopup, ConfigPopup @@ -48,6 +49,7 @@ class KaTrainGui(BoxLayout): try: self.log(f"Using config file {config_file}", OUTPUT_INFO) self._config_store = JsonStore(config_file) + self._config = dict(self._config_store) except Exception as e: self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR) sys.exit(1) @@ -56,10 +58,10 @@ class KaTrainGui(BoxLayout): try: if "/" in setting: cat, key = setting.split("/") - return self._config_store.get(cat).get(key, default) + return self._config[cat].get(key, default) else: - return self._config_store.get(setting) - except Exception: + return self._config[setting] + except KeyError: self.log(f"Missing configuration option {setting}", OUTPUT_ERROR) def start(self): @@ -165,7 +167,7 @@ class KaTrainGui(BoxLayout): def _do_config_popup(self): config_popup = Popup(title="Edit Settings", size_hint=(0.9, 0.9)) - popup_contents = ConfigPopup(self, config_popup, dict(self._config_store)) + popup_contents = ConfigPopup(self, config_popup, dict(self._config)) config_popup.add_widget(popup_contents) config_popup.open()