scroll, double click
This commit is contained in:
1 parent
e7b9f4be5b
commit
0de3335cd1
5 files changed
+34
-44
No files matched your search
@@ -97,30 +97,11 @@ In addition to these, there are:
|
|||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
Configuration is stored in `config.json`. Most settings are available to edit in the program, but some are not.
|
Configuration is stored in `config.json`. Most settings are now available to edit in the program, but
|
||||||
|
some cosmetic options are now.
|
||||||
You can use `python katrain.py your_config_file.json` to use another config file instead.
|
You can use `python katrain.py your_config_file.json` to use another config file instead.
|
||||||
|
|
||||||
#### The settings panel
|
If you ever need to reset to the original settings, simply re-download the `config.json` file in this repository.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The `trainer` block has the following options to tweak for engine assisted play and reviewing:
|
|
||||||
|
|
||||||
* `eval_off_show_last`: when the `eval` checkbox is off for a player, show coloured dots on the last this many moves regardless.
|
|
||||||
* `undo_eval_threshold`, `undo_point_threshold`: prompt player to undo if move is worse than this in terms of points AND evaluation.
|
|
||||||
|
|
||||||
The following options are relevant for the `balance score` AI play mode.
|
|
||||||
|
|
||||||
* `balance_play_target_score`: indicates how many points the AI aims to win by when using 'balance score'.
|
|
||||||
* `balance_play_randomize_eval`: when not needing to balance score, the AI will pick a random move which is at least this good as long as it stays ahead.
|
|
||||||
* `balance_play_min_eval`: when needing to balance score, the AI will pick a move which is at least this good.
|
|
||||||
* `balance_play_min_visits`: never pick a move with fewer playouts than this.
|
|
||||||
|
|
||||||
The cfg file has additional configuration for KataGo, which are documented there.
|
|
||||||
|
|
||||||
#### Configuring feedback
|
|
||||||
|
|
||||||
* `num_undo_prompts`: automatically undo bad moves when `undo` is on at most this many times. Can be a fraction like 0.5 for 50% chance of being granted an undo on a bad move.
|
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,13 @@ Low priority
|
|||||||
[] more teaching / groups in danger? hard
|
[] more teaching / groups in danger? hard
|
||||||
[] When creating a new game, the 9 buttons on the right side aren't all that useful. Maybe the 9, 13 and 19 ones make sense since these three board sizes are the traditionally used ones, but why 2, 4 and 9 stones buttons? Why 0.5, 6.5 and -40pts komi buttons?
|
[] When creating a new game, the 9 buttons on the right side aren't all that useful. Maybe the 9, 13 and 19 ones make sense since these three board sizes are the traditionally used ones, but why 2, 4 and 9 stones buttons? Why 0.5, 6.5 and -40pts komi buttons?
|
||||||
[] Score instead of game end
|
[] Score instead of game end
|
||||||
|
[] Plus, explanatory bubbles would help to clarify labels like "Debug" (are there bugs in the matrix? :p), "enable_ownership" (which didn't seem to prevent or allow visualizing territory ownership on the board, as that was already covered by the "owner" checkbox anyway... so I guess I missed something), etc.
|
||||||
|
-- possible right-click?
|
||||||
|
|
||||||
Wont do for now
|
Wont do for now
|
||||||
[] dual engine support -- easily possible but has weird effects on win rate etc
|
[] dual engine support -- easily possible but has weird effects on win rate etc
|
||||||
[/] The UI would be directly understood if there were bubbles with a short explanation popping up when hovering above buttons and labels, e.g "Performing additional analysis to 1502 visits" which appears currently in the comments window after pushing the Extra button would also make a perfect explanatory bubble when hovering over said button too.
|
[/] The UI would be directly understood if there were bubbles with a short explanation popping up when hovering above buttons and labels, e.g "Performing additional analysis to 1502 visits" which appears currently in the comments window after pushing the Extra button would also make a perfect explanatory bubble when hovering over said button too.
|
||||||
|
|
||||||
--- partially solved by config with help for some
|
--- partially solved by config with help for some
|
||||||
|
|
||||||
bug/suggestion reports
|
|
||||||
-- Plus, explanatory bubbles would help to clarify labels like "Debug" (are there bugs in the matrix? :p), "enable_ownership" (which didn't seem to prevent or allow visualizing territory ownership on the board, as that was already covered by the "owner" checkbox anyway... so I guess I missed something), etc.
|
|
||||||
|
|
||||||
@@ -43,8 +43,7 @@ class Game:
|
|||||||
self.komi = self.config.get("init_komi", {}).get(str(board_size), 6.5)
|
self.komi = self.config.get("init_komi", {}).get(str(board_size), 6.5)
|
||||||
self.root = GameNode(properties={**Game.DEFAULT_PROPERTIES, **{"SZ": board_size, "KM": self.komi, "DT": self.game_id}})
|
self.root = GameNode(properties={**Game.DEFAULT_PROPERTIES, **{"SZ": board_size, "KM": self.komi, "DT": self.game_id}})
|
||||||
|
|
||||||
self.current_node = self.root
|
self.set_current_node(self.root)
|
||||||
self._init_chains()
|
|
||||||
threading.Thread(target=lambda: self.analyze_all_nodes(-1_000_000, analyze_fast=analyze_fast), daemon=True).start() # return faster, but bypass Kivy Clock
|
threading.Thread(target=lambda: self.analyze_all_nodes(-1_000_000, analyze_fast=analyze_fast), daemon=True).start() # return faster, but bypass Kivy Clock
|
||||||
|
|
||||||
def analyze_all_nodes(self, priority=0, analyze_fast=False):
|
def analyze_all_nodes(self, priority=0, analyze_fast=False):
|
||||||
@@ -52,7 +51,7 @@ class Game:
|
|||||||
node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast)
|
node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast)
|
||||||
|
|
||||||
# -- move tree functions --
|
# -- move tree functions --
|
||||||
def _init_chains(self):
|
def _calculate_groups(self):
|
||||||
board_size_x, board_size_y = self.board_size
|
board_size_x, board_size_y = self.board_size
|
||||||
self.board = [[-1 for _x in range(board_size_x)] for _y in range(board_size_y)] # type: List[List[int]] # board pos -> chain id
|
self.board = [[-1 for _x in range(board_size_x)] for _y in range(board_size_y)] # type: List[List[int]] # board pos -> chain id
|
||||||
self.chains = [] # type: List[List[Move]] # chain id -> chain
|
self.chains = [] # type: List[List[Move]] # chain id -> chain
|
||||||
@@ -121,7 +120,7 @@ class Game:
|
|||||||
try:
|
try:
|
||||||
self._validate_move_and_update_chains(move, ignore_ko)
|
self._validate_move_and_update_chains(move, ignore_ko)
|
||||||
except IllegalMoveException:
|
except IllegalMoveException:
|
||||||
self._init_chains()
|
self._calculate_groups()
|
||||||
raise
|
raise
|
||||||
played_node = self.current_node.play(move)
|
played_node = self.current_node.play(move)
|
||||||
self.current_node = played_node
|
self.current_node = played_node
|
||||||
@@ -129,28 +128,29 @@ class Game:
|
|||||||
played_node.analyze(self.engines[played_node.next_player])
|
played_node.analyze(self.engines[played_node.next_player])
|
||||||
return played_node
|
return played_node
|
||||||
|
|
||||||
|
def set_current_node(self, node):
|
||||||
|
self.current_node = node
|
||||||
|
self._calculate_groups()
|
||||||
|
|
||||||
def undo(self, n_times=1):
|
def undo(self, n_times=1):
|
||||||
cn = self.current_node # avoid race conditions
|
cn = self.current_node # avoid race conditions
|
||||||
for _ in range(n_times):
|
for _ in range(n_times):
|
||||||
if not cn.is_root:
|
if not cn.is_root:
|
||||||
cn = cn.parent
|
cn = cn.parent
|
||||||
self.current_node = cn
|
self.set_current_node(cn)
|
||||||
self._init_chains()
|
|
||||||
|
|
||||||
def redo(self, n_times=1):
|
def redo(self, n_times=1):
|
||||||
cn = self.current_node # avoid race conditions
|
cn = self.current_node # avoid race conditions
|
||||||
for _ in range(n_times):
|
for _ in range(n_times):
|
||||||
if cn.children:
|
if cn.children:
|
||||||
cn = cn.children[-1]
|
cn = cn.children[-1]
|
||||||
self.current_node = cn
|
self.set_current_node(cn)
|
||||||
self._init_chains()
|
|
||||||
|
|
||||||
def switch_branch(self, direction):
|
def switch_branch(self, direction):
|
||||||
cn = self.current_node # avoid race conditions
|
cn = self.current_node # avoid race conditions
|
||||||
if cn.parent and len(cn.parent.children) > 1:
|
if cn.parent and len(cn.parent.children) > 1:
|
||||||
ix = cn.parent.children.index(cn)
|
ix = cn.parent.children.index(cn)
|
||||||
self.current_node = cn.parent.children[(ix + direction) % len(cn.parent.children)]
|
self.set_current_node(cn.parent.children[(ix + direction) % len(cn.parent.children)])
|
||||||
self._init_chains()
|
|
||||||
|
|
||||||
def place_handicap_stones(self, n_handicaps):
|
def place_handicap_stones(self, n_handicaps):
|
||||||
board_size_x, board_size_y = self.board_size
|
board_size_x, board_size_y = self.board_size
|
||||||
|
|||||||
+11
-10
@@ -71,23 +71,25 @@ class BadukPanWidget(Widget):
|
|||||||
self.draw_hover_contents()
|
self.draw_hover_contents()
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
def on_touch_up(self, touch):
|
||||||
if touch.button != "left":
|
if touch.button != "left" or not self.gridpos_x:
|
||||||
return
|
|
||||||
|
|
||||||
if not self.gridpos_x:
|
|
||||||
return
|
return
|
||||||
katrain = self.katrain
|
katrain = self.katrain
|
||||||
if self.ghost_stone:
|
if self.ghost_stone and touch.button == "left":
|
||||||
katrain("play", self.ghost_stone)
|
katrain("play", self.ghost_stone)
|
||||||
else:
|
elif not self.ghost_stone:
|
||||||
xd, xp = self._find_closest(touch.x, self.gridpos_x)
|
xd, xp = self._find_closest(touch.x, self.gridpos_x)
|
||||||
yd, yp = self._find_closest(touch.y, self.gridpos_y)
|
yd, yp = self._find_closest(touch.y, self.gridpos_y)
|
||||||
|
|
||||||
nodes_here = [node for node in katrain.game.current_node.nodes_from_root if node.single_move and node.single_move.coords == (xp, yp)]
|
nodes_here = [node for node in katrain.game.current_node.nodes_from_root if node.single_move and node.single_move.coords == (xp, yp)]
|
||||||
if nodes_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
if nodes_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
||||||
katrain.log(f"\nAnalysis:\n{nodes_here[-1].analysis}", OUTPUT_DEBUG)
|
if touch.is_double_tap: # navigate to move
|
||||||
katrain.log(f"\nParent Analysis:\n{nodes_here[-1].parent.analysis}", OUTPUT_DEBUG)
|
katrain.game.set_current_node(nodes_here[-1])
|
||||||
katrain.controls.info.text = nodes_here[-1].comment(sgf=True)
|
self.draw_board_contents()
|
||||||
|
else: # load comments
|
||||||
|
katrain.log(f"\nAnalysis:\n{nodes_here[-1].analysis}", OUTPUT_DEBUG)
|
||||||
|
katrain.log(f"\nParent Analysis:\n{nodes_here[-1].parent.analysis}", OUTPUT_DEBUG)
|
||||||
|
katrain.controls.info.text = nodes_here[-1].comment(sgf=True)
|
||||||
|
katrain.controls.info.text = nodes_here[-1].comment(sgf=True)
|
||||||
|
|
||||||
self.ghost_stone = None
|
self.ghost_stone = None
|
||||||
self.draw_hover_contents() # remove ghost
|
self.draw_hover_contents() # remove ghost
|
||||||
@@ -191,7 +193,6 @@ class BadukPanWidget(Widget):
|
|||||||
realized_points_lost = None
|
realized_points_lost = None
|
||||||
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
|
||||||
print("node", node.single_move, "pl", points_lost, "rpl", realized_points_lost)
|
|
||||||
evalsize = 1
|
evalsize = 1
|
||||||
if points_lost and realized_points_lost:
|
if points_lost and realized_points_lost:
|
||||||
if points_lost <= 0.5 and realized_points_lost <= 1.5:
|
if points_lost <= 0.5 and realized_points_lost <= 1.5:
|
||||||
|
|||||||
@@ -228,6 +228,13 @@ class KaTrainGui(BoxLayout):
|
|||||||
self.log(msg, OUTPUT_INFO)
|
self.log(msg, OUTPUT_INFO)
|
||||||
self.controls.set_status(msg)
|
self.controls.set_status(msg)
|
||||||
|
|
||||||
|
def on_touch_up(self, touch):
|
||||||
|
if touch.button == "scrollup":
|
||||||
|
self("redo")
|
||||||
|
elif touch.button == "scrolldown":
|
||||||
|
self("undo")
|
||||||
|
return super().on_touch_up(touch)
|
||||||
|
|
||||||
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
|
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
|
||||||
if isinstance(App.get_running_app().root_window.children[0], Popup):
|
if isinstance(App.get_running_app().root_window.children[0], Popup):
|
||||||
return # if in new game or load, don't allow keyboard shortcuts
|
return # if in new game or load, don't allow keyboard shortcuts
|
||||||
|
|||||||
Reference in new issue
Block a user