From 8dcfc1cd59f4062152589d6943ea4072ab940fd4 Mon Sep 17 00:00:00 2001 From: Sander Land Date: Mon, 30 Nov 2020 13:18:23 +0100 Subject: [PATCH] zero width space markers and base64 encoded data in sgf files are probably terrible ideas --- INSTALL.md | 3 +- katrain/__main__.py | 8 +-- katrain/config.json | 1 + katrain/core/constants.py | 5 ++ katrain/core/game.py | 37 ++++++++--- katrain/core/game_node.py | 61 +++++++++++++++--- katrain/gui/popups.py | 3 + .../i18n/locales/cn/LC_MESSAGES/katrain.mo | Bin 13955 -> 14015 bytes .../i18n/locales/cn/LC_MESSAGES/katrain.po | 4 ++ .../i18n/locales/de/LC_MESSAGES/katrain.mo | Bin 15674 -> 15779 bytes .../i18n/locales/de/LC_MESSAGES/katrain.po | 6 ++ .../i18n/locales/en/LC_MESSAGES/katrain.mo | Bin 15369 -> 15439 bytes .../i18n/locales/en/LC_MESSAGES/katrain.po | 6 +- .../i18n/locales/es/LC_MESSAGES/katrain.mo | Bin 15513 -> 15573 bytes .../i18n/locales/es/LC_MESSAGES/katrain.po | 4 ++ .../i18n/locales/fr/LC_MESSAGES/katrain.mo | Bin 17232 -> 17292 bytes .../i18n/locales/fr/LC_MESSAGES/katrain.po | 4 ++ .../i18n/locales/jp/LC_MESSAGES/katrain.mo | Bin 17781 -> 17841 bytes .../i18n/locales/jp/LC_MESSAGES/katrain.po | 4 ++ .../i18n/locales/ko/LC_MESSAGES/katrain.mo | Bin 17197 -> 17256 bytes .../i18n/locales/ko/LC_MESSAGES/katrain.po | 4 ++ .../i18n/locales/ru/LC_MESSAGES/katrain.mo | Bin 22470 -> 22530 bytes .../i18n/locales/ru/LC_MESSAGES/katrain.po | 4 ++ katrain/popups.kv | 40 +++++++----- requirements.txt | 1 + setup.py | 1 + 26 files changed, 153 insertions(+), 43 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index e2a52fd..002c939 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -97,8 +97,9 @@ pip3 install screeninfo # Skip on MacOS, not working In case the sound is not working, or there is no available wheel for your OS or Python version, try: ```bash pip3 uninstall kivy -pip3 install --no-binary kivy kivy==2.0.0rc2 +pip3 install kivy --extra-index-url https://kivy.org/downloads/simple/ ``` + You can now start KaTrain by running `python3 -m katrain` In case KataGo does not start, an alternative is to go [here](https://github.com/lightvector/KataGo) and compile KataGo yourself. diff --git a/katrain/__main__.py b/katrain/__main__.py index 01c4bc7..6d5dce1 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -253,14 +253,14 @@ class KaTrainGui(Screen, KaTrainBase): else: # game related actions self.message_queue.put([self.game.game_id, message, args, kwargs]) - def _do_new_game(self, move_tree=None, analyze_fast=False): + def _do_new_game(self, move_tree=None, analyze_fast=False, loaded_from_file=None): self.idle_analysis = False mode = self.play_analyze_mode if (move_tree is not None and mode == MODE_PLAY) or (move_tree is None and mode == MODE_ANALYZE): self.play_mode.switch_ui_mode() # for new game, go to play, for loaded, analyze self.board_gui.animating_pv = None self.engine.on_new_game() # clear queries - self.game = Game(self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast) + self.game = Game(self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast,loaded_from_file=loaded_from_file) if move_tree: for bw, player_info in self.players_info.items(): player_info.player_type = PLAYER_HUMAN @@ -340,7 +340,7 @@ class KaTrainGui(Screen, KaTrainBase): self.controls.timer.paused = True if not self.teacher_settings_popup: self.teacher_settings_popup = I18NPopup( - title_key="teacher settings", size=[dp(800), dp(750)], content=ConfigTeacherPopup(self) + title_key="teacher settings", size=[dp(800), dp(800)], content=ConfigTeacherPopup(self) ).__self__ self.teacher_settings_popup.content.popup = self.teacher_settings_popup self.teacher_settings_popup.open() @@ -369,7 +369,7 @@ class KaTrainGui(Screen, KaTrainBase): except ParseError as e: self.log(i18n._("Failed to load SGF").format(error=e), OUTPUT_ERROR) return - self._do_new_game(move_tree=move_tree, analyze_fast=fast) + self._do_new_game(move_tree=move_tree, analyze_fast=fast,loaded_from_file=file) if not rewind: self.game.redo(999) diff --git a/katrain/config.json b/katrain/config.json index d2c517b..0ba024b 100644 --- a/katrain/config.json +++ b/katrain/config.json @@ -67,6 +67,7 @@ true, true ], + "save_analysis": true, "low_visits": 25, "eval_off_show_last": 3, "top_moves_show": "top_move_delta_score", diff --git a/katrain/core/constants.py b/katrain/core/constants.py index 6ebb1f8..e0b9423 100644 --- a/katrain/core/constants.py +++ b/katrain/core/constants.py @@ -1,3 +1,4 @@ +PROGRAM_NAME = "KaTrain" VERSION = "1.7.0" HOMEPAGE = "https://github.com/sanderland/katrain" CONFIG_MIN_VERSION = "1.7.0" # keep config files from this version @@ -237,3 +238,7 @@ TOP_MOVE_OPTIONS = [ TOP_MOVE_VISITS, TOP_MOVE_NOTHING, ] + +SGF_COMMENTS_MARKER = "\u200b\u3164" +SGF_NOTE_MARKER = "\u200b\u200b" +SGF_SEPARATOR_MARKER = "\u3164\u3164" diff --git a/katrain/core/game.py b/katrain/core/game.py index 5028422..92d0bcc 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -16,6 +16,7 @@ from katrain.core.constants import ( STATUS_INFO, STATUS_TEACHING, PLAYER_HUMAN, + VERSION, PROGRAM_NAME, ) from katrain.core.engine import KataGoEngine from katrain.core.game_node import GameNode @@ -35,7 +36,7 @@ class KaTrainSGF(SGF): class Game: """Represents a game of go, including an implementation of capture rules.""" - DEFAULT_PROPERTIES = {"GM": 1, "FF": 4, "AP": f"KaTrain:{HOMEPAGE}", "CA": "UTF-8"} + DEFAULT_PROPERTIES = {"GM": 1, "FF": 4, "AP": f"{PROGRAM_NAME}:{VERSION}", "CA": "UTF-8"} def __init__( self, @@ -44,6 +45,7 @@ class Game: move_tree: GameNode = None, analyze_fast=False, game_properties: Optional[Dict] = None, + loaded_from_file = None ): self.katrain = katrain self._lock = threading.Lock() @@ -51,6 +53,8 @@ class Game: engine = {"B": engine, "W": engine} self.engines = engine self.game_id = datetime.strftime(datetime.now(), "%Y-%m-%d %H %M %S") + self.loaded_from_file = loaded_from_file + if move_tree: self.root = move_tree @@ -82,13 +86,16 @@ class Game: self.set_current_node(self.root) self.main_time_used = 0 threading.Thread( - target=lambda: self.analyze_all_nodes(-1_000_000, analyze_fast=analyze_fast), daemon=True + target=lambda: self.analyze_all_nodes(-1_000_000, analyze_fast=analyze_fast, even_if_present=False), + 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, even_if_present=True): for node in self.root.nodes_in_tree: - node.clear_analysis() - node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast) + if even_if_present or not node.analysis_loaded: + print(even_if_present, node.analysis_loaded, node.move) + node.clear_analysis() + node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast) # -- move tree functions -- def _calculate_groups(self): @@ -292,9 +299,11 @@ class Game: self, path: str, trainer_config: Optional[Dict] = None, ): if trainer_config is None: - trainer_config = self.katrain.config("trainer") - save_feedback = trainer_config["save_feedback"] + trainer_config = self.katrain.config("trainer", {}) + save_feedback = trainer_config.get("save_feedback", False) eval_thresholds = trainer_config["eval_thresholds"] + print(trainer_config) + save_analysis = trainer_config.get("save_analysis", False) def player_name(player_info): if player_info.name and player_info.player_type == PLAYER_HUMAN: @@ -314,15 +323,23 @@ class Game: x_properties["RE"] = self.end_result self.root.properties = {**root_properties, **{k: [v] for k, v in x_properties.items()}} player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw, bw)) for bw in "BW"} - 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")) + base_game_name = f"katrain_{player_names['B']} vs {player_names['W']}" + game_name = f"{base_game_name} {self.game_id}" + + if self.loaded_from_file and base_game_name in self.loaded_from_file and PROGRAM_NAME in self.root.get_property("AP","") and self.loaded_from_file.endswith('sgf'): + file_name = self.loaded_from_file + else: + file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf")) os.makedirs(os.path.dirname(file_name), exist_ok=True) show_dots_for = { bw: trainer_config.get("eval_show_ai", True) or self.katrain.players_info[bw].human for bw in "BW" } sgf = self.root.sgf( - save_comments_player=show_dots_for, save_comments_class=save_feedback, eval_thresholds=eval_thresholds + save_comments_player=show_dots_for, + save_comments_class=save_feedback, + eval_thresholds=eval_thresholds, + save_analysis=save_analysis, ) with open(file_name, "w", encoding="utf-8") as f: f.write(sgf) diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py index ca6257a..3d7fc02 100644 --- a/katrain/core/game_node.py +++ b/katrain/core/game_node.py @@ -2,10 +2,13 @@ import copy import random from typing import Dict, List, Optional, Tuple +from katrain.core.constants import HOMEPAGE, VERSION, SGF_COMMENTS_MARKER, SGF_SEPARATOR_MARKER, SGF_NOTE_MARKER, PROGRAM_NAME from katrain.core.lang import i18n from katrain.core.sgf_parser import Move, SGFNode from katrain.core.utils import evaluation_class, var_to_grid from katrain.gui.style import INFO_PV_COLOR +import base64 +import gzip class GameNode(SGFNode): @@ -22,19 +25,56 @@ class GameNode(SGFNode): self.time_used = 0 self.undo_threshold = random.random() # for fractional undos self.end_state = None + self.analysis_loaded = False self.clear_analysis() + def add_list_property(self, property: str, values: List): + if property == "KT": + try: + import bson + + self.analysis = bson.loads(gzip.decompress(base64.standard_b64decode(values[0]))) + self.analysis_loaded = True + except Exception as e: + print(e) + elif property == "C": + comments = [ # strip out all previously auto generated comments + c for v in values for c in v.split(SGF_SEPARATOR_MARKER) + ] + self.note = "".join(c for c in comments if SGF_NOTE_MARKER in c) + super().add_list_property( + property, + [c for c in comments if c.strip() and SGF_COMMENTS_MARKER not in c and SGF_NOTE_MARKER not in c], + ) + else: + return super().add_list_property(property, values) + 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): + def sgf_properties( + self, save_comments_player=None, save_comments_class=None, eval_thresholds=None, save_analysis=False + ): properties = copy.copy(super().sgf_properties()) note = self.note.strip() + print(save_analysis, self.analysis_complete) + if save_analysis and self.analysis_complete: + try: + import bson + + analysis = copy.deepcopy(self.analysis) + for movedict in analysis["moves"].values(): + if "ownership" in movedict: + del movedict["ownership"] + properties["KT"] = [base64.standard_b64encode(gzip.compress(bson.dumps(analysis))).decode("utf-8")] + except Exception as e: + print(e) if self.points_lost and save_comments_class is not None and eval_thresholds is not None: show_class = save_comments_class[evaluation_class(self.points_lost, eval_thresholds)] else: show_class = False + comments = properties.get("C", []) if ( self.parent and self.parent.analysis_exists @@ -50,18 +90,19 @@ class GameNode(SGFNode): properties["SQ"] = best_sq if top_x and "MA" not in properties: properties["MA"] = [top_x] - comment = self.comment(sgf=True, interactive=False) - if comment: - properties["C"] = ["\n".join(properties.get("C", "")) + comment] + comments.append(self.comment(sgf=True, interactive=False)) if self.is_root: - properties["C"] = [ - i18n._("SGF start message") - + "\n" - + "\n".join(properties.get("C", "")) - + "\nSGF with review generated by KaTrain." + comments = [ + i18n._("SGF start message") + SGF_COMMENTS_MARKER, + *comments, + f"SGF with generated by {PROGRAM_NAME} {VERSION}{SGF_COMMENTS_MARKER}.", ] if note: - properties["C"] = ["\n".join(properties.get("C", "")) + f"\nNote: {self.note}"] + comments.append(f"\nNote: {self.note}{SGF_NOTE_MARKER}") + if comments: + properties["C"] = [SGF_SEPARATOR_MARKER.join(comments)] + elif "C" in properties: + del properties["C"] return properties @staticmethod diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 24ba48c..9698e0b 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -274,6 +274,9 @@ class NewGamePopup(QuickConfigGui): current = root.get_property(k) if current != v: changed = True + self.katrain.log( + f"Property {k} changed from {current} to {v}, triggering re-analysis of entire game.", OUTPUT_INFO + ) self.katrain.game.root.set_property(k, v) self.update_playerinfo() if changed: diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo index 3b3df3c6d51f86a2478ae07a2d6c23c8177272fb..21a9a179f0ad8eb40f98cdccf38edb53ca01b309 100644 GIT binary patch delta 3426 zcmY+`3rv<(9LMpKK!S1+1O+hx5f#Zq4J63Ch8HSvWOOkbDk>^41t$^lh^To9Gp7>E z!pdvmR#7&m;YO}>x}4Y4E|!%cGdEZ2oaXxeeE(aEy}Y02-2UgB|9PGVYKspPdp||^ zZ*=?|2+C_P4&SwM3wEJ=96RDg z40X`D_Loo#EVBA?)XtWmCRl0h^{9C7n@y-V zdoYywT`L#b*>US|0kyNsR=#0s`3l?#sd6!>K*^{br&;@WRJ?q%5Y@j7)vp${(M{;7 z<4!L4xIKKS{Ec}UwZmUgnYfAys|_4BP zCa(Kd|yA z9v2#T5H;`=YG;>F3-}8)kw5v5#aN`u4MPRYLG5^&S&SN2h1y{qDuWHE3~jac-Ke-; z3m1IcX}%P=9raw_MFr|k{$zhtfJe;H7(+P+wShv^W4H+Q3aLa*P-E?Hp%%K+`~sQ6 zb6<0zlzxv2^gC*2*R4K~C~A*D?WiXzL;X<;OSATDRH}2WeHtpxJXF7G^9|HOw_u2# z|7~1oXU)i*Za-?m6R3edSou%X#5Yk3@#nS34qO*A3AOV~)KQK?-E4WNcrT#F6{6xS zP`#f2YA!Uzni0XG4?=8sm=iHRyaMXt4QE`(|3&=#>3u95^ zCZVT>saz=VEYyI7s7%yi05+foG@@?8Ce%cSP#O3RNs7CI8t=!Aq4r4BktU+*hnizi z8=DeC{?%a)6&g^1n&>rD;0?GKcVPl1@Ivo}V^IC3qZV3f<>mM&<@H#K$1od5u72dS=a#pGOYFvbMsEPgJefLBs)EP&k zGL&ehn#0YBrk8IQGtC94fYnxBZmu^QajoMXz-q2A*SR;TXu;{2OP=dG@Hpa``*@57_;wuqpzp=h4|R4UQK_6@ zPDMQxr5KE_nyXR$>dg;P8Tt}+|G7ifa1j;Yy6HF2_l66{VCqv)?HQ<}%0^`>7uB9` z<(XEVXI7x@mE}lM+}l>)BAMSEu?}ag;VNo^+o;DX;33}*dLqeigRJ~K>XluLT0o7} zuQlJpk<@>NJelq~l6@CC$X6bUo*t_wxKN5pko(NlScffEzZX-fKZ+#B{evkufJ#mL z3~FaHFbr3qCfa1}`%oJ?WaSg)g;esd)LfxL6L;X*)AN~tU2r(6{V8)MD&>`UZ^x*e zt;G=BVeOw=`+oB--29tkoL>D&1H&Ghu=E^}$@HA?|0xQok7om2v)XJ}$ z4X6cgM~&N$n)oZ!geOrOykhl%-caAa-O;FyX{gjaj#|K6)I^Jshr-pM0xvVyUt|IBK3W&zrxX z?u|ApN2dAu$C|xS3rhCsxpZq7V@^b6Vlq}>0cyZ`^AFU*{OV)3aP?g4q~_<)}cbQ7L?<`Bw0xfXIRwa|+`NN($z`Tvk*T gUtSttHhWfcc0^2U)R_M_6_v#2jmvJHHZUpZU&+ixb6 zm}|ONB@szxwU$9-b5^DzR%_R+QV9siQ~w_|`J=l+fS-vo*`iGvu7a&9nY;SjtBZ^IIcmtlbTSxm*97B^umaVrkQ zQyA@>=gv}yq2hvd=rJQ`ji5dWl`tJ?a#QejEJUsGG3<}4Q48FF>R*LJ@imOc4^ay^ zhJ4&vzJko}E?C7a)Xt(=O*jrm4a~$)%t!6?UTZHxE$|VmUxC`$2Gj(bti2kQ?`5+d zm8Sutncp3xpq;f^hZCrs{b=!d^Dk858_36nvmGT$MC~{Y)t-yWS7<(j>c1S-uN<|} zD)iK`jshRoz?b5~=2xg4o<^NS7b?*;)KQ0$B@Po&>71b{THNj-m0t-=BvjEk9 zIqDf&AK?78lPasIM@`&fwximAK;7X*)WGXzB-u652xLue0;;_Lbs`Iqu5OjZn=Rgs z8n@S@pn*-O9esgXz_+MGU6_Q|k&he9Jt$!sYNxqoA!=L+YKLX0lPgD^%ob~}M&+$T zKF)ieZzXO=z0Vz}L|4oZwyy+nW-=xcr=fO`k9z%zP(K~>Q4=h%_9sva-Dd7aQoA>i z6ZPC73QBYYwX+j`gF9zlLha~p)Cq-rCzSk6W)S0OETvVO{RKHSlC2FD1p!$0_ zNbi3Q1#-JRsDzEEfgf4?H7fB*)Iz#YJNVPQh1z*MKa;x3B-F!}jmkF>H7*~OXSUUs zVyxc(WfZica#VunQ9F1=9k2nF;4rG+m)N%;vkP^^7g1Mr12ry``_uyBQO`mOYTR8` zKM6f0o=!mn9z>nQA`HWF)PM@qLs*5HXdmhXK0r3_j-tkQTKi?xmEN@aC>|KKr=T`A z7S%o@(cb@JDm2kjRN{5`G*;pr*o!GRj30FMn}%BGEQ=T8G~zY59^b*4n8>QraS3Vz z)qLrM_M^r(CUO3$6xyiB!E>04@%*n)E1ZL)a1mzUi>QH3sHw|~ zd$9wnNBaGir13x#U%}ma|Lf9u1E|R4oNGe(hiCe6Uzz@nuV(o_O#MdtcQ+JubR*13 zs1ullk@&E=0@ZJ$`2y;MYLUmu?dz-eocoM|5}YtQt;0o(q&_U$Zx5iZYB=hoGEwb0 z7Ux-9U=|~X;TBuG&3p;<4Am=Ues_?95+6amPRCFy{{=Y&cg^CIG5$|=4r<~8RKH^L zahy)P33>C}C&;P0Qx^Y&+>(nO>yI0cdj4Di1r1nX4V!Ts@h;>LTq|-5?lNlPp)_h| zqc8>^Kuz>0s@+3vXotmn%>AgHH>2h~I*$A2jdQJt1i!eZ3f|_`x z)qAMBtwNpD+vXwEGt`EfxZCO@?)HDsyaWom%ju}Z%TWoQGAmIF*k#t5d(F2{&qkxg z9p=yGc~rh`^M=(AoYt|``F^+sQw*R{|D;N^Ii79a diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po index 4858a0e..7fe6945 100644 --- a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po @@ -719,3 +719,7 @@ msgstr "Change in score" #. TODO - top move stats show threshold description msgid "show stats if" msgstr "Show stats if more than ... visits" + +#. TODO - analysis option +msgid "cache analysis to sgf" +msgstr "Cache analysis in SGF" diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo index de4c5eaf6c93ec28de4d72a47467c7d2ecfae5bb..23986c5e03be72b22695dda6559d87f968252ac4 100644 GIT binary patch delta 3472 zcmZwJeN5F=9LMpmaVyWZD1=XcKcobx^BcXe;| zmc^kT;yvq(KPUJ*kiTnhSIsQ8$A9*v*n@f^4#hYekNxmb?2bjQUV-t{U&Fz;(bb!< z7xiYm13U0evygRC=t;vh*P$D&>No&na0Dvg7^I6$$39qqu~?2CT#Q=aGF1P19DqA8 z0S}?#wjm$u(64wX^fCe$}bvD{u_bWc^Wre5f5~xaZSQ@d}&)RR2m; zzZ%p=>oKH`+bQs|J$$Kt*x8EO;aOBBenSO{Vzg4-8+)SXG0wMSI0*8U?1|a<9sofok1<&cT~T>T)jI{l%YPT3=F|&Ohfg{L`^Uiwa^08 zLd#G`v>Y{Vbv*gkWm@MtHlpeWQ445ucDm;`P-huOH1$hzrlTgDj;zrNU3&>CGb@mx zR_E$lT>XO(1r0oe8rXu`**Vk#uAnCJkpCo1LYizWDqs$3$FrPesBueBJ6waxU;`>c zTix?rsJNjf3Vf`UF9q&Iz1KHUf%=j^nTiT9&Y6w_&pM{E3g6g-_ z`8sN$o3V%9|7{esvoJEJ?MF>`5;gF9SHFmw_)pYAJp3%O1MB4+irRS=>L?#ZUABBw zyqTzR0aToYYS;U}l!7LzMeU#g72qAz4nA?ukD&sbM)f<7|1QYs;oOwsIMjx`sJK4V z0y>Vf1xg+dJtBXJvQf|EEJJ%b`gk%_9$z%*QneC$2Gl&NE= zOVxq-_zTX!@yTYF@fFO$MS~;#zd&u^REPq{XP0p}#(2$M#SHY}0X%@6sDFfZvRWO% zZd`*$QJ1dpu1Mx)qjpy2>MuHLP#LO2-K~w-9YgQC!hX~l9YFJUB{!? zZ3q_;Tk&}e-_2O;HKaCq5;`nSb1zueXqK<6^>XL28UU&$nVk8KsgKn0kIy|D;&B-N;+ScSSH zb*PayK%CXS0NFb&DRWunHHq2g7cUaXa<%NPn%&`!=EZ<<{|tuQGolCpvjZ>g-3U~<>@EY=4VxI9F4Uv7Q z_WTDU8JdNO)GJVDS&LfWR@51Pgi&}H^_Cn(WuO@~&$p78F*y2v|se%S(lRd7ye!243Ls@R+3f1<)4Ecb=mM)_m^0pm(+761SM delta 3368 zcmYM$3rv<(9LMp0fQkqrFHn(hfGJ)uQX>(;hL_yCw4%IaDQ4=*q$!iO07p;h#JteV zrqg6uwpd$EOT5jR;WEu`baSOsn$p8(go@LQ-Fd%l=R%q7_W^CF%#M2dlzR~s_$u>i5hp_+y9^{)R}0iKsqL34r*L~)C-28CKy94 z%{0{b*{D6VAVU3>NrT^LLcO@fJ%H*zf?C6Ks0XjO$wb$SdLwhPLR9})R7IvELv5b7 z>%F}a_1tR#7kY3jDx+4^1inB8YR8^<1^HMS>!5&ns7#C980xtxs0^P(RjwLUndiKJ z87l62OB8|3UtYhBYg!(ccYj^I}epX8S40zqkcLjp z)c61sb^aTAyqaF@3ap#p!6nn*h;gR|~6ROT7{Olm26qBdIrD&A1kb7iPF z_(0I2(M4bZAX>(9BQeqqMnOqJvD(0)LzI& zJvYGb7h#~lBe~E6_n|6Lft|1#^*}9Z6E>h;v>8=__mJf6AnN%O-v1kFNjv<03L8fK z*{H+@q54N>`T3u~4ZY}bRN(noiA%5qf5#!1&kwp@I32lV)u@Uz;#}N_+c1IImg5c_ zsy2VwG`<8?p-I>aE27l@b}j;L=mlG_5Zh5p5xF&N_rXE5ry?JFkuO!M8MUcCz=^mY z$6;o+*=3xG<8fk6IDQiUiT1c&A-FX@Mk=M+j^VL z!NxvjpWtOYj_>F3bpt;zec7m7Zs^C7(yr*wpI+Jv$*!FC2(rGQ^S^4K*-AR!4Wl~$ z$%Dhv3_z8p6cs3j8d&A`>roY2jym6~F%{Q)`)$-Fd)M!OisWR+P!sIJ22;EUYC<`f z!uzerJMKZMYY$-}K7)5*J?c1aM^$1EYV&=MIxQEF{c3S{@;@V(gKF0zN!mKp_=Cu* z*>U7#Uf8>hU@q=MmHJ0ipwrk3FJT6z7lp^KKdQt9sCdN~ z!HKBEoSXcKFJLQxQyx8fm*9H($rF9qxMEWRAz;!=SHD2n}Eu^ z5;cK3%*C~+CEbOJcNCesokG1Q8We}69E=J$7q!W1F%F;i_7YSjR-iW78g~n7f(Mc6 zS{v&5gyCVlZm0tlMQz4$s6?Jc4wwZ?xX=u@qe^xJwX1)1|3bYWu_UZe8ge=<>Sm+% zNG|G^Z~|(g52If67%KBhRE26#@s=SK4{S9T{C3zz96;pOu*1%lh9$a!ne=xZ5w2wp zYJ#Px36IBkoPjzevrrY7i+a%l)Wm8~r>7pZCz`OgcF`U#v=+zlUc5M>B`M{BPA&5z MYqDF$44IkyABN#SF#rGn diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po index 0831153..9ba985f 100644 --- a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po @@ -764,3 +764,9 @@ msgstr "Change in Score" #. TODO - top move stats show threshold description msgid "show stats if" msgstr "Show stats if more than ... visits" + +#. TODO - analysis option +msgid "cache analysis to sgf" +msgstr "" +"cache analysis to sgf\n" +"(larger files, only compatible with KaTrain)" diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index f39a64c958de87ecc8d730c18b12c543bda24b3b..5babd5b6ace3742cc10a86878403d7f7ac40f6dc 100644 GIT binary patch delta 3445 zcmY+_3v7*N9LMpeH(D)v4y_i`vsI^MMpa8|%(d#WRVGw3BgUy7mkMPoHZPM*k(rq5 z;=ajTx@>eI3u_ibZP}QO&^ z@~--$H#q*C<$p*1uWzQ7a|tc~vmKW$X(wR@`mi6S;By#{W!9dDe%h-s4Yymn4ijmg z!{+!iwsOvMja;;*Quu>=#a0;6#;D!`?v`!`~H+=p%P z1Zv&}dnVqv6ene$<)7pQU3SSeqK)PHiYN9Mu#<@0Lgqp9!45IF@MBTR> zmFPzFbmLww__)J-sahkn_w_|BFdP+V2`bRp zs4ZHCdTynk`s*-lup4Vo?c=Bb8q7u;e~8*kAG7Jc4rVXZf+LU^U8(iYL{;Vu`<9q* zqXONDE%pBI;X;|!B5S&1s0F`6J$TvLw@?e;Lj@Ae&mtMPL^A`Gc>!uG2cZtzSk!zk zqMi$)=9#O0z5h$N&_dOy47Q*q_yCo`r#AjIYJw}M`)*=WKxQ=irV{&52?bE|W}yNo zK%Ir5sOO5&)4)V7G;tZ~fqAG(EXNq!f_h*F>JZkT7CMcpz(u4e?swGlQ5+17w?%Df zI;ua%9EwV8Tq^a~4dry`fhyEOD^L@!$62@!voM(-^e#9MRiScZO}7Y@z&luiJ8&)D z!(yx^>P)%lq=3HP#hI60b-*_7jk>zRJMY*4iVE<>ZF=y!5&jv5WgGy`?|=b|!QWxk92B)I)pjK@(4`g6i> zQFl~DO3-6F++6F}jBJ}bWbKQniSJ+^jOZPHjq)*{_RHwUtw_x7BW!~|;nR2*l}Klz z)|T}|RdxWXVnw;sUq2|Nbm+BOfQocC@}{`YtbG|3@jX-}e0gEpBj?JcqXHd)+L}^S zg(jgY8?^CPQ59Q(yqRui9`)A*b#y4AUr-U>MZGQ&q^$)LQIV&jCQi5huBf*o$HoVu z0v(Ck%4w*C=3oFoL!7o0bD3AJEc-|!Dn3M!+4sEo!SFM}J0F*pI6GQ@VY zgQ$gHxBg9-Nqal${(4km-&lVGYU{m7Hd2{op&rOVy*?9Bd+VVhU5A=rCn~TSRAr7~ z1fDeOQD@;xRNxO$r(Hj%3M3X)nO4ZWo=dfXE~p8+qu%p8yoTdZCGOKN9LP{iqWywd zjtXcAD&RF3g}YD-?m<=R0BZh2sKAb*U&sA(E;PaSn1a_)3qHbO823!=gM{Z}+D@5T z9t=#Wm@;c&WvDVRe@>usdRc9uKRYdH$p42z6@jtC3u|A=UK5)Ts+itmkUdk|tRO1# EUp5;}8UO$Q delta 3376 zcmYM#3ry8z7{~EPz#9T`O%aq63JG~h2?UwLB!}gN&D3m|8A2^HWwH`*-0(4f8zeP2bXQM(=aXGED0aPo;U)#;S_IIV>0c9n1!pny$KU( z@4?P^0u#)Fc9x6obX@iu?zpjx#?qgG3Yd!wSqa{U6{tB*#~6GOHNiU6{Y}^l-@{bg zikiS-}k8pfamNy`aIzm!aal z<+h;Wtj7f2Z(F!fW_$dGW2nr&^Y+i~4OHN}$j7>pjsm5lGR{Gb7o*};xRX)$&qUo< zk4m%&gSv4I7kq3zUuy4g51=wUiK;{x73e0a)X_vq!F1Gf15trX`O-wjd;c_V&q7V0 z5fx`;67|=OEk5um^08ff@ecbMHGv;c_g(e&->3?8BAP0Yf?Y5Rbzgtf3x=U4Sbg^S%=ROE>p$9jiGWr5Ffg`9uVa&i=$j6dc2L;SQWm@c3pq`t8%J6wq$6>uZ!!R_8YgbI8dHIXnXgJ0cysLWIOnbcBdpf=k;RJ=meb7iPF zW4(VWChGiGbDbYpvQxixpZ|$;=ta+>0?)zO_&Vm{4SWE5@q?}kjY4AEBvb+~;gi^iZ{l&R#A;^U zAGcs1{2tpYg!*F_ok{%_I6!MKj=|yBfXX!F{d;i$?cb5PSXS@IsVPBis`2Bira>&bX+itzieD&V*@^hd~7dYdhjCZk56tOQki^gpTe^ph}*Ly1xi@U$EQ%h#xtwr#J^BWGiYdJ*B7EPoZwDJj=asmN^C+7fPI5HJ*}v?83mEOR)}g( z!ywCKuXxA%sKDEB7#={D$=a|4b03aWY6dbVtH%`l7zg1_REEExmg)~wMWe_Cm}6fO_F6)XdML0$=j}YpBh0+s9)llO~#g+AIB02^3%e zC!i9Wi>k;fWLsGa>U~FoTyP@n9BRff#gU9skwakVsGs6YY|jvT(9T1>_z~}~LM>G_ z>i!j|#8!L%TFj+=5S7?(-XFZpg^o>t1y06t)J&(K0@R=;R)?z0BINkma(4x4FEpc0 z$8OYa-;bKeSE$OIK*c@p{a289L2KnAje)y(0TYKuO5BQi;9t~uTxrB?)P#yr6CQ*5 zg{(ro@EKI4YEcuOjhfiYsQVY7o^QsU`ej(lh1PUCj>dhZq1gBd9Yb@H2WN#sLz=rp M)y@lz8y+3?AMffzxc~qF diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po index c7a9635..cc3b920 100644 --- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po @@ -378,7 +378,7 @@ msgstr "" # teacher settings from here msgid "teacher settings" -msgstr "Edit Teacher Settings" +msgstr "Edit Teaching/Analysis Settings" msgid "point loss threshold" msgstr "Point loss greater than" @@ -405,6 +405,10 @@ msgstr "" "Show dots/SGF comments\n" " for AI players" +#. analysis option +msgid "cache analysis to sgf" +msgstr "Cache analysis in SGF" + #. removed as an option / can ignore msgid "lock ai when playing" msgstr "" diff --git a/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo index 987409a714eb0878ddf74709e15db461511261a6..5f449a7a718d4d2813771e96c181587b34eeaa61 100644 GIT binary patch delta 3426 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 Nq-aFLuB;s${skODQ^EiM delta 3369 zcmYM$3ryBk7{~Dk5EK!VR}o)9@Dko{VJeDv}7I{l+3YE8p7PZpSH)}x`t639u zb83{hz3)^8HCg4gxhzqUkpbt2KTG@}@u6Hk@0$)cy7SD1ND2!Th7V3TuDqev*1vS1H zHLeu3&@zl@;94&DSQTGt?{U9Ct?)Fe5_PCRmr?A6IUr^&Nc>7;eh2n^&3be*%n28$K9rb|0s00g8 zTQd_iz8H0e7KNz4R#N62>roG`c8{R$pF!h45}itkfFA~ z+snNDI%?jA2p5{T1GSRv#t=qjp0(L`5*EwS-6MU}cI>V6I?&KT6V>F#_~ zqDxWZBiKyu{~KHo+bU22x1lC};_a_cfxkl~Qioc>dG|JIBVbt-6ky7sGxkfi|eK zkb#=l!}|weM1e5+gx&FP%)@s4pzE+s#jdyj6>t?6;rqB5o04rY zZpR!<<}X_p9EXIm5^ukfPW?O5v5k%)cpN8V(+)v~)3K2DJnW61BSY*Qs#0+o!J$gW zWwbltBHW0hqll4d_B8Fnj={X6sFl|vx!TnT7lXJ+?!+sCV^Jmk8Y{6D^~Yyf=V0Y4 za0Ttvs6&^^vQ)VY)ZX_(9lpCzTR6-eg*pRcQS%B>TOWCl3r%ASl&=smHCdLgmBPR=EW64kzDMXcS4yt1FP!(J3{Yy{@zJN-o z0z2UcsMqitR07|lw(Ji~(EI-n7YcX_sglKUWHm4wr{GA`gVvx{z6o`B4xkdN#kTk- z&d1xR!#bZ6t#}ovL=K_${C8AkE@Fgjw8WuiG8;8u8nT^MjKs3na5x@DB^I3eW2zuYnus&=ypq0`Engg+r(k zpFtg(-!K&~qbij^S+t^5)SmW5C6J3+;W%Vh?I~28ZOAdR&rr|36yZX96`LRY@@1nE zC_t@vqPJ(bvr!M6i(1igRO0K9H_qPm_AzWn`xJJ?2JD8R5y9V>p_oZKGJy+~=yBAF z-$IqN67>VJ#odlds2X`&ZNFQCTG1iYylbd&x4a!cGFVWOn}Uj)j+~K*b>>1P>y0T< zlnzyz`$h#NeiXG=PoTz?qqd>~m2eft;HRj-`%o1;j5<5VP!&3jn*Wn~zEPfZjSHRD ZW}|~s9IB2_oD^GK5-Q57t{+^L@E&n|Sb?$`!1Q4@180wwCi#H1Q~E;3e<)C$=;{{L)=14q&@+4fD+Wla53sDWEpCKRo?$TYNI>d z&ygj2MNMq*`fsR(@1iym$=4z$unuld)X8&DS2-N@*e0XmO+(Eq zLB(01c76U=P|!lOd)|xap`3QtUcvegqFg{qd+PO+&R0 za7UsJHZ_s_Yrt$8G+_y9p*K*0H)1L7!hGz)7rHD$jjO-`xE)#BE}+KW#M3x~-7dtw z{AJ6d6ZaadkKauaV9*IJh?t4iBcAZNX4RFm7uf4jtnD|02)d6QHiY*(uzX$%Bb7d+AYL z`h8|^KNe(S-k{*|EkPcaIdL!AaU739?5}{ryk}n1s6P#a=JRjnwy`#uf6gH0}lD7HlnsAEvO6 zf)>7n+Q==`z&Ku{b~*?L;xOcpwivVU6VyhpBDZHZQS(#tf_edJ(!_eeCG9|UO(gYtEdCrKrI+m5X9}~4nX!` z<4|9Cog4>pj2d>Aat>)EJ{3`Na*924+)?_ZAk0$YvB*r%ui zeTjYW1nNq|w<&0$j6yTM3T&8LjB0-!HL=3o?(Rip<`C*J9&=A(HuclqA2A{r7ln!w z>vl&D5Vi~-kn0wrPBad)LVQk98+mVJaN-@PK>JYR>b(5|YTU1=Kf5icKVA`|f(^7m zU2O+cMiMdB()hBWpj2j~0*-R0A=hXNYMY}cwu&#FIlCmKcz*G`rDb!vq`+EUWY zv9g@@M`}~@vb8dYmsx?S(ae(6&C1I(b*OCjD zR07A5kDcXD8uQy_uXuo3Srf8Jz;>vCT`&$KsFe=)_OYl0U-0_rsFlq{O|Zz@SE1sq zcgs<6wqq0Kw>>;)Wrw`O3DnAd@$w(;->ATMk&h*?90f{8tvCnOo{x%GOpvG-v$iF!pjYT^p_Fsi){`+No!=%yRX@)e+k+Zxj;=b%;)LA`!sQC}U;p(ZHy_W7tpm%Hnb z(6$BH(ZKfdpg;#vD?1T3*hTjmYDM*^9f~Eo5^RbOUsKdpcR{u1qv8~z`b~6aq7q$< z>K|ZZz5i=@AhvBp1>AuexX;VSP=QaP5~)S4;EMYIwenQHCUumVsLR$J6|Wy^Tm%*8 zDX*W1&Gi0H4LtXY7)XrRP&Hm@|aGQ#J%xJ^8;j^fWm*Fs6kL|Dq6`&rql0>5F?AzcJ%yy&L zGsf&Me3AO}c449mP&>R9HGXTr!xKF0LuGm!btHN1!+`@)KRz2#cVjai#T}@LOCAf) zcCot>wX*k66KqCJxD&PIm8cy&jp`Si_YPOQ!a9T<6Hy&9+-$6*+yk%SEnJ4bXY;Pd zu=*U{ef*m3T!AT_%tqkG&Ln}qb_x5v(T$&A%BR@ovwHu_^UQuA(88X4jm9yk7Z)kk zY)0R3Cq@nkFW)%iV%r?lnMd7^QAc$EbxDt-R(#3J_pm+XmYi=g7NFjSBFxtNKh7H# zx+^h@4rQnTG(VvV}4u0g9etN zGTn+gqa&ylokBLou6z3}WY;bA@$ifbP~}nhKF&kMiRVJ8z7uxE(by47QHg(ofil_8 zgF60<%Jd%g$5?JAi?IUijq_27Zo@p>iyD8)%MAvFiT8DfqWX{V@?^}UJR3P}TQ!LN zS4Ib@P=@C*1Cs`afjgou;Yd_sPb0b61k?_ddHojmGq2x;y8U0F;#Z?4u1D^vr9{FV z$d9o9`pO(bg#u1MO*Gxhvr#Kpv|1B=}m?(3+DmZL7?+wNNIM|qvMA9JfwacbO)s0G~c_6MPX z#Safxl#IP&_zplNGJZrjU?wV1DQe52USE#tw*&Qadl2=bbqtkg73yezLhZ;o)Hmp# ks6_5yn!d~v3d6uz$Z=V}iiG5`4J+oPROMDYQ}A-qe`^0rod5s; diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po index ae45341..4a7f2aa 100644 --- a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po @@ -758,3 +758,7 @@ msgstr "Change in score" #. TODO - top move stats show threshold description msgid "show stats if" msgstr "Show stats if more than ... visits" + +#. TODO - analysis option +msgid "cache analysis to sgf" +msgstr "Cache analysis in SGF" diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo index 4d90b03f64d64291e42d1492e4d7a41bb1424a5b..fe6641cdb12fbb232272e78c7517e2cbb6bbbab3 100644 GIT binary patch delta 3427 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 S|GVZa^pzGCG>*?(8vifjWMn%4 delta 3369 zcmYM#drVhl9LMo5AQw^YKP^N>)SrSE$V|nEK+z}=G4lcwD|W%Tk80&s9A=oWwu3{y+593%N>8O^PJ~7-}8LG&vOp1eH?Of zPe>q`*k*(A?==5A^M6%@T4s0J|L+5w-lg3EJH(hJU|)O?bFm#xaP2Bgq`d@FagA&5 z#(3I|7>VaG)+}I`IEmxJRX5;oXEeRhTu(s-?1gmMQ0$0>s5w51ZEyx^f^$&g>#!5P zgFgHeHGwaY!!GgDf#=&*ci|o?vsh-+7Q3Nt?1N#Lhsw0T^_QY1SnjUBfXZwR>H!N~ z{|Z#Rb7bdE=j zuSSilK_yy;0S(;D35V_EN9_a7FHjj?Kvg1$3Umuq>M)`tVKVBz{;0q?{AeO2?s|o5 zPe)B)5h~8A1nRGW^{(S1Wg6WzEQmC;eu1inE93StW0Mh;709Td=y$~4c;)9eF_!$9BLv#R0h8~@1ZjH@tM?8rl2-ke^k6d zsQdCzaf;pbGK|;zU&V=LRD%joi^||_4ZxkK00&Uxj^q6aIfJMYx1g4)6?I=2>!}I& zP(>b?wjeJ}UFbY+P$rz3`s2dicHens=LEBLk_ykGbPNME_a{bp)OM2H` zk72{8zbh)SEL8vSWcU7$<$@kmi3&U$r{OXz#TLxR96sp8w59k6Za_`=E1ZSj;~gB$ zZ0BP!f6<=8qo@R;yLc7qg(GNZb)o*boXqD!CGN!v^mX-?VlI}`UWUckgjtx8N;X)I zD(ymChs$s^cI;+0GsNrze4TbecQz<)!d`d`)9`A5li{4S>%oS?(a0qm+SBZLtU&$o zIfR+mh@k|&iQ06x{9ff+QEMMbbS+Ull8dD}bCKfMBxHNo%cx2R*0=#XkSbfF8*mv_ zvRm$YTyMULv@@`P2{hq)+G!aq7w!GH0R4T<-oq{Z`0V0PX8j}9QnqEi~EWQ7?IUyPIvkux!C8)KoMwMz0>I-=aBk(e6vo@o4^$pjy z0&jc_vKr<`4lCwIyZ$XyyzNNN_Bp2Ve7oT~;zlrQ+PzV0S%yoo(zS!AOnydXk~q@a zOqrNXdpvH%HK+<@K4CTyr=Z%0a4i0bs%T*$>;EJti#bu?) zQB229W4ujPfXb){V{tM@<4o+13veL5>-tY4)wd?s?)|h^p}{zW>tk>{u0$mo#3~H@ z%ZUP3vNQC+<){zGCg(m>g)X4pf))(Ld(O~jcok`fqbfHSJK|#0#Mh$k-{$-bHSR1X z@qD|;iAwSt?g(Kcj`L=In(1n$zo6DIYJ#_GAICV_b1@NXk=txNhT}$zz4R4s87&f3`MZpr^e-ZdvO8@`> diff --git a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po index f159001..46bca48 100644 --- a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po @@ -767,3 +767,7 @@ msgstr "Change in score" #. TODO - top move stats show threshold description msgid "show stats if" msgstr "Show stats if more than ... visits" + +#. TODO - analysis option +msgid "cache analysis to sgf" +msgstr "Cache analysis in SGF" diff --git a/katrain/popups.kv b/katrain/popups.kv index eca98e4..6cdca00 100644 --- a/katrain/popups.kv +++ b/katrain/popups.kv @@ -280,10 +280,10 @@ DescriptionLabel: text: i18n._("save dots") AnchorLayout: - size_hint: 1, 3 + size_hint: 1, 4 GridLayout: cols: 2 - rows: 4 + rows: 5 padding: 4 size_hint: 0.95, 1 DescriptionLabel: @@ -293,25 +293,25 @@ LabelledSpinner: size_hint: 0.95,0.8 input_property: 'trainer/theme' - font_size: DESC_FONT_SIZE * 0.8 id: themes_spinner DescriptionLabel: font_size: DESC_FONT_SIZE * 0.8 text: i18n._("stats on top move") - BoxLayout: - orientation: 'horizontal' - size_hint: 1.5,1 - LabelledSpinner: - id: top_moves_show - value_refs: TOP_MOVE_OPTIONS - input_property: "trainer/top_moves_show" - Label: - size_hint: 0.1, 1 - text: '&' - LabelledSpinner: - id: top_moves_show_secondary - value_refs: TOP_MOVE_OPTIONS - input_property: "trainer/top_moves_show_secondary" + AnchorLayout: + BoxLayout: + size_hint: 1, 0.8 + orientation: 'horizontal' + LabelledSpinner: + id: top_moves_show + value_refs: TOP_MOVE_OPTIONS + input_property: "trainer/top_moves_show" + Label: + size_hint: 0.1, 1 + text: '&' + LabelledSpinner: + id: top_moves_show_secondary + value_refs: TOP_MOVE_OPTIONS + input_property: "trainer/top_moves_show_secondary" DescriptionLabel: font_size: DESC_FONT_SIZE * 0.8 text: i18n._("show stats if") @@ -332,6 +332,12 @@ AnchorLayout: LabelledCheckBox: input_property: "trainer/eval_show_ai" + DescriptionLabel: + font_size: DESC_FONT_SIZE * 0.8 + text: i18n._("cache analysis to sgf") + AnchorLayout: + LabelledCheckBox: + input_property: "trainer/save_analysis" AnchorLayout: size_hint: 1,1.5 AutoSizedRoundedRectangleButton: diff --git a/requirements.txt b/requirements.txt index 67fb1d9..8965eac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +bson==0.5.10 certifi==2020.6.20 chardet==3.0.4 Cython==0.29.14 diff --git a/setup.py b/setup.py index 9cdf005..7cc9736 100644 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ setup( "wheel", "setuptools", "urllib3", + "bson", "importlib_resources ;python_version<'3.7'", "cython>=0.24,<=0.29.14,!=0.27,!=0.27.2", # kivy wants this "kivy==2.0.0rc2;platform_system=='Darwin'", # rc3 failing on mac