extra analysis options
This commit is contained in:
1 parent
57922ddcb4
commit
f57dbcdee9
24 files changed
+139
-18
No files matched your search
@@ -103,6 +103,8 @@ Keyboard shortcuts are shown with **[key]**.
|
||||
* **[a]**: Deeper analysis: Re-evaluate the position using more visits, usually resulting in a more accurate evaluation.
|
||||
* **[s]**: Equalize visits: Re-evaluate all currently shown next moves with the same visits as the current top move. Useful to increase confidence in the suggestions with high uncertainty.
|
||||
* **[d]**: Analyze all moves: Evaluate all possible next moves. This can take a bit of time even though 'fast_visits' is used, but can be useful to see how many reasonable next moves are available.
|
||||
* **[f]**: Re-analyze game: ...
|
||||
* **[spacebar]**: Turn continuous analysis on/off.
|
||||
* **[enter]** AI move. Makes the AI move for the current player regardless of current player selection.
|
||||
|
||||
## Keyboard and mouse shortcuts
|
||||
@@ -112,7 +114,7 @@ In addition to shortcuts mentioned above and those shown in the main menu:
|
||||
* **[Shift]**: Open the main menu.
|
||||
* **[~]** or **[ ` ]** or **[m]**: Cycles through more minimalistic UI modes.
|
||||
* **[p]**: Pass
|
||||
* **[spacebar]**: Pause/Resume timer
|
||||
* **[b]**: Pause/Resume timer
|
||||
* **[arrow left]** or **[z]**: Undo move. Hold shift for 10 moves at a time, or ctrl to skip to the start.
|
||||
* **[arrow right]** or **[x]**: Redo move. Hold shift for 10 moves at a time, or ctrl to skip to the start.
|
||||
* **[arrow up/down]** Switch branch, as would be expected from the move tree.
|
||||
|
||||
+19
-9
@@ -89,6 +89,7 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
self.teacher_settings_popup = None
|
||||
self.timer_settings_popup = None
|
||||
|
||||
self.idle_analysis = False
|
||||
self.message_queue = Queue()
|
||||
|
||||
self._keyboard = Window.request_keyboard(None, self, "")
|
||||
@@ -113,6 +114,10 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
def play_analyze_mode(self):
|
||||
return self.play_mode.mode
|
||||
|
||||
def toggle_continuous_analysis(self):
|
||||
self.idle_analysis = not self.idle_analysis
|
||||
self.update_state()
|
||||
|
||||
def start(self):
|
||||
if self.engine:
|
||||
return
|
||||
@@ -182,7 +187,9 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
and not (teaching_undo and cn.auto_undo is None)
|
||||
): # cn mismatch stops this if undo fired. avoid message loop here or fires repeatedly.
|
||||
self._do_ai_move(cn)
|
||||
Clock.schedule_once(lambda _dt: self.update_gui(cn, redraw_board=redraw_board), -1)
|
||||
if len(self.engine.queries) == 0 and self.idle_analysis:
|
||||
self("analyze-extra", "extra", continuous=True)
|
||||
Clock.schedule_once(lambda _dt: self.update_gui(cn, redraw_board=redraw_board), -1) # trigger?
|
||||
|
||||
def update_player(self, bw, **kwargs):
|
||||
super().update_player(bw, **kwargs)
|
||||
@@ -197,7 +204,7 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
|
||||
def _message_loop_thread(self):
|
||||
while True:
|
||||
game, msg, *args = self.message_queue.get()
|
||||
game, msg, args, kwargs = self.message_queue.get()
|
||||
try:
|
||||
self.log(f"Message Loop Received {msg}: {args} for Game {game}", OUTPUT_EXTRA_DEBUG)
|
||||
if game != self.game.game_id:
|
||||
@@ -206,19 +213,19 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
)
|
||||
continue
|
||||
fn = getattr(self, f"_do_{msg.replace('-','_')}")
|
||||
fn(*args)
|
||||
fn(*args, **kwargs)
|
||||
self.update_state()
|
||||
except Exception as exc:
|
||||
self.log(f"Exception in processing message {msg} {args}: {exc}", OUTPUT_ERROR)
|
||||
traceback.print_exc()
|
||||
|
||||
def __call__(self, message, *args):
|
||||
def __call__(self, message, *args, **kwargs):
|
||||
if self.game:
|
||||
if message.endswith("popup"): # gui code needs to run in main kivy thread.
|
||||
fn = getattr(self, f"_do_{message.replace('-', '_')}")
|
||||
Clock.schedule_once(lambda _dt: fn(*args), -1)
|
||||
Clock.schedule_once(lambda _dt: fn(*args, **kwargs), -1)
|
||||
else: # game related actions
|
||||
self.message_queue.put([self.game.game_id, message, *args])
|
||||
self.message_queue.put([self.game.game_id, message, args, kwargs])
|
||||
|
||||
def _do_new_game(self, move_tree=None, analyze_fast=False):
|
||||
mode = self.play_analyze_mode
|
||||
@@ -266,8 +273,8 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
except IllegalMoveException as e:
|
||||
self.controls.set_status(f"Illegal Move: {str(e)}")
|
||||
|
||||
def _do_analyze_extra(self, mode):
|
||||
self.game.analyze_extra(mode)
|
||||
def _do_analyze_extra(self, mode, **kwargs):
|
||||
self.game.analyze_extra(mode, **kwargs)
|
||||
|
||||
def _do_new_game_popup(self):
|
||||
self.controls.timer.paused = True
|
||||
@@ -397,6 +404,7 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
"a": ("analyze-extra", "extra"),
|
||||
"s": ("analyze-extra", "equalize"),
|
||||
"d": ("analyze-extra", "sweep"),
|
||||
"f": ("analyze-extra", "game"),
|
||||
"p": ("play", None),
|
||||
"down": ("switch-branch", 1),
|
||||
"up": ("switch-branch", -1),
|
||||
@@ -429,8 +437,10 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
elif keycode[1] == "shift":
|
||||
self.nav_drawer.set_state("toggle")
|
||||
elif keycode[1] == "spacebar":
|
||||
self.toggle_continuous_analysis()
|
||||
elif keycode[1] == "b" and "ctrl" not in modifiers:
|
||||
self.controls.timer.paused = not self.controls.timer.paused
|
||||
elif keycode[1] in ["`", "~", "m"]:
|
||||
elif keycode[1] in ["`", "~", "m"] and "ctrl" not in modifiers:
|
||||
self.zen = (self.zen + 1) % 3
|
||||
elif keycode[1] in ["left", "z"]:
|
||||
self("undo", 1 + ("shift" in modifiers) * 9 + ("ctrl" in modifiers) * 999)
|
||||
|
||||
+18
-3
@@ -317,16 +317,29 @@ class Game:
|
||||
f.write(sgf)
|
||||
return i18n._("sgf written").format(file_name=file_name)
|
||||
|
||||
def analyze_extra(self, mode):
|
||||
def analyze_extra(self, mode, **kwargs):
|
||||
stones = {s.coords for s in self.stones}
|
||||
cn = self.current_node
|
||||
|
||||
engine = self.engines[cn.next_player]
|
||||
if mode == "extra":
|
||||
visits = cn.analysis_visits_requested + engine.config["max_visits"]
|
||||
if kwargs.get("continuous", False):
|
||||
visits = max(engine.config["fast_visits"], math.ceil(cn.analysis_visits_requested * 1.1))
|
||||
else:
|
||||
visits = cn.analysis_visits_requested + engine.config["fast_visits"]
|
||||
|
||||
self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits))
|
||||
cn.analyze(engine, visits=visits, priority=-1_000, time_limit=False)
|
||||
return
|
||||
if mode == "game":
|
||||
nodes = self.root.nodes_in_tree
|
||||
min_visits = min(node.analysis_visits_requested for node in nodes)
|
||||
visits = min_visits + engine.config["max_visits"]
|
||||
for node in nodes:
|
||||
node.analyze(engine, visits=visits, priority=-1_000_000, time_limit=False)
|
||||
self.katrain.controls.set_status(i18n._("game re-analysis").format(visits=visits))
|
||||
return
|
||||
|
||||
elif mode == "sweep":
|
||||
board_size_x, board_size_y = self.board_size
|
||||
if cn.analysis_ready:
|
||||
@@ -354,7 +367,7 @@ class Game:
|
||||
visits = engine.config["fast_visits"]
|
||||
self.katrain.controls.set_status(i18n._("sweep analysis").format(visits=visits))
|
||||
priority = -1_000_000_000
|
||||
else: # mode=='equalize':
|
||||
elif mode == "equalize":
|
||||
if not cn.analysis_ready:
|
||||
self.katrain.controls.set_status(i18n._("wait-before-equalize"), self.current_node)
|
||||
return
|
||||
@@ -363,6 +376,8 @@ class Game:
|
||||
visits = max(d["visits"] for d in cn.analysis["moves"].values())
|
||||
self.katrain.controls.set_status(i18n._("equalizing analysis").format(visits=visits))
|
||||
priority = -1_000
|
||||
else:
|
||||
raise ValueError("Invalid analysis mode")
|
||||
for move in analyze_moves:
|
||||
cn.analyze(
|
||||
engine, priority, visits=visits, refine_move=move, time_limit=False
|
||||
|
||||
@@ -69,8 +69,9 @@ class GameNode(SGFNode):
|
||||
|
||||
# various analysis functions
|
||||
def analyze(self, engine, priority=0, visits=None, time_limit=True, refine_move=None, analyze_fast=False):
|
||||
if visits and not refine_move:
|
||||
self.analysis_visits_requested = max(visits, engine.config["max_visits"])
|
||||
if not refine_move:
|
||||
req_visits = visits or (engine.config["fast_visits"] if analyze_fast else engine.config["max_visits"])
|
||||
self.analysis_visits_requested = max(req_visits, self.analysis_visits_requested)
|
||||
engine.request_analysis(
|
||||
self,
|
||||
lambda result: self.set_analysis(result, refine_move),
|
||||
|
||||
@@ -721,6 +721,16 @@
|
||||
icon: 'img/Sweep.png'
|
||||
shortcut: 'd'
|
||||
on_action: root.katrain("analyze-extra", "sweep")
|
||||
AnalysisMenuItem:
|
||||
text: i18n._("analysis:game")
|
||||
icon: 'img/analysis.png'
|
||||
shortcut: 'f'
|
||||
on_action: root.katrain("analyze-extra", "game")
|
||||
AnalysisMenuItem:
|
||||
text: i18n._("analysis:continuous")
|
||||
icon: 'img/off.png'
|
||||
shortcut: 'space'
|
||||
on_action: root.katrain.toggle_continuous_analysis()
|
||||
AnalysisMenuItem:
|
||||
text: i18n._("analysis:aimove")
|
||||
icon: 'img/ai.png'
|
||||
|
||||
@@ -402,7 +402,6 @@ class CollapsablePanel(MDBoxLayout):
|
||||
height = self.header.height
|
||||
self.height, self.size_hint_y = height, size_hint_y
|
||||
|
||||
|
||||
@property
|
||||
def option_state(self):
|
||||
return {option: active for option, active in zip(self.options, self.option_active)}
|
||||
|
||||
@@ -59,4 +59,4 @@ ENGINE_BUSY_COL = EVAL_COLORS[2]
|
||||
ENGINE_READY_COL = EVAL_COLORS[-1]
|
||||
|
||||
# info
|
||||
INFO_PV_COLOR = to_hexcol(RED)
|
||||
INFO_PV_COLOR = to_hexcol(YELLOW)
|
||||
@@ -228,7 +228,6 @@ class RankGraph(Graph):
|
||||
for pl, rank in self.calculate_ranks(policy_stats[bounds[0] : bounds[1] + 1], num_intersec).items():
|
||||
ranks[pl].append((segment_mid, rank))
|
||||
self.rank_by_player = ranks
|
||||
print(ranks)
|
||||
self.redraw_trigger()
|
||||
|
||||
def update_value(self, node):
|
||||
|
||||
Binary file not shown.
@@ -572,3 +572,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
@@ -615,3 +615,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
@@ -98,6 +98,15 @@ msgstr "Equalize visits of potential moves"
|
||||
msgid "analysis:sweep"
|
||||
msgstr "Fast analysis of all moves"
|
||||
|
||||
msgid "analysis:sweep"
|
||||
msgstr "Fast analysis of all moves"
|
||||
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
|
||||
msgid "analysis:aimove"
|
||||
msgstr "Force AI Move"
|
||||
|
||||
@@ -113,6 +122,10 @@ msgstr "Analyzing entire board using {visits} visits/move"
|
||||
msgid "equalizing analysis"
|
||||
msgstr "Equalizing analysis of candidate moves to {visits} visits"
|
||||
|
||||
#. status message
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. right panel buttons and below board
|
||||
msgid "pass-button-text"
|
||||
msgstr "Pass"
|
||||
|
||||
Binary file not shown.
@@ -610,3 +610,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
@@ -649,3 +649,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
@@ -587,3 +587,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
@@ -612,3 +612,15 @@ msgstr "All available models already downloaded"
|
||||
#. TODO
|
||||
msgid "tab:rank_est"
|
||||
msgstr "Rank Estimate"
|
||||
|
||||
#. TODO
|
||||
msgid "game re-analysis"
|
||||
msgstr "Re-analyzing entire game using {visits} visits"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:game"
|
||||
msgstr "Re-analyze entire game"
|
||||
|
||||
#. TODO
|
||||
msgid "analysis:continuous"
|
||||
msgstr "Continuously analyze"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Reference in new issue
Block a user