From 3a2e908669a6bff74c44dcd43b22bd1fa9f614fe Mon Sep 17 00:00:00 2001 From: Sander Land Date: Mon, 26 Oct 2020 22:52:30 +0100 Subject: [PATCH] update komi/rules on the fly, etc --- katrain/__main__.py | 2 +- katrain/config.json | 2 +- katrain/core/engine.py | 40 ++++++++++++------ katrain/core/game.py | 31 ++++++++------ katrain/core/game_node.py | 25 +++++++---- katrain/gui.kv | 5 +++ katrain/gui/popups.py | 13 ++++++ .../i18n/locales/cn/LC_MESSAGES/katrain.mo | Bin 13577 -> 13759 bytes .../i18n/locales/cn/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/de/LC_MESSAGES/katrain.mo | Bin 15727 -> 15909 bytes .../i18n/locales/de/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/en/LC_MESSAGES/katrain.mo | Bin 14821 -> 15003 bytes .../i18n/locales/en/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/es/LC_MESSAGES/katrain.mo | Bin 14966 -> 15148 bytes .../i18n/locales/es/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/fr/LC_MESSAGES/katrain.mo | Bin 16539 -> 16721 bytes .../i18n/locales/fr/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/jp/LC_MESSAGES/katrain.mo | Bin 17211 -> 17393 bytes .../i18n/locales/jp/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/ko/LC_MESSAGES/katrain.mo | Bin 16496 -> 16678 bytes .../i18n/locales/ko/LC_MESSAGES/katrain.po | 14 ++++++ .../i18n/locales/ru/LC_MESSAGES/katrain.mo | Bin 20854 -> 21036 bytes .../i18n/locales/ru/LC_MESSAGES/katrain.po | 14 ++++++ katrain/popups.kv | 37 ++++++++++------ 24 files changed, 215 insertions(+), 52 deletions(-) diff --git a/katrain/__main__.py b/katrain/__main__.py index 9252395..c5bbfbc 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -131,7 +131,6 @@ class KaTrainGui(Screen, KaTrainBase): def toggle_continuous_analysis(self): if self.idle_analysis: - self.engine.terminate_continuous_query() self.controls.set_status("", STATUS_INFO) self.idle_analysis = not self.idle_analysis self.update_state() @@ -442,6 +441,7 @@ class KaTrainGui(Screen, KaTrainBase): "s": ("analyze-extra", "equalize"), "d": ("analyze-extra", "sweep"), "f": ("analyze-extra", "alternative"), + "g": ("analyze-extra", "local"), "p": ("play", None), "down": ("switch-branch", 1), "up": ("switch-branch", -1), diff --git a/katrain/config.json b/katrain/config.json index ea3afd0..1a85486 100644 --- a/katrain/config.json +++ b/katrain/config.json @@ -17,7 +17,7 @@ "anim_pv_time": 0.5, "debug_level": 0, "lang": "en", - "version": "1.5.1" + "version": "1.6.0" }, "timer": { "byo_length": 30, diff --git a/katrain/core/engine.py b/katrain/core/engine.py index 490b97c..17ce22b 100644 --- a/katrain/core/engine.py +++ b/katrain/core/engine.py @@ -13,6 +13,7 @@ from kivy.utils import platform from katrain.core.constants import OUTPUT_DEBUG, OUTPUT_ERROR, OUTPUT_EXTRA_DEBUG, OUTPUT_KATAGO_STDERR from katrain.core.game_node import GameNode from katrain.core.lang import i18n +from katrain.core.sgf_parser import Move from katrain.core.utils import find_package_resource @@ -34,7 +35,6 @@ class KataGoEngine: def __init__(self, katrain, config): self.katrain = katrain self.queries = {} # outstanding query id -> start time and callback - self.continuous_query = None self.config = config self.query_counter = 0 self.katago_process = None @@ -108,10 +108,9 @@ class KataGoEngine: def on_new_game(self): self.base_priority += 1 - for query_id in self.queries: + for query_id in list(self.queries.keys()): self.terminate_query(query_id) self.queries = {} - self.continuous_query = None def restart(self): self.queries = {} @@ -211,7 +210,7 @@ class KataGoEngine: self.katrain.log(line, OUTPUT_EXTRA_DEBUG) try: if callback and not analysis.get("noResults", False): - callback(analysis) + callback(analysis, partial_result) except Exception as e: self.katrain.log(f"Error in engine callback for query {query_id}: {e}", OUTPUT_ERROR) if getattr(self.katrain, "update_state", None): # easier mocking etc @@ -220,16 +219,12 @@ class KataGoEngine: self.katrain.log(f"Unexpected exception {e} while processing KataGo output {line}", OUTPUT_ERROR) traceback.print_exc() - def send_query(self, query, callback, error_callback, next_move=None, report_during_search=False): + def send_query(self, query, callback, error_callback, next_move=None): with self._lock: self.query_counter += 1 if "id" not in query: query["id"] = f"QUERY:{str(self.query_counter)}" self.queries[query["id"]] = (callback, error_callback, time.time(), next_move) - if report_during_search: - query["reportDuringSearchEvery"] = 0.25 - self.terminate_continuous_query() - self.continuous_query = query["id"] if self.katago_process: self.katrain.log(f"Sending query {query['id']}: {json.dumps(query)}", OUTPUT_DEBUG) try: @@ -238,9 +233,6 @@ class KataGoEngine: except OSError as e: self.check_alive(os_error=str(e), exception_if_dead=True) - def terminate_continuous_query(self): - self.terminate_query(self.continuous_query) - def terminate_query(self, query_id): if query_id is not None: self.send_query({"action": "terminate", "terminateId": query_id}, None, None) @@ -254,6 +246,7 @@ class KataGoEngine: analyze_fast: bool = False, time_limit=True, find_alternatives: bool = False, + find_local: bool = False, priority: int = 0, ownership: Optional[bool] = None, next_move: Optional[GameNode] = None, @@ -272,6 +265,8 @@ class KataGoEngine: if analyze_fast and self.config.get("fast_visits"): visits = self.config["fast_visits"] + size_x, size_y = analysis_node.board_size + if find_alternatives: avoid = [ { @@ -280,10 +275,26 @@ class KataGoEngine: "untilDepth": 1, } ] + elif find_local: + distance = 5 + last_move = analysis_node.move + if last_move is None or last_move.is_pass: + return + avoid = [ + { + "moves": [ + Move((x, y)).gtp() + for x in range(0, size_x) + for y in range(0, size_y) + if max(abs(x - last_move.coords[0]), abs(y - last_move.coords[1])) > distance + ], + "player": analysis_node.next_player, + "untilDepth": 1, + } + ] else: avoid = [] - size_x, size_y = analysis_node.board_size settings = copy.copy(self.override_settings) if time_limit: settings["maxTime"] = self.config["max_time"] @@ -296,7 +307,6 @@ class KataGoEngine: "analyzeTurns": [len(moves)], "maxVisits": visits, "komi": analysis_node.komi, - "avoidMoves": avoid, "boardXSize": size_x, "boardYSize": size_y, "includeOwnership": ownership and not next_move, @@ -309,5 +319,7 @@ class KataGoEngine: } if report_every is not None: query["reportDuringSearchEvery"] = report_every + if avoid: + query["avoidMoves"] = avoid self.send_query(query, callback, error_callback, next_move) analysis_node.analysis_visits_requested = max(analysis_node.analysis_visits_requested, visits) diff --git a/katrain/core/game.py b/katrain/core/game.py index c3a4db9..91b7ce9 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -86,9 +86,8 @@ class Game: def analyze_all_nodes(self, priority=0, analyze_fast=False): for node in self.root.nodes_in_tree: - node.analyze( - self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast #, report_every=None - ) + node.clear_analysis() + node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast) # -- move tree functions -- def _calculate_groups(self): @@ -325,11 +324,14 @@ class Game: if mode == "extra": if kwargs.get("continuous", False): - visits = 1_000_000_000 + visits = min( + 1_000_000_000, max(engine.config["max_visits"], math.ceil(cn.analysis_visits_requested * 1.25)) + ) else: visits = cn.analysis_visits_requested + engine.config["max_visits"] self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS) - cn.analyze(engine, visits=visits, priority=-1_000, time_limit=False, report_during_search=True) + self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS) + cn.analyze(engine, visits=visits, priority=-1_000, time_limit=False) return if mode == "game": nodes = self.root.nodes_in_tree @@ -370,26 +372,29 @@ class Game: visits = engine.config["fast_visits"] self.katrain.controls.set_status(i18n._("sweep analysis").format(visits=visits), STATUS_ANALYSIS) priority = -1_000_000_000 - elif mode in ["equalize", "alternative"]: - if not cn.analysis_complete: + elif mode == "local": # also do a quick update on current candidates so it doesn't look too weird + self.katrain.controls.set_status(i18n._("local analysis"), STATUS_ANALYSIS) + cn.analyze(engine, priority=-500, time_limit=False, find_local="local") + return + elif mode in ["equalize", "alternative", "local"]: + if not cn.analysis_complete and mode != "local": self.katrain.controls.set_status(i18n._("wait-before-equalize"), STATUS_INFO, self.current_node) return - - analyze_moves = [Move.from_gtp(gtp, player=cn.next_player) for gtp, _ in cn.analysis["moves"].items()] - priority = -1_000 if mode == "alternative": # also do a quick update on current candidates so it doesn't look too weird self.katrain.controls.set_status(i18n._("alternative analysis"), STATUS_ANALYSIS) - cn.analyze(engine, priority=-500, time_limit=False, find_alternatives=True) + cn.analyze(engine, priority=-500, time_limit=False, find_alternatives="alternative") visits = engine.config["fast_visits"] - else: + else: # equalize visits = max(d["visits"] for d in cn.analysis["moves"].values()) self.katrain.controls.set_status(i18n._("equalizing analysis").format(visits=visits), STATUS_ANALYSIS) + priority = -1_000 + analyze_moves = [Move.from_gtp(gtp, player=cn.next_player) for gtp, _ in cn.analysis["moves"].items()] else: raise ValueError("Invalid analysis mode") for move in analyze_moves: if cn.analysis["moves"].get(move.gtp(), {"visits": 0})["visits"] < visits: cn.analyze( - engine, priority, visits=visits, refine_move=move, time_limit=False, report_every=None + engine, priority=priority, visits=visits, refine_move=move, time_limit=False, report_every=None ) # explicitly requested so take as long as you need def analyze_undo(self, node): diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py index 48e23f4..997e4e6 100644 --- a/katrain/core/game_node.py +++ b/katrain/core/game_node.py @@ -13,7 +13,6 @@ class GameNode(SGFNode): def __init__(self, parent=None, properties=None, move=None): super().__init__(parent=parent, properties=properties, move=move) - self.analysis = {"moves": {}, "root": None, "completed": False} self.ownership = None self.policy = None self.auto_undo = None # None = not analyzed. False: not undone (good move). True: undone (bad move) @@ -21,9 +20,13 @@ class GameNode(SGFNode): self.note = "" self.move_number = 0 self.time_used = 0 - self.analysis_visits_requested = 0 self.undo_threshold = random.random() # for fractional undos self.end_state = None + self.clear_analysis() + + def clear_analysis(self): + self.analysis_visits_requested = 0 + self.analysis = {"moves": {}, "root": None, "completed": False} def sgf_properties(self, save_comments_player=None, save_comments_class=None, eval_thresholds=None): properties = copy.copy(super().sgf_properties()) @@ -77,17 +80,21 @@ class GameNode(SGFNode): refine_move=None, analyze_fast=False, find_alternatives=False, + find_local=False, report_every=0.25, ): engine.request_analysis( self, - callback=lambda result, partial_result: self.set_analysis(result, refine_move, find_alternatives, partial_result), + callback=lambda result, partial_result: self.set_analysis( + result, refine_move, find_alternatives or find_local, partial_result + ), priority=priority, visits=visits, analyze_fast=analyze_fast, time_limit=time_limit, next_move=refine_move, find_alternatives=find_alternatives, + find_local=find_local, report_every=report_every, ) @@ -105,7 +112,7 @@ class GameNode(SGFNode): cur.update(move_analysis) def set_analysis( - self, analysis_json: Dict, refine_move: Optional[Move], alternatives_mode: bool, partial_result: bool = False + self, analysis_json: Dict, refine_move: Optional[Move], additional_moves: bool, partial_result: bool = False ): if refine_move: pvtail = analysis_json["moveInfos"][0]["pv"] if analysis_json["moveInfos"] else [] @@ -113,17 +120,17 @@ class GameNode(SGFNode): {"pv": [refine_move.gtp()] + pvtail, **analysis_json["rootInfo"]}, refine_move.gtp() ) else: - if alternatives_mode: + if additional_moves: for m in analysis_json["moveInfos"]: - m["order"] += 100 # offset for not making this top - if refine_move is None and not alternatives_mode: + del m["order"] # avoid changing order + if refine_move is None and not additional_moves: for move_dict in self.analysis["moves"].values(): move_dict["order"] = 999 # old moves to end for move_analysis in analysis_json["moveInfos"]: self.update_move_analysis(move_analysis, move_analysis["move"]) self.ownership = analysis_json.get("ownership") self.policy = analysis_json.get("policy") - if not alternatives_mode: + if not additional_moves: self.analysis["root"] = analysis_json["rootInfo"] if self.parent and self.move: analysis_json["rootInfo"]["pv"] = [self.move.gtp()] + ( @@ -132,7 +139,7 @@ class GameNode(SGFNode): self.parent.update_move_analysis( analysis_json["rootInfo"], self.move.gtp() ) # update analysis in parent for consistency - is_normal_query = refine_move is None and not alternatives_mode + is_normal_query = refine_move is None and not additional_moves self.analysis["completed"] = self.analysis["completed"] or (is_normal_query and not partial_result) @property diff --git a/katrain/gui.kv b/katrain/gui.kv index f4dd0cd..d88f056 100644 --- a/katrain/gui.kv +++ b/katrain/gui.kv @@ -749,6 +749,11 @@ icon: 'img/Alternative.png' shortcut: 'f' on_action: root.katrain("analyze-extra", "alternative") + AnalysisMenuItem: + text: i18n._("analysis:local") + icon: 'img/Alternative.png' + shortcut: 'g' + on_action: root.katrain("analyze-extra", "local") AnalysisMenuItem: text: i18n._("analysis:game") icon: 'img/analysis.png' diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 0663a35..3e4c337 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -260,6 +260,19 @@ class NewGamePopup(QuickConfigGui): self.katrain.update_player(bw, **player_setup.player_type_dump) self.katrain("new-game") + def update_game(self, save_to_file=True): + props = self.collect_properties(self) + root = self.katrain.game.root + changed = False + for k, v in [("RU", props["game/rules"]), ("KM", props["game/komi"])]: + current = root.get_property(k) + if current != v: + changed = True + self.katrain.game.root.set_property(k, v) + if changed: + self.katrain.engine.on_new_game() + self.katrain.game.analyze_all_nodes() + self.popup.dismiss() def wrap_anchor(widget): anchor = AnchorLayout() diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo index d7f987d24e662b75097e00a48f2767850298c930..0143e4a050fe34d0b1c993789755abf068431d2c 100644 GIT binary patch delta 3370 zcmZA2du)w&9LMn=O3^!dp;L!pbHB9A%#@9?1aX@9#x5>fZM2h4 zEp}70O%@edjqZ;brpbbhwaZdllik@SF4^$M-k+XtvSf1lynfg3@A^EpF8_3e*U~Mj z%JJ_MfA{b=qmy#ZZHWEPRFdW7ld%eu@O@0f6BvV+EZ>UV$lt*}7#|nO5649ElQA0S zV!U&nTSy{-f}k~6XKur;liWRJ&zPTjf~-1FbaQ1P4F*N`%Xmfg*~wcW+6ZK z7!S3}ZOePkg-B>c<=6#xpgL4z2RwvY;bE(9Kuzq7m4Ag=(PiZ4e&(V2Tc~*LSe=YP z#YslB>x*%W??zgKiKrD#xBPr_F{(ol`MI?`6le=-rIo1qT4eF=sCg3kxeGkht`)V= zo2YitoQJ0~N#>z~fo2wJ1&^S1VkRokQqrn&kL}IzOto#USM;eizYqtCq%il)z zi(_``*V`kZ6^%emU;=8OnV63G$j@!$p@5axcGl)mRKL$rE4+l-xmMK9T($aJsJPLb zr;ap(2Sv`yB%$|s8Y<8db2Tc!CUZOXBwvYI!6DRZ*MRzDe1;m}tkwU3n&>rC+ey+T zpmwxB6327HNoZvgtzwS32(_XBYKK;%Cisli??7#Jwbj?6;v7M>J8d?hCi*L?{U4}> z-Nj_acO99wW|WTVIKc8_Q3FpxO=Ko&1q;j&YUP_zXSoe^*=kVn-a+*{go<;_%1@)l zIghD&|656D=C`dPj_<8HW}s#~7!_cgITf|Fb5SetqXI5R4ZI$82cAdud&SE4qT<$~ z+Sj4SF1V8bD5BL(A}KEXTfh6EiTC z3#4{qQR6<^ll@o00tzNz0T$!in1kKr?xu~6Z z4>#b)RzHSit2`Uaa29I3li2p1=uARq)x7J?=yXqe5yOIHnmNE6jp~|h`5beexdbby zUx~Z%E@oq;j~jqr<3||aL>e)rpL5%>6`L@0FNdLq)B3Zq*o3d5H-IlcCJl7%<@U~% zVji|16j@urkjNLL40Sjas9UnzJcwHB3Dm+G%_gh=5p`?+9^yszB5r8pQy`u1O-s(qJGea3=DO zx`$B{dmIO2q2+g?KC17c`qf+cDYF?TQGNw^CET##dRKFXjf$yLXV@5|7I202Y-%TgMBwelwa4Tx- zs!K0yaetdDsYo|8M~4H2{rIPR-TXOTkLG1tlqF`0ZRs{J<9CEtr~a#4|QX)xpu2LmO(x`na1Q5}nl^ZZ4- z4kVsW@`nlozPz$eeKU?-1iJ^7%vlqID&~lDZFi{Fc%qCm722wRQ7_ z10}19LnVQdT~$NA@XcS9?=KDbRur!cjtG|(1xmUGLq30AX>d&-67Q*@4@UK#7x0Jk UmIXtFzJlWL|KrqEjVz7&7w!#ZB>(^b delta 3186 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 M6H>b<@2imi0BQp@ZvX%Q diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po index 78cc749..897082f 100644 --- a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po @@ -735,3 +735,17 @@ msgstr "" #. TODO msgid "ai:settle" msgstr "Settle Style" + +#. TODO - Analyze again but allow only nearby moves +msgid "analysis:local" +msgstr "Find local responses" + +#. TODO - status message +msgid "local analysis" +msgstr "Searching for local responses" + +#. TODO - change komi etc in current game +msgid "change current game" +msgstr "" +"Update komi/rules\n" +"in active game" diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index c55b7a742979a93a69c6014930226b36d724c9ab..83e6a1d6d04af799b807c3f9cdb444cdd9cc30b6 100644 GIT binary patch delta 3376 zcmZA34NR3)9LMovfT+A)6%`PDZmak->WkXF|dW9QagNxoPPBVL)=3+Kq zra0%+HLYn&r5WayDRWDuBr|PlXai$2U&5A~xTd!C{qdZwt#-Yi=bY!9|MNfpbDm2# z!@Fvn*4~lZ4ga0x-$4Eqbyv%n_hSFEKbNa%C*gMV;6WUKCou-E*mgViru`VxF+R?1 zkHkdUFJm;$#CT&IGnb15Is$gUO6vyfMgJ~T!2QU_e9c!sY(k!4S}_v;KqdGWYJ7L1 zr(iPn#a!fLUg1mQ=5)0kV}e|0MXRwVZbnVmi4jy#A9IT@ z-G7LR*NxT57*w1j)VRSI$Mel7J764YMTNFqVx5ng5I{a=1z!qOi&|+N>iz*_@#dKI zH1aW*_|mv`)IvK^D$qhy=|b2CYf7oAWh#?C-c!)IzHDD5I@8+V$m0MS#9<&vSW%k+rqo|5B zBOlXZ+a0$32sJN`>@+XU;X*6QMkP>ydQdT@Vmb0LYxq*YI_%nO>oL^4GpH3_K~=6D zRhfJC{zFvUX!cWEI*2d2jFZEK-s7pLKntu(Q32LkKf+|%b*L58qh7m4)KA8@s0W<0 z_kTkrdf%#Ya%mD!6&;4eam+|Aw6byb#_QHn)QbG53N1w?_`bcr8CB|?_Wl7>oTI35 zP1avfiQYkt{}Z*aCz!qg2$y4BO5_J@_S5BE_f`ylD-hR=y6kmm5%rZ8s|3 zr>J@Ls5r-Me-r9C7qP$I|8_2v`6GKHj^A5N9E8gF8B~C=*2$>S&P1)mhYGkD_25;g zGq4^tZ;S2UgNl0qHNF8Is$foY5rx-K6KI^ydtu{yH2}>6nH^I01KH6JEoKxG&8O_&cg% zoj4q0$Z7?S#&kT08sCii+mS%0D$)mc;|SE5IfJU$4-OYvQ46Xx?Wl@8K&`-d-BKr@ zCZwarWudlU94g>+)Sj21#x1Z`;St*JVk>41Hf9#a3~~SDI}5pJq$6{vF<0?69>r6` zcvY|_gTHiG&T_|h<0qPW|46%veOZGAZ1BdX`2PSb!&kH11$;5mt;jd1Lwp@M-{uao zYhC-rVRcL@8%GW%1GS<;)E>=2l`e!@*@vi=ZAAt67UWHJmJ7Doj6#*R7`-?jqj3#tOKR=?I@AO9+x{b{gioR#a23bk4b;~3 zd)__mX_!De&pHLW-v3!#%-}{4wX#N}nx+L6IAXMW*wRq#NyzS)w`_YID)1hB0S_a) zV{YP$7@y--st^fjN>QhOBRXt{*~^7i_!DZcenpk^E+*mw~1CfKgX{HDjU@k=V6B>`&W+dT^%gpXhL*y_$xa5Js(RrR`sj!)e!} zR(9F;x1kPgkFjoo8K`+VsD#F&Dl!9kYt0<%T+|tuhf3Jl#Dz}zHdF$;P!-vWTKOT{ ze;gI?6ei*Kcmvx|r9H(-)A;kK``4}aQ4fmFcMoAKD#3IdpmUhbg#r}fWGu;Vm=?Pz zGODt=%vZVXv&4%YU$DaOEvpHI{J~}33SX7KVYw$iBF0zg^#y&EE5m_s!=b+ADSf5{ zg5}<>Y2J`Oyreo9_HT>NzUD1iQtn&k_r6nI703?NRQkic0zt2@Y*}Er-wk&w`+Q{D a8-8D?Y*8Rs;eES0^uI9ShKAhHQU3xtZ)Ir! delta 3208 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 b*wyE0zb{l=8VD}*zEmFi-$3JY^IZP|6xe9K delta 3208 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 diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po index 7901826..f30e5b3 100644 --- a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po @@ -714,3 +714,17 @@ msgstr "" msgid "ai:settle" msgstr "堅実派" + +#. TODO - Analyze again but allow only nearby moves +msgid "analysis:local" +msgstr "Find local responses" + +#. TODO - status message +msgid "local analysis" +msgstr "Searching for local responses" + +#. TODO - change komi etc in current game +msgid "change current game" +msgstr "" +"Update komi/rules\n" +"in active game" diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo index 206bb8e9c7721b8526c9586f99ab49ca52c57705..5b11b24942a3fc45c3e6eb265c8ad497b8797105 100644 GIT binary patch delta 3379 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 na7py+@O7=R$ATvVgWCq: