From a02697c7830b67f0053182ff64e058aebcccbd5a Mon Sep 17 00:00:00 2001 From: Sander Land Date: Sat, 5 Dec 2020 16:44:39 +0100 Subject: [PATCH] back to branching point --- README.md | 5 +++-- katrain/__main__.py | 5 +++-- katrain/core/engine.py | 3 +-- katrain/core/game.py | 27 +++++++++++++++++---------- katrain/core/game_node.py | 2 +- katrain/gui/badukpan.py | 16 +++++++--------- katrain/gui/controlspanel.py | 7 ++++++- katrain/gui/widgets/movetree.py | 2 +- 8 files changed, 39 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 1390f51..260810c 100644 --- a/README.md +++ b/README.md @@ -179,10 +179,11 @@ In addition to shortcuts mentioned above and those shown in the main menu: * **[p]**: Pass * **[b]**: Pause/Resume timer * **[arrow left]** or **[z]**: Undo move. Hold alt for 10 moves at a time, or ctrl to skip to the start. -* **[arrow right]** or **[x]**: Redo move. Hold alt for 10 moves at a time, or ctrl to skip to the start. +* **[arrow right]** or **[x]**: Redo move. Hold alt for 10 moves at a time, or ctrl to skip to the end. * **[arrow up/down]** Switch branch, as would be expected from the move tree. -* **[n]** As in clicking the red arrow, go to one move before the next mistake (orange or worse) by a human player. * **[home/end]** Go to the beginning/end of the game. +* **[b]** Go back to the previous branching point. +* **[n]** As in clicking the red arrow, go to one move before the next mistake (orange or worse) by a human player. * **[scroll up]**: Undo move. Only works when hovering the cursor over the board. * **[scroll down]**: Redo move. Only works when hovering the cursor over the board. * **[click on a move]**: See detailed statistics for a previous move, along with expected variation that was best instead of this move. diff --git a/katrain/__main__.py b/katrain/__main__.py index 97f24cb..8c5c24c 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -430,12 +430,12 @@ class KaTrainGui(Screen, KaTrainBase): save_game_popup.dismiss() path, file = os.path.split(filename.strip()) if not path: - path = popup_contents.filesel.path # whatever dir is shown + path = popup_contents.filesel.path # whatever dir is shown if path != self.config("general/sgf_save"): self.log(f"Updating sgf save path default to {path}", OUTPUT_DEBUG) self._config["general"]["sgf_save"] = path self.save_config("general") - self._do_save_game(os.path.join(path,file)) + self._do_save_game(os.path.join(path, file)) popup_contents.filesel.on_success = readfile popup_contents.filesel.on_submit = readfile @@ -499,6 +499,7 @@ class KaTrainGui(Screen, KaTrainBase): "i": ("insert-mode",), "p": ("play", None), "n": ("next-mistake",), + "b": ("undo", "branch"), "down": ("switch-branch", 1), "up": ("switch-branch", -1), "f5": ("timer-popup",), diff --git a/katrain/core/engine.py b/katrain/core/engine.py index a5f67ff..d3c1a9e 100644 --- a/katrain/core/engine.py +++ b/katrain/core/engine.py @@ -112,7 +112,6 @@ class KataGoEngine: self.terminate_query(query_id) self.queries = {} - def restart(self): self.queries = {} self.shutdown(finish=False) @@ -250,7 +249,7 @@ class KataGoEngine: analyze_fast: bool = False, time_limit=True, find_alternatives: bool = False, - region_of_interest: Optional[List] = None, + region_of_interest: Optional[List] = None, priority: int = 0, ownership: Optional[bool] = None, next_move: Optional[GameNode] = None, diff --git a/katrain/core/game.py b/katrain/core/game.py index f68799f..00d8bac 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -236,8 +236,8 @@ class Game: self.current_node = played_node if analyze: if self.region_of_interest: - played_node.analyze(self.engines[played_node.next_player],analyze_fast=True) - played_node.analyze(self.engines[played_node.next_player],region_of_interest=self.region_of_interest) + played_node.analyze(self.engines[played_node.next_player], analyze_fast=True) + played_node.analyze(self.engines[played_node.next_player], region_of_interest=self.region_of_interest) else: played_node.analyze(self.engines[played_node.next_player]) return played_node @@ -259,10 +259,15 @@ class Game: self.current_node = cn.parent self._calculate_groups() return - + break_on_branch = False + if n_times == "branch": + n_times = 9999 + break_on_branch = True for _ in range(n_times): if not cn.is_root: cn = cn.parent + if break_on_branch and len(cn.children) > 1: + break self.set_current_node(cn) def redo(self, n_times=1, stop_on_mistake=None): @@ -416,16 +421,16 @@ class Game: f.write(sgf) return i18n._("sgf written").format(file_name=filename) - def set_region_of_interest(self,region_of_interest): - x1, x2, y1, y2 =region_of_interest + def set_region_of_interest(self, region_of_interest): + x1, x2, y1, y2 = region_of_interest xmin, xmax = min(x1, x2), max(x1, x2) ymin, ymax = min(y1, y2), max(y1, y2) - if not (xmin==xmax and ymin==ymax): - self.region_of_interest = [xmin,xmax,ymin,ymax] + szx, szy = self.board_size + if not (xmin == xmax and ymin == ymax) and not (xmax - xmin + 1 >= szx and ymax - ymin + 1 >= szy): + self.region_of_interest = [xmin, xmax, ymin, ymax] else: self.region_of_interest = None - self.katrain.controls.set_status("",OUTPUT_INFO) - + self.katrain.controls.set_status("", OUTPUT_INFO) def analyze_extra(self, mode, **kwargs): stones = {s.coords for s in self.stones} @@ -443,7 +448,9 @@ class Game: visits = cn.analysis_visits_requested + engine.config["max_visits"] self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS) self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS) - cn.analyze(engine, visits=visits, priority=-1_000, region_of_interest=self.region_of_interest, time_limit=False) + cn.analyze( + engine, visits=visits, priority=-1_000, region_of_interest=self.region_of_interest, time_limit=False + ) return if mode == "game": nodes = self.root.nodes_in_tree diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py index bd7ec9a..5fdfda2 100644 --- a/katrain/core/game_node.py +++ b/katrain/core/game_node.py @@ -145,7 +145,7 @@ class GameNode(SGFNode): refine_move=None, analyze_fast=False, find_alternatives=False, - region_of_interest = None, + region_of_interest=None, report_every=0.25, ): additional_moves = bool(find_alternatives or region_of_interest) diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index a79f263..f1cd02a 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -457,17 +457,16 @@ class BadukPanWidget(Widget): self.draw_hover_contents() - def draw_roi_box(self,region_of_interest,width=2): + def draw_roi_box(self, region_of_interest, width=2): xmin, xmax, ymin, ymax = region_of_interest Color(*LIGHTER_BACKGROUND_COLOR) Line( rectangle=( - self.gridpos_x[xmin] - self.grid_size/6, - self.gridpos_y[ymin] - self.grid_size/6, - (xmax - xmin + 1/3) * self.grid_size, - (ymax - ymin + 1/3) * self.grid_size, + self.gridpos_x[xmin] - self.grid_size / 3, + self.gridpos_y[ymin] - self.grid_size / 3, + (xmax - xmin + 2 / 3) * self.grid_size, + (ymax - ymin + 2 / 3) * self.grid_size, ), - dash_length=10,dash_offset=10, width=width, ) @@ -627,7 +626,7 @@ class BadukPanWidget(Widget): if self.selecting_region_of_interest and len(self.region_of_interest) == 4: x1, x2, y1, y2 = self.region_of_interest - self.draw_roi_box([min(x1, x2), max(x1, x2), min(y1, y2), max(y1, y2)],width=2) + self.draw_roi_box([min(x1, x2), max(x1, x2), min(y1, y2), max(y1, y2)], width=dp(2)) else: # hover next move ghost stone if self.ghost_stone: @@ -641,8 +640,7 @@ class BadukPanWidget(Widget): self.draw_pv(pv, node, up_to_move) if self.katrain.game.region_of_interest: - self.draw_roi_box(self.katrain.game.region_of_interest, width=1) # dashed - + self.draw_roi_box(self.katrain.game.region_of_interest, width=dp(1.25)) def animate_pv(self, _dt): if self.animating_pv: diff --git a/katrain/gui/controlspanel.py b/katrain/gui/controlspanel.py index 8d70461..c848400 100644 --- a/katrain/gui/controlspanel.py +++ b/katrain/gui/controlspanel.py @@ -92,7 +92,12 @@ class ControlsPanel(BoxLayout): def set_status(self, msg, status_type, at_node=None, check_level=True): at_node = at_node or self.katrain and self.katrain.game and self.katrain.game.current_node - if at_node != self.status_state[2] or not check_level or int(status_type) >= int(self.status_state[1]) or msg == "": + if ( + at_node != self.status_state[2] + or not check_level + or int(status_type) >= int(self.status_state[1]) + or msg == "" + ): if self.status_state != (msg, status_type, at_node): # prevent loop if error in update eval Clock.schedule_once(self.update_evaluation, 0) self.status_state = (msg, status_type, at_node) diff --git a/katrain/gui/widgets/movetree.py b/katrain/gui/widgets/movetree.py index b907632..844dd41 100644 --- a/katrain/gui/widgets/movetree.py +++ b/katrain/gui/widgets/movetree.py @@ -187,7 +187,7 @@ class MoveTreeCanvas(Widget): class MoveTree(ScrollView, BackgroundMixin): current_node = ObjectProperty(None) - min_height = NumericProperty(dp(50)) # non-expanded height, to determine the node size + min_height = NumericProperty(dp(50)) # non-expanded height, to determine the node size def __init__(self, **kwargs): super().__init__(**kwargs)