This commit is contained in:
Sander Land committed 2020-05-29 16:08:31 +02:00
1 parent 671a764c6a
commit d62fc46626
11 files changed
+308 -225

No files matched your search

+9 -9
View File
@@ -147,7 +147,7 @@ class KaTrainGui(Screen, KaTrainBase):
self.controls.update_players() self.controls.update_players()
self.update_state() self.update_state()
for player_setup_block in PlayerSetupBlock.INSTANCES: for player_setup_block in PlayerSetupBlock.INSTANCES:
player_setup_block.update_players(bw,self.players_info[bw]) player_setup_block.update_players(bw, self.players_info[bw])
def set_note(self, note): def set_note(self, note):
self.game.current_node.note = note self.game.current_node.note = note
@@ -215,7 +215,7 @@ class KaTrainGui(Screen, KaTrainBase):
def _do_new_game_popup(self): def _do_new_game_popup(self):
self.controls.timer.paused = True self.controls.timer.paused = True
if not self.new_game_popup: if not self.new_game_popup:
self.new_game_popup = I18NPopup(title_key="New Game title", size_hint=(0.5, 0.6), content=NewGamePopup(self)).__self__ self.new_game_popup = I18NPopup(title_key="New Game title", size=[800, 800], content=NewGamePopup(self)).__self__
self.new_game_popup.content.popup = self.new_game_popup self.new_game_popup.content.popup = self.new_game_popup
self.new_game_popup.open() self.new_game_popup.open()
@@ -226,6 +226,13 @@ class KaTrainGui(Screen, KaTrainBase):
self.timer_settings_popup.content.popup = self.timer_settings_popup self.timer_settings_popup.content.popup = self.timer_settings_popup
self.timer_settings_popup.open() self.timer_settings_popup.open()
def _do_teacher_popup(self):
self.controls.timer.paused = True
if not self.teacher_settings_popup:
self.teacher_settings_popup = I18NPopup(title_key="teacher settings", size=[800, 800], content=ConfigTeacherPopup(self)).__self__
self.teacher_settings_popup.content.popup = self.teacher_settings_popup
self.teacher_settings_popup.open()
# todo pop # todo pop
def _do_analyze_sgf_popup(self): def _do_analyze_sgf_popup(self):
@@ -264,13 +271,6 @@ class KaTrainGui(Screen, KaTrainBase):
self.ai_settings_popup.add_widget(ConfigAIPopupContents(self, self.ai_settings_popup)) self.ai_settings_popup.add_widget(ConfigAIPopupContents(self, self.ai_settings_popup))
self.ai_settings_popup.open() self.ai_settings_popup.open()
def _do_teacher_popup(self):
self.controls.timer.paused = True
if not self.teacher_settings_popup:
self.teacher_settings_popup = I18NPopup(title_key="Edit Teacher Settings", size_hint=(0.7, 0.8)).__self__
self.teacher_settings_popup.add_widget(ConfigTeacherPopup(self, self.teacher_settings_popup))
self.teacher_settings_popup.open()
def _do_output_sgf(self): def _do_output_sgf(self):
for pl in Move.PLAYERS: for pl in Move.PLAYERS:
if not self.game.root.get_property(f"P{pl}"): if not self.game.root.get_property(f"P{pl}"):
+12 -4
View File
@@ -12,10 +12,6 @@
"_hint_wide_root_noise": "A higher value here (typically 0.05-0.1)\nmakes the analysis explore more moves\nat the cost of some strength.", "_hint_wide_root_noise": "A higher value here (typically 0.05-0.1)\nmakes the analysis explore more moves\nat the cost of some strength.",
"_enable_ownership": true "_enable_ownership": true
}, },
"timer": {
"byo_length": 30,
"byo_periods": 5
},
"general": { "general": {
"sgf_load": "~/Downloads", "sgf_load": "~/Downloads",
"sgf_save": "./sgfout", "sgf_save": "./sgfout",
@@ -23,6 +19,10 @@
"debug_level": 1, "debug_level": 1,
"language": "en" "language": "en"
}, },
"timer": {
"byo_length": 30,
"byo_periods": 5
},
"game": { "game": {
"size": "19", "size": "19",
"komi": 6.5, "komi": 6.5,
@@ -55,6 +55,14 @@
true, true,
true true
], ],
"show_dots": [
true,
true,
true,
true,
true,
true
],
"eval_off_show_last": 3, "eval_off_show_last": 3,
"eval_show_ai": true, "eval_show_ai": true,
"lock_ai": false "lock_ai": false
-3
View File
@@ -90,7 +90,6 @@ class KaTrainBase:
except KeyError: except KeyError:
self.log(f"Missing configuration option {setting}", OUTPUT_ERROR) self.log(f"Missing configuration option {setting}", OUTPUT_ERROR)
def update_player(self, bw, **kwargs): def update_player(self, bw, **kwargs):
self.players_info[bw].update(**kwargs) self.players_info[bw].update(**kwargs)
@@ -100,7 +99,6 @@ class KaTrainBase:
for v in self.players_info.values(): for v in self.players_info.values():
v.periods_used = 0 v.periods_used = 0
@property @property
def last_player_info(self) -> Player: def last_player_info(self) -> Player:
return self.players_info[self.game.current_node.player] return self.players_info[self.game.current_node.player]
@@ -108,4 +106,3 @@ class KaTrainBase:
@property @property
def next_player_info(self) -> Player: def next_player_info(self) -> Player:
return self.players_info[self.game.current_node.next_player] return self.players_info[self.game.current_node.next_player]
+1 -1
View File
@@ -246,7 +246,7 @@ class Game:
if eval_thresholds is None: if eval_thresholds is None:
eval_thresholds = self.katrain.config("trainer/eval_thresholds") eval_thresholds = self.katrain.config("trainer/eval_thresholds")
player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P"+bw) or str(self.katrain.players_info[bw])) for bw in "BW" } player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw) or str(self.katrain.players_info[bw])) for bw in "BW"}
game_name = f"katrain_{player_names['B']} vs {player_names['W']} {self.game_id}" game_name = f"katrain_{player_names['B']} vs {player_names['W']} {self.game_id}"
file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf")) file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf"))
os.makedirs(os.path.dirname(file_name), exist_ok=True) os.makedirs(os.path.dirname(file_name), exist_ok=True)
+2 -7
View File
@@ -903,13 +903,7 @@
spacing: 3*CP_SPACING spacing: 3*CP_SPACING
padding: CP_PADDING padding: CP_PADDING
height: (self.parent.item_height or 50) * 5 height: (self.parent.item_height or 50) * 5
players: {'B':black,'W':white}
PlayerSetup:
player: 'B'
id: black
PlayerSetup:
player: 'W'
id: white
<HamburgerMenuContents@MDBoxLayout+BackgroundMixin>: <HamburgerMenuContents@MDBoxLayout+BackgroundMixin>:
katrain: app.gui katrain: app.gui
@@ -921,6 +915,7 @@
text: i18n._('menu:playersetup') text: i18n._('menu:playersetup')
PlayerSetupBlock: PlayerSetupBlock:
id: player_setup id: player_setup
update_global: True
MenuLabel: MenuLabel:
size_hint: 1,1 size_hint: 1,1
MenuLabel: MenuLabel:
+9 -5
View File
@@ -1,6 +1,7 @@
import copy import copy
import math import math
import time import time
from typing import List, Optional
from kivy.clock import Clock from kivy.clock import Clock
from kivy.graphics.context_instructions import Color from kivy.graphics.context_instructions import Color
@@ -136,7 +137,7 @@ class BadukPanWidget(Widget):
self.draw_hover_contents() # remove ghost self.draw_hover_contents() # remove ghost
# drawing functions # drawing functions
def redraw(self,*_args): def redraw(self, *_args):
self.draw_board() self.draw_board()
self.draw_board_contents() self.draw_board_contents()
@@ -155,10 +156,10 @@ class BadukPanWidget(Widget):
Color(*innercol) Color(*innercol)
Line(circle=(self.gridpos_x[x], self.gridpos_y[y], stone_size * 0.475 / 0.85), width=0.1 * stone_size) Line(circle=(self.gridpos_x[x], self.gridpos_y[y], stone_size * 0.475 / 0.85), width=0.1 * stone_size)
def eval_color(self, points_lost): def eval_color(self, points_lost, show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
colors = EVAL_COLORS
i = evaluation_class(points_lost, self.trainer_config["eval_thresholds"]) i = evaluation_class(points_lost, self.trainer_config["eval_thresholds"])
return colors[i] if show_dots_for_class is None or show_dots_for_class[i]:
return EVAL_COLORS[i]
def draw_board(self, *_args): def draw_board(self, *_args):
if not (self.katrain and self.katrain.game): if not (self.katrain and self.katrain.game):
@@ -236,8 +237,11 @@ class BadukPanWidget(Widget):
has_stone[m.coords] = m.player has_stone[m.coords] = m.player
show_dots_for = {p: self.trainer_config["eval_show_ai"] or katrain.game.players[p].human for p in Move.PLAYERS} show_dots_for = {p: self.trainer_config["eval_show_ai"] or katrain.game.players[p].human for p in Move.PLAYERS}
show_dots_for_class = self.trainer_config["show_dots"]
nodes = katrain.game.current_node.nodes_from_root nodes = katrain.game.current_node.nodes_from_root
realized_points_lost = None realized_points_lost = None
katrain.config("teacher/show_dots")
for i, node in enumerate(nodes[::-1]): # reverse order! for i, node in enumerate(nodes[::-1]): # reverse order!
points_lost = node.points_lost points_lost = node.points_lost
evalsize = 1 evalsize = 1
@@ -250,7 +254,7 @@ class BadukPanWidget(Widget):
if has_stone.get(m.coords) and not drawn_stone.get(m.coords): # skip captures, last only for if has_stone.get(m.coords) and not drawn_stone.get(m.coords): # skip captures, last only for
move_eval_on = show_dots_for.get(m.player) and (i < show_n_eval or full_eval_on) move_eval_on = show_dots_for.get(m.player) and (i < show_n_eval or full_eval_on)
if move_eval_on and points_lost is not None: if move_eval_on and points_lost is not None:
evalcol = self.eval_color(points_lost) evalcol = self.eval_color(points_lost, show_dots_for_class)
else: else:
evalcol = None evalcol = None
inner = stone_color[m.opponent] if i == 0 else None inner = stone_color[m.opponent] if i == 0 else None
+24 -15
View File
@@ -228,18 +228,6 @@ class StyledSpinner(Spinner):
item.font_name = self.font_name item.font_name = self.font_name
class PlayerSetupBlock(MDBoxLayout):
players = ObjectProperty(None)
INSTANCES = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
PlayerSetupBlock.INSTANCES.append(self)
def update_players(self, bw, player_info): # update sub widget based on gui state change
self.players[bw].update_widget(player_type=player_info.player_type, player_subtype=player_info.player_subtype)
class PlayerSetup(MDBoxLayout): class PlayerSetup(MDBoxLayout):
player = OptionProperty("B", options=["B", "W"]) player = OptionProperty("B", options=["B", "W"])
@@ -267,9 +255,30 @@ class PlayerSetup(MDBoxLayout):
self.player_subtype.select_key(player_subtype) # should trigger setup options self.player_subtype.select_key(player_subtype) # should trigger setup options
def update_global_player_info(self): def update_global_player_info(self):
katrain = MDApp.get_running_app().gui if self.parent and self.parent.update_global:
if katrain.game and katrain.game.current_node: katrain = MDApp.get_running_app().gui
katrain.update_player(self.player, **self.player_type_dump) if katrain.game and katrain.game.current_node:
katrain.update_player(self.player, **self.player_type_dump)
class PlayerSetupBlock(MDBoxLayout):
players = ObjectProperty(None)
black = ObjectProperty(None)
white = ObjectProperty(None)
update_global = BooleanProperty(False)
INSTANCES = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.black = PlayerSetup(player="B")
self.white = PlayerSetup(player="W")
self.players = {"B": self.black, "W": self.white}
self.add_widget(self.black)
self.add_widget(self.white)
PlayerSetupBlock.INSTANCES.append(self)
def update_players(self, bw, player_info): # update sub widget based on gui state change
self.players[bw].update_widget(player_type=player_info.player_type, player_subtype=player_info.player_subtype)
class PlayerInfo(MDBoxLayout, BackgroundMixin): class PlayerInfo(MDBoxLayout, BackgroundMixin):
+64 -179
View File
@@ -1,22 +1,21 @@
from collections import defaultdict from collections import defaultdict
from typing import Dict, List, DefaultDict, Tuple
import re import re
from typing import Dict, Tuple, Any, Union, List
from kivy.clock import Clock from kivy.clock import Clock
from kivy.properties import StringProperty, BooleanProperty from kivy.properties import StringProperty, BooleanProperty
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.selectioncontrol import MDCheckbox from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.uix.textfield import MDTextField from kivymd.uix.textfield import MDTextField
from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG, OUTPUT_INFO
from katrain.core.engine import KataGoEngine from katrain.core.engine import KataGoEngine
from katrain.core.game import Game, GameNode from katrain.core.utils import i18n
from katrain.gui.kivyutils import StyledSpinner from katrain.gui.kivyutils import StyledSpinner, BackgroundMixin
from katrain.gui.style import DEFAULT_FONT from katrain.gui.style import DEFAULT_FONT, EVAL_COLORS
class I18NPopup(Popup): class I18NPopup(Popup):
@@ -98,7 +97,7 @@ class QuickConfigGui(MDBoxLayout):
self.popup = None self.popup = None
Clock.schedule_once(lambda _dt: self.set_properties(self)) Clock.schedule_once(lambda _dt: self.set_properties(self))
def collect_properties(self, widget): def collect_properties(self, widget) -> Dict:
if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None): if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None):
try: try:
ret = {widget.input_property: widget.input_value} ret = {widget.input_property: widget.input_value}
@@ -111,17 +110,23 @@ class QuickConfigGui(MDBoxLayout):
ret[k] = v ret[k] = v
return ret return ret
def get_setting(self, key): def get_setting(self, key) -> Tuple[Any,Union[Dict,List],str]:
keys = key.split("/") keys = key.split("/")
config = self.katrain._config config = self.katrain._config
for k in keys[:-1]: for k in keys[:-1]:
if k not in config: if k not in config:
config[k] = {} config[k] = {}
config = config[k] config = config[k]
if keys[-1] not in config:
config[keys[-1]] = "" if "::" in keys[-1]:
self.katrain.log(f"Configuration setting {repr(key)} was missing, created it, but this likely indicates a broken config file.", OUTPUT_ERROR) arraykey, ix = keys[-1].split("::")
return config[keys[-1]], config, keys[-1] array = config[arraykey]
return array[int(ix)], array, ix
else:
if keys[-1] not in config:
config[keys[-1]] = ""
self.katrain.log(f"Configuration setting {repr(key)} was missing, created it, but this likely indicates a broken config file.", OUTPUT_ERROR)
return config[keys[-1]], config, keys[-1]
def set_properties(self, widget): def set_properties(self, widget):
if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None): if isinstance(widget, (LabelledTextInput, LabelledSpinner, LabelledCheckBox)) and getattr(widget, "input_property", None):
@@ -146,7 +151,7 @@ class QuickConfigGui(MDBoxLayout):
old_value, conf, key = self.get_setting(multikey) old_value, conf, key = self.get_setting(multikey)
if value != old_value: if value != old_value:
self.katrain.log(f"Updating setting {multikey} = {value}", OUTPUT_DEBUG) self.katrain.log(f"Updating setting {multikey} = {value}", OUTPUT_DEBUG)
conf[key] = value # reference straight back to katrain._config conf[key] = value # reference straight back to katrain._config - may be array or dict
updated.add(multikey) updated.add(multikey)
if save_to_file: if save_to_file:
self.katrain.save_config() self.katrain.save_config()
@@ -158,9 +163,6 @@ class QuickConfigGui(MDBoxLayout):
class ConfigTimerPopup(QuickConfigGui): class ConfigTimerPopup(QuickConfigGui):
def __init__(self, katrain):
super().__init__(katrain)
def update_config(self, save_to_file=True): def update_config(self, save_to_file=True):
super().update_config(save_to_file=save_to_file) super().update_config(save_to_file=save_to_file)
for p in self.katrain.players_info.values(): for p in self.katrain.players_info.values():
@@ -176,98 +178,66 @@ class NewGamePopup(QuickConfigGui):
self.rules_spinner.value_refs = [name for abbr, name in katrain.engine.RULESETS_ABBR] self.rules_spinner.value_refs = [name for abbr, name in katrain.engine.RULESETS_ABBR]
def update_config(self, save_to_file=True): def update_config(self, save_to_file=True):
updated = super().update_config(save_to_file=save_to_file) super().update_config(save_to_file=save_to_file)
self.katrain.log(f"New game settings: {self.katrain.config('game')}", OUTPUT_DEBUG) self.katrain.log(f"New game settings: {self.katrain.config('game')}", OUTPUT_DEBUG)
if self.restart.active: if self.restart.active:
self.katrain.log("Restarting Engine", OUTPUT_DEBUG) self.katrain.log("Restarting Engine", OUTPUT_DEBUG)
self.katrain.engine.restart() self.katrain.engine.restart()
for bw, player_setup in self.player_setup.players.items():
self.katrain.update_player(bw, **player_setup.player_type_dump)
self.katrain("new-game") self.katrain("new-game")
# for bw, player_widget in self.nav_drawer_contents.player_setup.players.items():
# self.players[bw].update(**player_widget.player_def) def wrap_anchor(widget):
anchor = AnchorLayout()
anchor.add_widget(widget)
return anchor
class ConfigTeacherPopup(QuickConfigGui):
def __init__(self, katrain):
self.build()
super().__init__(katrain)
def add_option_widgets(self, widgets):
for widget in widgets:
self.options_grid.add_widget(wrap_anchor(widget))
def build(self):
undos = self.katrain.config("trainer/num_undo_prompts")
thresholds = self.katrain.config("trainer/eval_thresholds")
savesgfs = self.katrain.config("trainer/save_feedback")
show_dots = self.katrain.config("trainer/show_dots")
for i, (color, threshold, undo, show_dot, savesgf) in enumerate(zip(EVAL_COLORS, thresholds, undos, show_dots, savesgfs)):
self.add_option_widgets(
[
BackgroundMixin(background_color=color[:3]),
LabelledFloatInput(text=str(threshold), input_property=f"trainer/eval_thresholds::{i}"),
LabelledFloatInput(text=str(undo), input_property=f"trainer/num_undo_prompts::{i}"),
LabelledCheckBox(text=str(show_dot), input_property=f"trainer/show_dots::{i}"),
LabelledCheckBox(text=str(savesgf), input_property=f"trainer/save_feedback::{i}"),
]
)
class ConfigPopup(QuickConfigGui): class ConfigPopup(QuickConfigGui):
def __init__(self, katrain, popup: Popup, config: Dict, ignore_cats: Tuple = (), **kwargs): def update_config(self, save_to_file=True):
self.config = config updated = super().update_config(save_to_file=save_to_file)
self.ignore_cats = ignore_cats self.katrain.debug_level = self.katrain.config("general/debug_level", OUTPUT_INFO)
self.orientation = "vertical"
super().__init__(katrain, popup, **kwargs)
Clock.schedule_once(self.build, 0)
def build(self, _): ignore = {"max_visits", "max_time", "enable_ownership", "wide_root_noise"}
detected_restart = [key for key in updated if "engine" in key and not any(ig in key for ig in ignore)]
props_in_col = [0, 0] if detected_restart:
cols = [BoxLayout(orientation="vertical"), BoxLayout(orientation="vertical")]
for k1, all_d in sorted(self.config.items(), key=lambda tup: -len(tup[1])): # sort to make greedy bin packing work better
if k1 in self.ignore_cats:
continue
d = {k: v for k, v in all_d.items() if isinstance(v, (int, float, str, bool)) and not k.startswith("_")} # no lists . dict could be supported but hard to scale
cat = GridLayout(cols=2, rows=len(d) + 1, size_hint=(1, len(d) + 1))
cat.add_widget(Label(text=""))
cat.add_widget(ScaledLightLabel(text=f"{k1} settings", bold=True))
for k2, v in d.items():
label = ScaledLightLabel(text=f"{k2}:")
widget = self.type_to_widget_class(v)(text=str(v), input_property=f"{k1}/{k2}")
hint = all_d.get("_hint_" + k2)
if hint:
label.tooltip_text = hint
if isinstance(widget, LabelledTextInput):
widget.hint_text = hint
cat.add_widget(label)
cat.add_widget(widget)
if props_in_col[0] <= props_in_col[1]:
cols[0].add_widget(cat)
props_in_col[0] += len(d)
else:
cols[1].add_widget(cat)
props_in_col[1] += len(d)
col_container = BoxLayout(size_hint=(1, 0.9))
col_container.add_widget(cols[0])
col_container.add_widget(cols[1])
self.add_widget(col_container)
self.info_label = Label(halign="center")
self.apply_button = StyledButton(text="Apply", on_press=lambda _: self.update_config())
self.save_button = StyledButton(text="Apply and Save", on_press=lambda _: self.update_config(save_to_file=True))
btn_container = BoxLayout(orientation="horizontal", size_hint=(1, 0.1), spacing=1, padding=1)
btn_container.add_widget(self.apply_button)
btn_container.add_widget(self.info_label)
btn_container.add_widget(self.save_button)
self.add_widget(btn_container)
def update_config(self, save_to_file=False):
updated_cat = defaultdict(list) # type: DefaultDict[List[str]]
try:
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[k1].append(k2)
self.config[k1][k2] = v
self.popup.dismiss()
except InputParseError as e:
self.info_label.text = str(e)
self.katrain.log(e, OUTPUT_ERROR)
return
if save_to_file:
self.katrain.save_config()
engine_updates = updated_cat["engine"]
if "visits" in engine_updates:
self.katrain.engine.visits = engine_updates["visits"]
if {key for key in engine_updates if key not in {"max_visits", "max_time", "enable_ownership", "wide_root_noise"}}:
self.katrain.log(f"Restarting Engine after {engine_updates} settings change")
self.info_label.text = "Restarting engine\nplease wait."
self.katrain.controls.set_status(f"Restarted Engine after {engine_updates} settings change.")
def restart_engine(_dt): def restart_engine(_dt):
self.katrain.log(f"Restarting Engine after {detected_restart} settings change")
self.katrain.controls.set_status(i18n._("restarting engine"))
old_engine = self.katrain.engine # type: KataGoEngine old_engine = self.katrain.engine # type: KataGoEngine
old_proc = old_engine.katago_process old_proc = old_engine.katago_process
if old_proc: if old_proc:
old_engine.shutdown(finish=True) old_engine.shutdown(finish=False)
new_engine = KataGoEngine(self.katrain, self.config["engine"]) new_engine = KataGoEngine(self.katrain, self.config["engine"])
self.katrain.engine = new_engine self.katrain.engine = new_engine
self.katrain.game.engines = {"B": new_engine, "W": new_engine} self.katrain.game.engines = {"B": new_engine, "W": new_engine}
@@ -276,91 +246,6 @@ class ConfigPopup(QuickConfigGui):
Clock.schedule_once(restart_engine, 0) Clock.schedule_once(restart_engine, 0)
self.katrain.debug_level = self.config["debug"]["level"]
self.katrain.update_state(redraw_board=True)
class LoadSGFPopup(BoxLayout): class LoadSGFPopup(BoxLayout):
pass pass
class ConfigTeacherPopup(QuickConfigGui):
def __init__(self, katrain, popup, **kwargs):
self.settings = katrain.config("trainer")
self.sgf_settings = katrain.config("sgf")
self.ui_settings = katrain.config("board_ui")
super().__init__(katrain, popup, self.settings, **kwargs)
self.spacing = 2
Clock.schedule_once(self.build, 0)
def build(self, _dt):
thresholds = self.settings["eval_thresholds"]
undos = self.settings["num_undo_prompts"]
colors = self.ui_settings["eval_colors"]
thrbox = GridLayout(spacing=1, padding=2, cols=5, rows=len(thresholds) + 1)
thrbox.add_widget(ScaledLightLabel(text="Point loss greater than", bold=True))
thrbox.add_widget(ScaledLightLabel(text="Gives this many undos", bold=True))
thrbox.add_widget(ScaledLightLabel(text="Color (fixed)", bold=True))
thrbox.add_widget(ScaledLightLabel(text="Show dots", bold=True))
thrbox.add_widget(ScaledLightLabel(text="Save in SGF", bold=True))
for i, (thr, undos, color) in enumerate(zip(thresholds, undos, colors)):
thrbox.add_widget(LabelledFloatInput(text=str(thr), input_property=f"eval_thresholds::{i}"))
thrbox.add_widget(LabelledFloatInput(text=str(undos), input_property=f"num_undo_prompts::{i}"))
thrbox.add_widget(BackgroundMixin(background_color=color[:3]))
thrbox.add_widget(LabelledCheckBox(text=str(color[3] == 1), input_property=f"alpha::{i}"))
thrbox.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.sgf_settings["save_feedback"][i]), input_property=f"save_feedback::{i}"))
self.add_widget(thrbox)
xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2)
xsettings.add_widget(ScaledLightLabel(text="Show last <n> dots"))
xsettings.add_widget(LabelledIntInput(size_hint=(0.5, 1), text=str(self.settings["eval_off_show_last"]), input_property="eval_off_show_last"))
self.add_widget(xsettings)
xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2)
xsettings.add_widget(ScaledLightLabel(text="Show dots/SGF comments for AI players"))
xsettings.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.settings["eval_show_ai"]), input_property="eval_show_ai"))
self.add_widget(xsettings)
xsettings = BoxLayout(size_hint=(1, 0.15), spacing=2)
xsettings.add_widget(ScaledLightLabel(text="Disable analysis while in teach mode"))
xsettings.add_widget(LabelledCheckBox(size_hint=(0.5, 1), text=str(self.settings["lock_ai"]), input_property="lock_ai"))
self.add_widget(xsettings)
bl = BoxLayout(size_hint=(1, 0.15), spacing=2)
bl.add_widget(StyledButton(text=f"Apply", on_press=lambda _: self.update_config(False)))
self.info_label = Label()
bl.add_widget(self.info_label)
bl.add_widget(StyledButton(text=f"Apply and Save", on_press=lambda _: self.update_config(True)))
self.add_widget(bl)
def update_config(self, save_to_file=False):
try:
for k, v in self.collect_properties(self).items():
if "::" in k:
k1, i = k.split("::")
i = int(i)
if "alpha" in k1:
v = 1.0 if v else 0.0
if self.ui_settings["eval_colors"][i][3] != v:
self.katrain.log(f"Updating alpha {i} = {v}", OUTPUT_DEBUG)
self.ui_settings["eval_colors"][i][3] = v
elif "save_feedback" in k1:
if self.sgf_settings[k1][i] != v:
self.sgf_settings[k1][i] = v
self.katrain.log(f"Updating setting sgf/{k1}[{i}] = {v}", OUTPUT_DEBUG)
else:
if self.settings[k1][i] != v:
self.settings[k1][i] = v
self.katrain.log(f"Updating setting trainer/{k1}[{i}] = {v}", OUTPUT_DEBUG)
else:
if self.settings[k] != v:
self.settings[k] = v
self.katrain.log(f"Updating setting {k} = {v}", OUTPUT_DEBUG)
if save_to_file:
self.katrain.save_config()
self.popup.dismiss()
except InputParseError as e:
self.info_label.text = str(e)
self.katrain.log(e, OUTPUT_ERROR)
return
self.katrain.update_state()
self.popup.dismiss()
Binary file not shown.
+41 -1
View File
@@ -20,7 +20,7 @@ msgid "menu:load"
msgstr "Load Game" msgstr "Load Game"
msgid "menu:settings" msgid "menu:settings"
msgstr "General Settings" msgstr "General & Engine Settings"
msgid "menu:clocksettings" msgid "menu:clocksettings"
msgstr "Timer Settings" msgstr "Timer Settings"
@@ -278,6 +278,46 @@ msgstr "Note that handicaps above 9 are not supported on non-square boards."
msgid "new game" msgid "new game"
msgstr "Start New Game" msgstr "Start New Game"
# teacher settings from here
msgstr "teacher settings"
msgid "Edit Teacher Settings"
msgid "point loss threshold"
msgstr "Point loss greater than"
msgid "num undos"
msgstr "Number of undos"
msgid "num undos"
msgstr "Number of undos"
msgid "dot color"
msgstr "Colour (fixed)"
msgid "show dots"
msgstr "Show dots"
msgid "save dots"
msgstr "Save in SGF"
msgid "show last n dots"
msgstr "Show dots for the last <this many> moves"
msgid "show ai dots"
msgstr "Show dots/SGF comments for AI players"
msgid "lock ai when teaching"
msgstr "Disable analysis while in teach mode"
#. submit button
msgid "update teacher"
msgstr "Update Teaching Game Settings"
#main config settings
msgid "restarting engine"
msgstr "Restarting Engine after Settings Change."
#. misc errors and info messages #. misc errors and info messages
msgid "sgf written" msgid "sgf written"
msgstr "SGF with analysis written to {file_name}" msgstr "SGF with analysis written to {file_name}"
+146 -1
View File
@@ -43,7 +43,7 @@
font_size: DESC_FONT_SIZE font_size: DESC_FONT_SIZE
<I18NPopup>: <I18NPopup>:
background_color: [*[c*255/66 for c in BACKGROUND_COLOR[:3]], 1] #background_color: [*[c*255/66 for c in BACKGROUND_COLOR[:3]], 1]
title: i18n._(self.title_key) title: i18n._(self.title_key)
title_size: DESC_FONT_SIZE title_size: DESC_FONT_SIZE
title_font: self.font_name title_font: self.font_name
@@ -65,6 +65,144 @@
<SmallDescriptionLabel@DescriptionLabel> <SmallDescriptionLabel@DescriptionLabel>
font_size: DESC_FONT_SIZE * 0.66 font_size: DESC_FONT_SIZE * 0.66
<ConfigPopup>:
BoxLayout:
orientation: 'horizontal'
GridLayout:
cols: 2
rows: 9
spacing: CP_SPACING
Label:
Label:
text: 'engine'
DescriptionLabel:
text: i18n._("general:sgf_load")
AnchorLayout:
LabelledTextInput:
input_property: "general/sgf_load" # just last load dir?
DescriptionLabel:
text: i18n._("general:sgf_save")
AnchorLayout:
LabelledTextInput:
input_property: "general/sgf_save"
DescriptionLabel:
text: i18n._("general:anim_pv_time")
AnchorLayout:
LabelledFloatInput:
input_property: "general/anim_pv_time"
DescriptionLabel:
text: i18n._("general:debug_level")
AnchorLayout:
LabelledIntInput:
input_property: "general/debug_level"
BackgroundMixing:
background_color: LIGHTGREY
size_hint: None, 1
width: 2
GridLayout:
cols: 2
rows: 9
spacing: CP_SPACING
Label:
Label:
text: 'engine'
DescriptionLabel:
text: i18n._("engine:katago")
AnchorLayout:
LabelledTextInput:
input_property: "engine/katago"
DescriptionLabel:
text: i18n._("engine:model")
AnchorLayout:
LabelledTextInput:
input_property: "engine/model"
DescriptionLabel:
text: i18n._("engine:config")
AnchorLayout:
LabelledTextInput:
input_property: "engine/config"
DescriptionLabel:
text: i18n._("engine:max_visits")
AnchorLayout:
LabelledIntInput:
input_property: "engine/max_visits"
DescriptionLabel:
text: i18n._("engine:max_time")
AnchorLayout:
LabelledFloatInput:
input_property: "engine/fast_visits"
DescriptionLabel:
text: i18n._("engine:fast_visits")
AnchorLayout:
LabelledFloatInput:
input_property: "engine/max_time"
DescriptionLabel:
text: i18n._("engine:threads")
AnchorLayout:
LabelledIntInput:
input_property: "engine/threads"
DescriptionLabel:
text: i18n._("engine:wide_root_noise")
AnchorLayout:
LabelledFloatInput:
input_property: "engine/wide_root_noise"
AnchorLayout:
size_hint: 1,1
AutoSizedRoundedRectangleButton:
padding_x: 15
size_hint: None,0.5
text: i18n._("update settings")
on_press: root.update_config(True)
<ConfigTeacherPopup>
options_grid: options_grid
GridLayout:
cols: 5
rows: 7
size_hint: 1, 7
id: options_grid
DescriptionLabel:
text: i18n._("dot color")
DescriptionLabel:
text: i18n._("point loss threshold")
DescriptionLabel:
text: i18n._("num undos")
DescriptionLabel:
text: i18n._("show dots")
DescriptionLabel:
text: i18n._("save dots")
GridLayout:
cols: 2
rows: 3
size_hint: 1, 3
DescriptionLabel:
text: i18n._("show last n dots")
AnchorLayout:
LabelledIntInput:
input_property: "trainer/eval_off_show_last"
DescriptionLabel:
text: i18n._("show ai dots")
AnchorLayout:
LabelledIntInput:
input_property: "trainer/eval_off_show_last"
DescriptionLabel:
text: i18n._("show last n dots")
AnchorLayout:
LabelledIntInput:
input_property: "trainer/eval_show_ai"
DescriptionLabel:
text: i18n._("lock ai when teaching")
AnchorLayout:
LabelledCheckBox:
input_property: "trainer/lock_ai"
AnchorLayout:
size_hint: 1,1
AutoSizedRoundedRectangleButton:
padding_x: 15
size_hint: None,0.5
text: i18n._("update teacher")
on_press: root.update_config(True)
<ConfigTimerPopup>: <ConfigTimerPopup>:
MDGridLayout: MDGridLayout:
@@ -103,6 +241,10 @@
<NewGamePopup>: <NewGamePopup>:
restart: restart restart: restart
rules_spinner: rules_spinner rules_spinner: rules_spinner
player_setup: player_setup
PlayerSetupBlock:
size_hint: 1, 2
id: player_setup
GridLayout: GridLayout:
rows: 6 rows: 6
cols: 3 cols: 3
@@ -199,6 +341,9 @@
on_press: root.update_config(True) on_press: root.update_config(True)
<NewLoadSGFPopup>:
FileBrowser:
# old # old
<LoadSGFPopup>: <LoadSGFPopup>: