diff --git a/README.md b/README.md index 77b2fc58..508fb966 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![License:MIT](https://img.shields.io/pypi/l/katrain)](https://en.wikipedia.org/wiki/MIT_License) [![GitHub Downloads](https://img.shields.io/github/downloads/sanderland/katrain/total?color=%23336699&label=github%20downloads)](https://github.com/sanderland/katrain/releases) [![PyPI Downloads](https://pepy.tech/badge/katrain)](https://pepy.tech/project/katrain) -[![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=6&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland) +[![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=7&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland) [![Discord](https://img.shields.io/discord/417022162348802048?logo=discord)](https://discord.com/channels/417022162348802048/629446365688365067) @@ -14,6 +14,7 @@ * [Previews and YouTube tutorials](#preview) * [Installation](#install) * [Manual](#ai) + * [Configuring KataGo](#kata) * [Play against AI](#ai) * [Analyzing your Games](#analysis) * [Keyboard shortcuts](#keyboard) @@ -61,10 +62,9 @@ but has since grown to include a wide range of features, including: ### YouTube videos -| **New Features in v1.3** | **Analysis Tutorial** | **Teaching Game Tutorial** | +| **New Features in v1.4** | **Analysis Tutorial** | **Teaching Game Tutorial** | |:-----------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------:| -| [![New Features Video](https://user-images.githubusercontent.com/48946947/86819542-1514ee80-c088-11ea-954e-7830f7926b97.png)](https://www.youtube.com/watch?v=h8qCzjd5tEo) | [![Analysis Tutorial](https://i.imgur.com/3EP4IEr.png)](https://www.youtube.com/watch?v=qjxkcKgrsbU) | [![ Teaching Game Tutorial](https://i.imgur.com/jAdcSL5.png)](https://www.youtube.com/watch?v=wFl4Bab_eGM) | - +| [![New Features Video](https://i.imgur.com/IXNwTHL.png)](https://www.youtube.com/watch?v=ujjRWGSZJrQ&feature=youtu.be) | [![Analysis Tutorial](https://i.imgur.com/3EP4IEr.png)](https://www.youtube.com/watch?v=qjxkcKgrsbU) | [![ Teaching Game Tutorial](https://i.imgur.com/jAdcSL5.png)](https://www.youtube.com/watch?v=wFl4Bab_eGM) | @@ -74,6 +74,21 @@ but has since grown to include a wide range of features, including: * [This page](INSTALL.md) has detailed instructions for Window, Linux and MacOS, as well as troubleshooting and setting up KataGo to use multiple GPUs. +## Configuring KataGo + +KaTrain comes pre-packaged with a working KataGo (OpenCL version) for Windows and Linux operating systems, and the 15 block neural network. + +To change the model, open 'General and Engine settings' in the application and 'Download models'. You can then select the model you want from the dropdown menu. + +To change the katago binary, + e.g. to the Eigen/CPU version if you don't have a GPU, click 'Download KataGo versions'. + You can then select the KataGo binary from the dropdown menu. + +Finally, you can override the entire command used to start the analysis engine, which + can be useful for connecting to a remote server. Do keep in mind that KaTrain uses the *analysis engine* + of KataGo, and not the GTP engine. + + ## Play against AI * Select the players in the main menu, or under 'New Game'. @@ -181,7 +196,7 @@ In addition to shortcuts mentioned above and those shown in the main menu: * KataGo crashes with out of memory errors, how can I prevent this? * Try using a lower number for `nnMaxBatchSize` in `KataGo/analysis_config.cfg`, and avoid using versions compiled with large board sizes. * If still encountering problems, please start KataGo by itself to check for any errors it gives. - * Note that if you don't have a GPU, or your GPU does not support OpenCL, you may not be able to use KataGo. + * Note that if you don't have a GPU, or your GPU does not support OpenCL, you should use the 'eigen' binaries which run on CPU only. * How can I play on larger boards? * For windows, change the `katago` setting to `katrain\KataGo\katago-bs52.exe`. For other operating systems, you need to compile your own KataGo version with higher limits. @@ -189,9 +204,9 @@ In addition to shortcuts mentioned above and those shown in the main menu: ## Support / Contribute [![GitHub issues](https://img.shields.io/github/issues/sanderland/katrain)](https://github.com/sanderland/katrain/issues) -[![Contributors](https://img.shields.io/static/v1?label=contributors&message=17&color=dcb424)](CONTRIBUTIONS.md) +[![Contributors](https://img.shields.io/static/v1?label=contributors&message=19&color=dcb424)](CONTRIBUTIONS.md) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/sanderbaduk)](https://liberapay.com/sanderbaduk/) -[![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=6&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland) +[![Github sponsors](https://img.shields.io/static/v1?label=sponsor&message=7&logo=GitHub&color=dcb424&link=https://github.com/sponsors/sanderland/)](https://github.com/sponsors/sanderland) * Ideas, feedback, and contributions to code or translations are all very welcome. * For suggestions and planned improvements, see [open issues](https://github.com/sanderland/katrain/issues) on github to check if the functionality is already planned. diff --git a/katrain/KataGo/analysis_config.cfg b/katrain/KataGo/analysis_config.cfg index 203b267f..84a0130d 100644 --- a/katrain/KataGo/analysis_config.cfg +++ b/katrain/KataGo/analysis_config.cfg @@ -1,11 +1,17 @@ # Example config for C++ (non-python) gtp bot # SEE NOTES ABOUT PERFORMANCE AND MEMORY USAGE IN gtp_example.cfg +# SEE NOTES ABOUT numSearchThreads AND OTHER IMPORTANT PARAMS BELOW! # Logs------------------------------------------------------------------------------------ # Where to output log? logFile = "~/.katrain/katago_log.txt" +# logFile = analysis.log # Use this instead of logDir to just specify a single file directly +# logToStderr = true # Echo everything output to log file to stderr as well +# logAllRequests = false # Log all input lines received to the analysis engine. +# logAllResponses = false # Log all lines output to stdout from the analysis engine. +# logSearchInfo = false # Log debug info for every search performed # Controls the number of moves after the first move in a variation. # analysisPVLen = 15 @@ -47,22 +53,64 @@ maxVisits = 500 # If provided, cap search time at this many seconds # maxTime = 60 -# Number of threads to use in each search in parallel for any SINGLE position. -# NOTE: Analysis engine can specify number of POSITIONS to be able to search in parallel via command line argument -# so this number does not necessarily need to be larger than 1, although you can still set it larger if you prefer -# to analyze fewer positions in parallel but spend more threads on each position. -# Generally, having more threads on a single position will worsen the quality of search slightly, holding fixed the -# number of visits, and thread contention will reduce efficiency, so cross-position parallelization is preferable -# to numSearchThreads, but numSearchThreads is preferable if you want to reduce latency, and have individual -# searches complete faster by doing fewer of them at a time. -numSearchThreads = 6 -# GPU Settings------------------------------------------------------------------------------- +# numSearchThreads is the number of threads to use in each MCTS tree search in parallel for any individual position. +# But NOTE: Analysis engine also specifies max number of POSITIONS to be able to search in parallel via command line +# argument, -num-analysis-threads. + +# Parallelization across positions is more efficient since the threads on different positions operate +# on different MCTS trees so they don't have to synchronize with each other. Also, multiple threads on the same MCTS +# tree weakens the search (holding playouts fixed) due to out of date statistics on nodes and suboptimal exploration, +# although the loss is still quite small for only 2,4,8 threads. So you often want to keep numSearchThreads small, +# unlike in GTP. + +# But obviously you only get the benefit of parallelization across positions when you actually have lots of positions +# that you are querying at once. + +# Therefore: +# * If you plan to use the analysis engine only for batch processing large numbers of positions, +# it's preferable to set this to only a small number (e.g. 1,2,4) and use a higher -num-analysis-threads. +# * But if you sometimes plan to query the analysis engine for single positions, or otherwise in smaller quantities +# than -num-analysis-threads, or if you plan to be user-interactive such that the response time on some individual +# analysis requests is important to keep low, then set this to a larger number and use somewhat fewer analysis threads, +# That way, individual searches complete faster due to having more threads on each one and doing fewer other ones at a time. + +# For 19x19 boards, weaker GPUs probably want a TOTAL number of threads (numSearchThreads * num-analysis-threads) +# between 4 and 32. Mid-tier GPUs probably between 16 and 64. Strong GPUs probably between 32 and 256. +# But there's no substitute for experimenting and seeing what's best for your hardware and your usage case. +# Keep in mind that the number of threads you want doesn't necessarily have much to do with how many cores you +# have on your system, and could easily exceed the number of cores. GPU batching is (usually) the dominant consideration. +numSearchThreads = 8 + +# nnMaxBatchSize is the max number of positions to send to a single GPU at once. Generally, it should be the case that: +# (number of GPUs you will use * nnMaxBatchSize) >= (numSearchThreads * num-analysis-threads) +# That way, when each threads tries to request a GPU eval, your batch size summed across GPUs is large enough to handle them +# all at once. However, it can be sensible to set this a little smaller if you are limited on GPU memory, +# too large a number may fail if the GPU doesn't have enough memory. +nnMaxBatchSize = 96 + +# Eigen-specific settings-------------------------------------- +# These only apply when using the Eigen (pure CPU) version of KataGo. + +# This is the number of CPU threads for evaluating the neural net on the Eigen backend. +# It defaults to min(numAnalysisThreads * numSearchThreadsPerAnalysisThread, numCPUCores). +# numEigenThreadsPerModel = X + +# Uncomment and set these smaller if you ONLY are going to use the analysis engine for smaller boards (or plan to +# run multiple instances, with some instances only handling smaller boards). It should improve performance. +# It may also mean you can use more threads profitably. +# maxBoardXSizeForNNBuffer = 19 +# maxBoardYSizeForNNBuffer = 19 + +# TO USE MULTIPLE GPUS: +# Uncomment and set this to the number of GPUs you have and/or would like to use... +# AND if it is more than 1, uncomment the appropriate CUDA or OpenCL section below. +# numNNServerThreadsPerModel = 1 + +# Other General GPU Settings------------------------------------------------------------------------------- -# Maximum number of positions to send to GPU at once. -nnMaxBatchSize = 72 # Cache up to 2 ** this many neural net evaluations in case of transpositions in the tree. -nnCacheSizePowerOfTwo = 19 +nnCacheSizePowerOfTwo = 20 # Size of mutex pool for nnCache is 2 ** this nnMutexPoolSizePowerOfTwo = 16 # Randomize board orientation when running neural net evals? @@ -99,7 +147,6 @@ nnRandomize = true # cudaUseFP16 = auto # cudaUseNHWC = auto - # OpenCL GPU settings-------------------------------------- # These only apply when using the OpenCL version of KataGo. diff --git a/katrain/KataGo/katago b/katrain/KataGo/katago index 65163686..99298c04 100755 Binary files a/katrain/KataGo/katago and b/katrain/KataGo/katago differ diff --git a/katrain/KataGo/katago-bs52.exe b/katrain/KataGo/katago-bs52.exe deleted file mode 100644 index 98e365c8..00000000 Binary files a/katrain/KataGo/katago-bs52.exe and /dev/null differ diff --git a/katrain/KataGo/katago.exe b/katrain/KataGo/katago.exe index 15563c10..b416e3cd 100644 Binary files a/katrain/KataGo/katago.exe and b/katrain/KataGo/katago.exe differ diff --git a/katrain/__main__.py b/katrain/__main__.py index 1ea853fd..5dd6f62a 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -99,6 +99,7 @@ def __init__(self, **kwargs): self._keyboard = Window.request_keyboard(None, self, "") self._keyboard.bind(on_key_down=self._on_keyboard_down) + Clock.schedule_interval(self.animate_pondering, 0.1) def log(self, message, level=OUTPUT_INFO): super().log(message, level) @@ -118,6 +119,12 @@ def log(self, message, level=OUTPUT_INFO): ) and getattr(self, "controls", None): self.controls.set_status(f"ERROR: {message}", STATUS_ERROR) + def animate_pondering(self, *_args): + if not self.idle_analysis: + self.board_controls.engine_status_pondering = -1 + else: + self.board_controls.engine_status_pondering += 5 + @property def play_analyze_mode(self): return self.play_mode.mode @@ -323,7 +330,7 @@ def _do_teacher_popup(self): self.controls.timer.paused = True if not self.teacher_settings_popup: self.teacher_settings_popup = I18NPopup( - title_key="teacher settings", size=[dp(800), dp(700)], content=ConfigTeacherPopup(self) + title_key="teacher settings", size=[dp(800), dp(750)], content=ConfigTeacherPopup(self) ).__self__ self.teacher_settings_popup.content.popup = self.teacher_settings_popup self.teacher_settings_popup.open() @@ -332,7 +339,7 @@ def _do_config_popup(self): self.controls.timer.paused = True if not self.config_popup: self.config_popup = I18NPopup( - title_key="general settings title", size=[dp(1200), dp(800)], content=ConfigPopup(self) + title_key="general settings title", size=[dp(1200), dp(950)], content=ConfigPopup(self) ).__self__ self.config_popup.content.popup = self.config_popup self.config_popup.open() @@ -452,6 +459,7 @@ def _on_keyboard_down(self, _keyboard, keycode, _text, modifiers): if popup: if keycode[1] in ["f5", "f6", "f7", "f8"]: # switch between popups popup.dismiss() + return else: return diff --git a/katrain/config.json b/katrain/config.json index 47b26ad3..6c51d8a0 100644 --- a/katrain/config.json +++ b/katrain/config.json @@ -1,12 +1,13 @@ { "engine": { "katago": "", + "altcommand": "", "model": "katrain/models/g170e-b15c192-s1672170752-d466197061.bin.gz", "config": "katrain/KataGo/analysis_config.cfg", "threads": 12, "max_visits": 500, "fast_visits": 50, - "max_time": 3.0, + "max_time": 8.0, "wide_root_noise": 0.0, "_enable_ownership": true }, @@ -16,7 +17,7 @@ "anim_pv_time": 0.5, "debug_level": 0, "lang": "en", - "version": "1.3.4" + "version": "1.4.0" }, "timer": { "byo_length": 30, @@ -65,6 +66,7 @@ true ], "eval_off_show_last": 3, + "text_point_loss": false, "eval_show_ai": true, "lock_ai": false }, diff --git a/katrain/core/ai.py b/katrain/core/ai.py index eefb3da9..e39923a0 100644 --- a/katrain/core/ai.py +++ b/katrain/core/ai.py @@ -91,7 +91,7 @@ def ai_rank_estimation(strategy, settings) -> int: def weighted_selection_without_replacement(items: List[Tuple], pick_n: int) -> List[Tuple]: """For a list of tuples where the second element is a weight, returns random items with those weights, without replacement.""" - elt = [(math.log(random.random()) / item[1], item) for item in items] # magic + elt = [(math.log(random.random()) / (item[1] + 1e-18), item) for item in items] # magic return [e[1] for e in heapq.nlargest(pick_n, elt)] # NB fine if too small diff --git a/katrain/core/constants.py b/katrain/core/constants.py index 150687ee..d37d4102 100644 --- a/katrain/core/constants.py +++ b/katrain/core/constants.py @@ -1,6 +1,6 @@ -VERSION = "1.3.4" +VERSION = "1.4.0" HOMEPAGE = "https://github.com/sanderland/katrain" -CONFIG_MIN_VERSION = "1.3.3" # keep config files from this version +CONFIG_MIN_VERSION = "1.4.0" # keep config files from this version OUTPUT_ERROR = -1 OUTPUT_KATAGO_STDERR = -0.5 diff --git a/katrain/core/engine.py b/katrain/core/engine.py index 0ef853b1..89714c8f 100644 --- a/katrain/core/engine.py +++ b/katrain/core/engine.py @@ -30,7 +30,7 @@ class KataGoEngine: def get_rules(node): return KataGoEngine.RULESETS.get(str(node.ruleset).lower(), "japanese") - def __init__(self, katrain, config, override_command=None): + def __init__(self, katrain, config): self.katrain = katrain self.queries = {} # outstanding query id -> start time and callback self.config = config @@ -43,10 +43,8 @@ def __init__(self, katrain, config, override_command=None): self.stderr_thread = None exe = config.get("katago", "").strip() - if override_command: - self.command = override_command - elif exe.startswith('"') and exe.endswith('"'): - self.command = exe.strip('"') + if config.get("altcommand", ""): + self.command = config["altcommand"] else: if not exe: if platform == "win": @@ -82,7 +80,6 @@ def __init__(self, katrain, config, override_command=None): def start(self): try: self.katrain.log(f"Starting KataGo with {self.command}", OUTPUT_DEBUG) - self.katago_process = subprocess.Popen( self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True ) @@ -107,8 +104,12 @@ def check_alive(self, os_error="", exception_if_dead=False): ok = self.katago_process and self.katago_process.poll() is None if not ok and exception_if_dead: if self.katago_process: - os_error += f"status {self.katago_process and self.katago_process.poll()}" - died_msg = i18n._("Engine died unexpectedly").format(error=os_error) + code = self.katago_process and self.katago_process.poll() + if code == 3221225781: + died_msg = i18n._("Engine missing DLL") + else: + os_error += f"status {code}" + died_msg = i18n._("Engine died unexpectedly").format(error=os_error) self.katrain.log(died_msg, OUTPUT_ERROR) self.katago_process = None else: @@ -150,7 +151,7 @@ def _read_stderr_thread(self): def _analysis_read_thread(self): while self.katago_process is not None: try: - line = self.katago_process.stdout.readline() + line = self.katago_process.stdout.readline().strip() if self.katago_process and not line: self.check_alive(exception_if_dead=True) except OSError as e: diff --git a/katrain/gui.kv b/katrain/gui.kv index 0fd9e060..407e970a 100644 --- a/katrain/gui.kv +++ b/katrain/gui.kv @@ -247,9 +247,16 @@ size_hint: None, 1 width: self.height canvas: + Color: + rgba: YELLOW + Ellipse: + pos: self.pos[0] + self.width/2 - self.width/6, self.pos[1] + self.height/2 - self.width/6 + size: self.width/3, self.width/3 Color: rgba: root.engine_status_col Ellipse: + angle_start: 0 if root.engine_status_pondering==-1 else root.engine_status_pondering % 360 + angle_end: 360 if root.engine_status_pondering==-1 else (root.engine_status_pondering % 360 + 180) pos: self.pos[0] + self.width/2 - self.width/6, self.pos[1] + self.height/2 - self.width/6 size: self.width/3, self.width/3 Color: @@ -501,6 +508,7 @@ orientation: 'vertical' players: {'B':B_player,'W':W_player} engine_status_col: [1,1,1,1] + engine_status_pondering: -1 timer:timer graph: graph rank_graph: rank_graph diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index 12373e97..01ddf542 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -10,14 +10,14 @@ from kivy.graphics.context_instructions import Color from kivy.graphics.vertex_instructions import Ellipse, Line, Rectangle from kivy.metrics import dp -from kivy.properties import BooleanProperty, ListProperty, ObjectProperty +from kivy.properties import BooleanProperty, ListProperty, NumericProperty, ObjectProperty from kivy.uix.dropdown import DropDown from kivy.uix.widget import Widget from kivymd.app import MDApp from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.floatlayout import MDFloatLayout -from katrain.core.constants import MODE_PLAY, OUTPUT_DEBUG +from katrain.core.constants import MODE_PLAY, OUTPUT_DEBUG, STATUS_TEACHING from katrain.core.game import Move from katrain.core.lang import i18n from katrain.core.utils import evaluation_class, var_to_grid @@ -63,8 +63,7 @@ def check_next_move_ghost(self, touch): self.draw_hover_contents() def on_touch_down(self, touch): - self.animating_pv = None # any click kills PV from label/move - self.draw_hover_contents() + self.set_animating_pv(None, None) # any click kills PV from label/move if "button" in touch.profile and touch.button != "left": return self.check_next_move_ghost(touch) @@ -88,19 +87,19 @@ def on_mouse_pos(self, *args): # https://gist.github.com/opqopq/15c707dc4cffc2b ] if near_move: self.set_animating_pv(near_move[0][0], near_move[0][1]) - else: - self.animating_pv = None - self.draw_hover_contents() + elif self.animating_pv is not None: + self.set_animating_pv(None, None) # any click kills PV from label/move if inside and self.animating_pv is not None: d_sq = (pos[0] - self.animating_pv[3][0]) ** 2 + (pos[1] - self.animating_pv[3][1]) if d_sq > 2 * self.stone_size ** 2: # move too far from where it was activated - self.animating_pv = None - self.draw_hover_contents() + self.set_animating_pv(None, None) # any click kills PV from label/move self.last_mouse_pos = pos def play_stone_sound(self, *_args): if self.katrain.config("timer/sound"): - random.choice(self.stones_sounds).play() + sound = random.choice(self.stones_sounds) + if sound: + sound.play() def on_touch_up(self, touch): if ("button" in touch.profile and touch.button != "left") or not self.gridpos_x: @@ -305,19 +304,40 @@ def draw_board_contents(self, *_args): self.draw_stone(1, y, "B", innercol=STONE_COLORS["W"], evalcol=evalcol) self.draw_stone(2, y, "W", evalcol=evalcol, evalscale=y / (board_size_y - 1)) self.draw_stone(3, y, "W", innercol=STONE_COLORS["B"], evalcol=evalcol) - # self.draw_stone(4, y, evalcol=[*evalcol[:3], 0.5], scale=0.8) # ownership - allow one move out of date for smooth animation ownership = current_node.ownership or (current_node.parent and current_node.parent.ownership) if katrain.analysis_controls.ownership.active and ownership: - ownership_grid = var_to_grid(ownership, (board_size_x, board_size_y)) rsz = self.grid_size * 0.2 - for y in range(board_size_y - 1, -1, -1): - for x in range(board_size_x): - ix_owner = "B" if ownership_grid[y][x] > 0 else "W" - if ix_owner != (has_stone.get((x, y), -1)): - Color(*STONE_COLORS[ix_owner][:3], abs(ownership_grid[y][x])) - Rectangle(pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz)) + if ( + current_node.children + and katrain.controls.status_state[1] == STATUS_TEACHING + and current_node.children[-1].auto_undo + and current_node.children[-1].ownership + ): # loss + loss_grid = var_to_grid( + [a - b for a, b in zip(current_node.children[-1].ownership, ownership)], + (board_size_x, board_size_y), + ) + + for y in range(board_size_y - 1, -1, -1): + for x in range(board_size_x): + loss = max(0, (-1 if current_node.children[-1].move.player == "B" else 1) * loss_grid[y][x]) + if loss > 0: + Color(*EVAL_COLORS[self.trainer_config["theme"]][1][:3], loss) + Rectangle( + pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz) + ) + else: + ownership_grid = var_to_grid(ownership, (board_size_x, board_size_y)) + for y in range(board_size_y - 1, -1, -1): + for x in range(board_size_x): + ix_owner = "B" if ownership_grid[y][x] > 0 else "W" + if ix_owner != (has_stone.get((x, y), -1)): + Color(*STONE_COLORS[ix_owner][:3], abs(ownership_grid[y][x])) + Rectangle( + pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz) + ) policy = current_node.policy if ( @@ -434,6 +454,20 @@ def draw_hover_contents(self, *_args): col=[*self.eval_color(move_dict["pointsLost"])[:3], alpha], r=self.stone_size * scale, ) + if self.trainer_config["text_point_loss"]: + if move_dict["pointsLost"] < 0.05: + ptloss_text = "0.0" + else: + ptloss_text = f"{-move_dict['pointsLost']:+.1f}" + sizefac = 1 + Color(*BLACK) + draw_text( + pos=(self.gridpos_x[move.coords[0]], self.gridpos_y[move.coords[1]]), + text=ptloss_text, + font_size=self.grid_size * sizefac / 2.5, + font_name="Roboto", + ) + if i == 0: Color(*TOP_MOVE_BORDER_COLOR) Line( @@ -499,10 +533,13 @@ def draw_pv(self, pv, node, up_to_move): draw_text(pos=board_coords, text=str(i + 1), font_size=self.grid_size * sizefac / 1.45, font_name="Roboto") def set_animating_pv(self, pv, node): - if node is not None and ( + if pv is None: + self.animating_pv = None + elif node is not None and ( not self.animating_pv or not (self.animating_pv[0] == pv and self.animating_pv[1] == node) ): self.animating_pv = (pv, node, time.time(), self.last_mouse_pos) + self.draw_hover_contents() def show_pv_from_comments(self, pv_str): self.set_animating_pv(pv_str[1:].split(" "), self.katrain.controls.active_comment_node.parent) @@ -545,3 +582,4 @@ def build_dropdown(self): class BadukPanControls(MDFloatLayout): engine_status_col = ListProperty(ENGINE_DOWN_COL) + engine_status_pondering = NumericProperty(-1) diff --git a/katrain/gui/controlspanel.py b/katrain/gui/controlspanel.py index 8d34b4b0..37f1cf5f 100644 --- a/katrain/gui/controlspanel.py +++ b/katrain/gui/controlspanel.py @@ -90,10 +90,11 @@ def update_players(self, *_args): def set_status(self, msg, status_type, at_node=None): 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 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) self.status.text = msg self.status.error = status_type == STATUS_ERROR - Clock.schedule_once(self.update_evaluation, 0) # handles showing completed analysis and score graph def update_evaluation(self, *_args): diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index e5860f20..1ba0c1d0 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -1,7 +1,9 @@ import glob import os import re +import stat from typing import Any, Dict, List, Tuple, Union +from zipfile import ZipFile from kivy.clock import Clock from kivy.metrics import dp @@ -10,6 +12,7 @@ from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.popup import Popup +from kivy.utils import platform from kivymd.app import MDApp from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.selectioncontrol import MDCheckbox @@ -374,12 +377,14 @@ class ConfigPopup(QuickConfigGui): def __init__(self, katrain): super().__init__(katrain) self.paths = [self.katrain.config("engine/model"), "katrain/models", "~/.katrain"] + self.katago_paths = [self.katrain.config("engine/katago"), "~/.katrain"] MDApp.get_running_app().bind(language=self.check_models) + MDApp.get_running_app().bind(language=self.check_katas) def build_and_set_properties(self, *_args): super().build_and_set_properties() - def check_models(self, *args): # WIP + def check_models(self, *args): done = set() model_files = [] for path in self.paths + [self.model_path.text]: @@ -405,12 +410,58 @@ def check_models(self, *args): # WIP self.model_files.values = [models_available_msg] + model_files self.model_files.text = models_available_msg + def check_katas(self, *args): + done = set() + model_files = [] + for path in self.katago_paths + [self.katago_path.text]: + path = path.rstrip("/\\") + if path.startswith("katrain"): + path = path.replace("katrain", PATHS["PACKAGE"].rstrip("/\\"), 1) + path = os.path.expanduser(path) + if not os.path.isdir(path): + path, _file = os.path.split(path) + slashpath = path.replace("\\", "/") + if slashpath in done or not os.path.isdir(path): + continue + done.add(slashpath) + files = [ + f.replace("/", os.path.sep).replace(PATHS["PACKAGE"], "katrain") + for ftype in ["katago*"] + for f in glob.glob(slashpath + "/" + ftype) + if os.path.isfile(f) and not f.endswith(".zip") + ] + if files and path not in self.paths: + self.paths.append(path) # persistent on paths with models found + model_files += files + katas_available_msg = i18n._("katago binaries available").format(num=len(model_files)) + self.katago_files.values = [katas_available_msg, i18n._("default katago option")] + sorted( + model_files, key=lambda f: "bs29" in f + ) + self.katago_files.text = katas_available_msg + MODELS = { "latest 20b": "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170e-b20c256x2-s5303129600-d1228401921.bin.gz", "latest 30b": "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170-b30c320x2-s4824661760-d1229536699.bin.gz", "latest 40b": "https://github.com/lightvector/KataGo/releases/download/v1.4.5/g170-b40c256x2-s5095420928-d1229425124.bin.gz", } + KATAGOS = { + "win": { + "OpenCL v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-gpu-opencl-windows-x64.zip", + "CUDA v1.6.1 (New NVIDIA cards)": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-gpu-cuda10.2-windows-x64.zip", + "Eigen AVX2 (Modern CPUs) v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-cpu-eigen-avx2-windows-x64.zip", + "Eigen (CPU, Non-optimized) v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-cpu-eigen-windows-x64.zip", + "OpenCL v1.6.1 (bigger boards)": "https://github.com/lightvector/KataGo/releases/download/v1.6.1%2Bbs29/katago-v1.6.1+bs29-gpu-opencl-windows-x64.zip", + }, + "linux": { + "OpenCL v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-gpu-opencl-linux-x64.zip", + "CUDA v1.6.1 (New NVIDIA cards)": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-gpu-cuda10.2-linux-x64.zip", + "Eigen AVX2 (Modern CPUs) v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-cpu-eigen-avx2-linux-x64.zip", + "Eigen (CPU, Non-optimized) v1.6.1": "https://github.com/lightvector/KataGo/releases/download/v1.6.1/katago-v1.6.1-cpu-eigen-linux-x64.zip", + "OpenCL v1.6.1 (bigger boards)": "https://github.com/lightvector/KataGo/releases/download/v1.6.1%2Bbs29/katago-v1.6.1+bs29-gpu-opencl-linux-x64.zip", + }, + } + def download_models(self, *_largs): def download_complete(req, tmp_path, path, model): try: @@ -449,8 +500,81 @@ def download_complete(req, tmp_path, path, model): progress.start(self.download_progress_box) downloading = True if not downloading: - self.download_progress_box.add_widget(Label(text=i18n._("All models downloaded"), text_size=(None, dp(50)))) - print("x") + self.download_progress_box.add_widget( + Label(text=i18n._("All models downloaded"), font_name=i18n.font_name, text_size=(None, dp(50))) + ) + + def download_katas(self, *_largs): + def unzipped_name(zipfile): + if platform == "win": + return zipfile.replace(".zip", ".exe") + else: + return zipfile.replace(".zip", "") + + def download_complete(req, tmp_path, path, binary): + try: + if tmp_path.endswith(".zip"): + with ZipFile(tmp_path, "r") as zipObj: + exes = [f for f in zipObj.namelist() if f.startswith("katago")] + if len(exes) != 1: + raise FileNotFoundError( + f"Zip file {tmp_path} does not contain exactly 1 file starting with 'katago' (contents: {zipObj.namelist()})" + ) + with open(path, "wb") as fout: + fout.write(zipObj.read(exes[0])) + os.chmod(path, os.stat(path).st_mode | stat.S_IXUSR | stat.S_IXGRP) + for f in zipObj.namelist(): + if f.lower().endswith("dll"): + with open(os.path.join(os.path.split(path)[0], f), "wb") as fout: + fout.write(zipObj.read(f)) + os.remove(tmp_path) + else: + os.rename(tmp_path, path) + self.katrain.log(f"Download of katago binary {binary} model complete -> {path}", OUTPUT_INFO) + except Exception as e: + self.katrain.log( + f"Download of katago binary {binary} complete, but could not move file: {e}", OUTPUT_ERROR + ) + self.check_katas() + + for c in self.katago_download_progress_box.children: + if isinstance(c, ProgressLoader) and c.request: + c.request.cancel() + self.katago_download_progress_box.clear_widgets() + downloading = False + for name, url in self.KATAGOS.get(platform, {}).items(): + filename = os.path.split(url)[1] + exe_name = unzipped_name(filename) + if not any(os.path.split(f)[1] == exe_name for f in self.katago_files.values): + savepath_tmp = os.path.expanduser(os.path.join("~/.katrain", filename)) + exe_path_name = os.path.expanduser(os.path.join("~/.katrain", exe_name)) + self.katrain.log(f"Downloading binary {name} from {url} to {savepath_tmp}", OUTPUT_INFO) + progress = ProgressLoader( + download_url=url, + path_to_file=savepath_tmp, + downloading_text=f"Downloading {name}: " + "{}", + label_downloading_text=f"Starting download for {name}", + download_complete=lambda req, tmp=savepath_tmp, path=exe_path_name, model=name: download_complete( + req, tmp, path, model + ), + download_redirected=lambda req, mname=name: self.katrain.log( + f"Download {mname} redirected {req.resp_headers}", OUTPUT_DEBUG + ), + download_error=lambda req, error, mname=name: self.katrain.log( + f"Download of {mname} failed or cancelled ({error})", OUTPUT_ERROR + ), + ) + progress.start(self.katago_download_progress_box) + downloading = True + if not downloading: + if not self.KATAGOS.get(platform): + self.katago_download_progress_box.add_widget( + Label(text=f"No binaries available for platform {platform}", text_size=(None, dp(50))) + ) + else: + self.katago_download_progress_box.add_widget( + Label(text=i18n._("All binaries downloaded"), font_name=i18n.font_name, text_size=(None, dp(50))) + ) def update_config(self, save_to_file=True): updated = super().update_config(save_to_file=save_to_file) diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo index 6e51bd45..8db5b156 100644 Binary files a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po index 1ccceb44..9d1d6c39 100644 --- a/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/cn/LC_MESSAGES/katrain.po @@ -592,18 +592,38 @@ msgstr "预计棋力" msgid "reanalyze max visits" msgstr "每步棋计算深度" -#. TODO - on move tree editing msgid "Delete Node" -msgstr "Delete Node" +msgstr "删除模式" -#. TODO - theme name msgid "theme:red-green-colourblind" -msgstr "Red-Green Colourblind" +msgstr "红绿色盲友好" -#. TODO - theme name msgid "theme:normal" -msgstr "Default Theme" +msgstr "默认主题" -#. TODO - theme label msgid "theme" -msgstr "Colour Theme" +msgstr "颜色主题" + +msgid "engine:altcommand:hint" +msgstr "使用全命令启动引擎, 例如使用plink连接远程引擎" + +msgid "engine:altcommand" +msgstr "覆盖引擎命令" + +msgid "download katago button" +msgstr "下载KataGo 版本" + +msgid "show point loss as text" +msgstr "在棋子上显示目数损失" + +msgid "katago binaries available" +msgstr "{num} 个exe文件可用" + +msgid "default katago option" +msgstr "检测平台并使用所提供的exe文件" + +msgid "All binaries downloaded" +msgstr "所有可用的exe文件已下载" + +msgid "Engine missing DLL" +msgstr "启动katago失败因缺失dll文件. 请检查运行要求, 或尝试让exe文件自行运行并检查细节. " diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo index 4a1c9dac..49fc661d 100644 Binary files a/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/de/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po index 337431d8..9941e6cd 100644 --- a/katrain/i18n/locales/de/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/de/LC_MESSAGES/katrain.po @@ -651,3 +651,40 @@ msgstr "Default Theme" #. TODO - theme label msgid "theme" msgstr "Colour Theme" + +#. TODO +msgid "engine:altcommand:hint" +msgstr "" +"Full command used to start the engine. All other model options will be " +"ignored." + +#. TODO +msgid "engine:altcommand" +msgstr "Override Engine Command" + +#. TODO - button in general settings for downloading katago executables +msgid "download katago button" +msgstr "Download KataGo versions" + +#. TODO - shown on on the binaries select dropdown +msgid "katago binaries available" +msgstr "{num} available katago versions found" + +#. TODO - shown on on the katago binary select dropdown +msgid "default katago option" +msgstr "Detect platform and use provided OpenCL KataGo binary" + +#. TODO - error message on trying to download models when already done +msgid "All binaries downloaded" +msgstr "All available binaries already downloaded" + +#. TODO +msgid "Engine missing DLL" +msgstr "" +"Failed to start KataGo due to missing DLL. Check the requirements in the " +"KataGo documentation, or try running the binary by itself for details. " + +#. TODO - in addition to colour, show point loss as -0.1 etc on hints/top +#. moves +msgid "show point loss as text" +msgstr "Show point loss on top moves" diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo index 35348fc6..2da0389c 100644 Binary files a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po index ebcfb7c8..2e84d252 100644 --- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po @@ -26,7 +26,7 @@ msgid "menu:clocksettings" msgstr "Timer Settings" msgid "menu:teachsettings" -msgstr "Teaching Game Settings" +msgstr "Teaching/Analysis Settings" msgid "menu:aisettings" msgstr "AI Settings" @@ -366,6 +366,10 @@ msgstr "" "Show dots/SGF comments\n" " for AI players" +#. in addition to colour, show point loss as -0.1 etc on hints/top moves +msgid "show point loss as text" +msgstr "Show point loss on top moves" + #. removed as an option / can ignore msgid "lock ai when playing" msgstr "" @@ -411,6 +415,14 @@ msgstr "Path to KataGo model file" msgid "engine:config" msgstr "Path to KataGo config file" +msgid "engine:altcommand" +msgstr "Override Engine Command" + +msgid "engine:altcommand:hint" +msgstr "" +"Full command used to start the engine. All other model options will be " +"ignored." + msgid "engine:max_visits" msgstr "Maximum number of visits in analysis" @@ -502,6 +514,11 @@ msgstr "" "Engine died unexpectedly without sending output, possibly due to out of " "memory: {error}" +msgid "Engine missing DLL" +msgstr "" +"Failed to start KataGo due to missing DLL. Check the requirements in the " +"KataGo documentation, or try running the binary by itself for details. " + #. AI names, help etc msgid "strength:kyu" msgstr "k" @@ -628,14 +645,30 @@ msgstr "Estimated Strength" msgid "download models button" msgstr "Download Models" +#. button in general settings for downloading katago executables +msgid "download katago button" +msgstr "Download KataGo versions" + #. shown on on the model select dropdown msgid "models available" msgstr "{num} available model(s) found" +#. shown on on the katago binary select dropdown +msgid "default katago option" +msgstr "Detect platform and use provided OpenCL KataGo binary" + +#. shown on on the binaries select dropdown +msgid "katago binaries available" +msgstr "{num} available katago versions found" + #. error message on trying to download models when already done msgid "All models downloaded" msgstr "All available models already downloaded" +#. error message on trying to download models when already done +msgid "All binaries downloaded" +msgstr "All available binaries already downloaded" + #. label in little popup for analyzing entire game msgid "reanalyze max visits" msgstr "Number of visits per move" diff --git a/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo index df670533..06f7b0ec 100644 Binary files a/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/es/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/es/LC_MESSAGES/katrain.po b/katrain/i18n/locales/es/LC_MESSAGES/katrain.po index f2c5e75a..60d31528 100644 --- a/katrain/i18n/locales/es/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/es/LC_MESSAGES/katrain.po @@ -647,3 +647,40 @@ msgstr "Default Theme" #. TODO - theme label msgid "theme" msgstr "Colour Theme" + +#. TODO +msgid "engine:altcommand:hint" +msgstr "" +"Full command used to start the engine, for e.g. using plink to connect to a " +"remote engine. All other model options will be ignored." + +#. TODO +msgid "engine:altcommand" +msgstr "Override Engine Command" + +#. TODO - button in general settings for downloading katago executables +msgid "download katago button" +msgstr "Download KataGo versions" + +#. TODO - shown on on the binaries select dropdown +msgid "katago binaries available" +msgstr "{num} available katago versions found" + +#. TODO - shown on on the katago binary select dropdown +msgid "default katago option" +msgstr "Detect platform and use provided OpenCL KataGo binary" + +#. TODO - error message on trying to download models when already done +msgid "All binaries downloaded" +msgstr "All available binaries already downloaded" + +#. TODO +msgid "Engine missing DLL" +msgstr "" +"Failed to start KataGo due to missing DLL. Check the requirements, or try " +"running the binary by itself for details. " + +#. TODO - in addition to colour, show point loss as -0.1 etc on hints/top +#. moves +msgid "show point loss as text" +msgstr "Show point loss on top moves" diff --git a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo index f8bba30f..53682e9e 100644 Binary files a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po index 8e9f2e07..bc7fb231 100644 --- a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po @@ -29,7 +29,7 @@ msgid "menu:teachsettings" msgstr "Champ d'étude" msgid "menu:aisettings" -msgstr "Joueurs Artificiels" +msgstr "Joueurs artificiels" msgid "menu:lang" msgstr "Langue" @@ -321,7 +321,7 @@ msgstr "Commencer la partie" # teacher settings from here msgid "teacher settings" -msgstr "Champ d’étude" +msgstr "Champ d'étude" msgid "point loss threshold" msgstr "Pertes plus larges que" @@ -339,14 +339,10 @@ msgid "save dots" msgstr "Diagnostics sauvegardés" msgid "show last n dots" -msgstr "" -"Marquer les \n" -"derniers coups" +msgstr "Dernier(s) coup(s) à marquer :" msgid "show ai dots" -msgstr "" -"Marquer/commenter \n" -"les coups joués par l’IA" +msgstr "Étudier les coups du joueur artificiel" msgid "lock ai when playing" msgstr "" @@ -673,18 +669,45 @@ msgstr "" "Tout à droite, un PDA de 3 (B+3) supposera que Noir est bien plus fort que Blanc. \n" "Cocher l'option 'automatic' adaptera la valeur PDA au handicap utilisé." -#. TODO - on move tree editing msgid "Delete Node" -msgstr "Delete Node" +msgstr "Supprimer le nœud" -#. TODO - theme name msgid "theme:red-green-colourblind" -msgstr "Red-Green Colourblind" +msgstr "Daltonisme rouge-vert" -#. TODO - theme name msgid "theme:normal" -msgstr "Default Theme" +msgstr "Par défaut" -#. TODO - theme label msgid "theme" -msgstr "Colour Theme" +msgstr "Palette de couleurs" + +msgid "engine:altcommand:hint" +msgstr "" +"Commande complète exécutée par le moteur de jeu, outrepassant les " +"réseaux/fichiers sélectionnés plus haut." + +msgid "engine:altcommand" +msgstr "Redéfinir la commande" + +msgid "download katago button" +msgstr "Télécharger des exécutables" + +msgid "katago binaries available" +msgstr "{num} exécutable(s) trouvé(s)" + +msgid "default katago option" +msgstr "" +"Utilisation automatique de l'exécutable opencl approprié au système " +"d'exploitation" + +msgid "All binaries downloaded" +msgstr "Pas de nouveaux exécutables disponibles" + +msgid "Engine missing DLL" +msgstr "" +"Impossible de démarrer KataGo à cause d'un DLL manquant. Veuillez répondre " +"aux conditions requises, ou bien essayez l'exécutable seul pour plus de " +"détails." + +msgid "show point loss as text" +msgstr "Indiquer les points perdus" diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo index ae85ba01..7785ec14 100644 Binary files a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po index 51f74a16..81f5789d 100644 --- a/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/jp/LC_MESSAGES/katrain.po @@ -26,7 +26,7 @@ msgid "menu:clocksettings" msgstr "時間設定" msgid "menu:teachsettings" -msgstr "指導対局設定" +msgstr "指導・分析設定" msgid "menu:aisettings" msgstr "AI設定" @@ -392,10 +392,10 @@ msgid "config file path" msgstr "全オプションの保存先:" msgid "engine:katago" -msgstr "KataGo本体(実行ファイル)のフルパス" +msgstr "KataGo実行ファイル (フルパス)" msgid "engine:katago:hint" -msgstr "内蔵エンジンを使うなら空のまま" +msgstr "内蔵KataGoを使うなら空のまま" msgid "engine:model" msgstr "KataGoモデルファイルの場所" @@ -404,10 +404,10 @@ msgid "engine:config" msgstr "KataGo設定ファイルの場所" msgid "engine:max_visits" -msgstr "分析時の最大読み手数" +msgstr "分析時の最大探索手数" msgid "engine:fast_visits" -msgstr "簡易分析時の最大読み手数" +msgstr "簡易分析時の最大探索手数" msgid "engine:max_time" msgstr "分析の最大時間" @@ -502,7 +502,7 @@ msgstr "KataGo" msgid "aihelp:default" msgstr "" -"手加減なしのKataGo AI. 強さは, 一般設定のエンジンの読み手数とモデル, およびエンジンの設定ファイルによります. " +"手加減なしのKataGo AI. 強さは, 一般設定のエンジンの探索手数とモデル, およびエンジンの設定ファイルによります. " "オプション設定はありません." #. ai which handles handicap games better @@ -526,7 +526,7 @@ msgstr "損も混ぜて" msgid "aihelp:scoreloss" msgstr "" -"損する目数に応じた確率でランダムに手を選択します(損が大きいほど低確率). 読み手数の設定値を大きくするほど多彩で弱い打ち方をするでしょう." +"損する目数に応じた確率でランダムに手を選択します(損が大きいほど低確率). 探索手数の設定値を大きくするほど多彩で弱い打ち方をするでしょう." msgid "ai:policy" msgstr "第一感" @@ -605,11 +605,11 @@ msgstr "推定段級位" #. button in general settings for downloading models msgid "download models button" -msgstr "モデルをダウンロード" +msgstr "追加モデルをダウンロード" #. shown on on the model select dropdown msgid "models available" -msgstr "利用できるモデルが {num} 個みつかりました" +msgstr "入手済モデルの一覧({num}個みつかりました)" #. error message on trying to download models when already done msgid "All models downloaded" @@ -617,20 +617,52 @@ msgstr "利用できるモデルはすべてダウンロード済です" #. label in little popup for analyzing entire game msgid "reanalyze max visits" -msgstr "着手毎の読み手数" +msgstr "着手毎の探索手数" -#. TODO - on move tree editing +#. on move tree editing msgid "Delete Node" msgstr "この手以降を削除" -#. TODO - theme name +#. theme name msgid "theme:red-green-colourblind" msgstr "赤緑色弱" -#. TODO - theme name +#. theme name msgid "theme:normal" msgstr "デフォルト" -#. TODO - theme label +#. theme label msgid "theme" msgstr "カラーテーマ" + +msgid "engine:altcommand:hint" +msgstr "エンジン起動コマンド全体 (plinkでリモートエンジンに接続, 等). 他のモデルオプションはすべて無視されます." + +msgid "engine:altcommand" +msgstr "エンジンコマンドの上書き" + +#. button in general settings for downloading katago executables +msgid "download katago button" +msgstr "別版KataGoをダウンロード" + +#. shown on on the binaries select dropdown +msgid "katago binaries available" +msgstr "入手済KataGo実行ファイルの一覧({num}個みつかりました)" + +#. shown on on the katago binary select dropdown +msgid "default katago option" +msgstr "内蔵KataGo" + +#. error message on trying to download models when already done +msgid "All binaries downloaded" +msgstr "KataGo実行ファイルはすべてダウンロード済です" + +msgid "Engine missing DLL" +msgstr "" +"KataGoの起動に失敗しました. DLLがみつかりません. 必要なものをKataGoの説明書で確認するか, " +"KataGo実行ファイル自体を直接実行して詳細を調べてください." + +#. in addition to colour, show point loss as -0.1 etc on hints/top +#. moves +msgid "show point loss as text" +msgstr "損失目数を候補手上に表示" diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo index fb5e7390..1891a074 100644 Binary files a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po index f4429583..f88a620c 100644 --- a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po @@ -27,7 +27,7 @@ msgid "menu:clocksettings" msgstr "시간 설정" msgid "menu:teachsettings" -msgstr "지도대국 설정" +msgstr "분석/지도대국 설정" msgid "menu:aisettings" msgstr "인공지능 설정" @@ -608,18 +608,39 @@ msgstr "추정 기력" msgid "reanalyze max visits" msgstr "한 수당 visit 수" -#. TODO - on move tree editing msgid "Delete Node" -msgstr "Delete Node" +msgstr "노드 지우기" -#. TODO - theme name msgid "theme:red-green-colourblind" -msgstr "Red-Green Colourblind" +msgstr "적록색약" -#. TODO - theme name msgid "theme:normal" -msgstr "Default Theme" +msgstr "기본 테마" -#. TODO - theme label msgid "theme" -msgstr "Colour Theme" +msgstr "색 테마" + +msgid "engine:altcommand:hint" +msgstr "엔진을 시작하기 위한 명령어입니다. 다른 설정은 무시합니다." + +msgid "engine:altcommand" +msgstr "엔진 명령어 덮어씌우기" + +msgid "download katago button" +msgstr "KataGo 내려받기" + +msgid "katago binaries available" +msgstr "{num}가지의 실행 파일을 받을 수 있습니다." + +msgid "default katago option" +msgstr "제공되는 KataGo 실행 파일 사용" + +msgid "All binaries downloaded" +msgstr "이미 사용할 수 있는 모든 실행 파일을 내려받았습니다." + +msgid "Engine missing DLL" +msgstr "" +"없는 DLL 파일이 있어 KataGo가 실행되지 않습니다. 요구사항을 점검하시거나, 실행 파일을 따로 실행해 세부사항을 알아보십시오." + +msgid "show point loss as text" +msgstr "돌 위에 집 손해 표시하기" diff --git a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo index 4c3def2c..34585570 100644 Binary files a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.mo differ diff --git a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po index 04150441..d7ceda8b 100644 --- a/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po +++ b/katrain/i18n/locales/ru/LC_MESSAGES/katrain.po @@ -633,18 +633,42 @@ msgstr "Оценка силы" msgid "reanalyze max visits" msgstr "Количество посещений на ход" -#. TODO - on move tree editing msgid "Delete Node" -msgstr "Delete Node" +msgstr "Удалить ход" -#. TODO - theme name msgid "theme:red-green-colourblind" -msgstr "Red-Green Colourblind" +msgstr "Режим красно-зелёной слепоты" -#. TODO - theme name msgid "theme:normal" -msgstr "Default Theme" +msgstr "Стандартная тема" -#. TODO - theme label msgid "theme" -msgstr "Colour Theme" +msgstr "Цветовая тема" + +msgid "engine:altcommand:hint" +msgstr "" +"Полная команда использована для запуска движка. Все остальные настройки " +"игнорированы." + +msgid "engine:altcommand" +msgstr "Переопределить команду движка" + +msgid "download katago button" +msgstr "Скачать бинарные файлы" + +msgid "katago binaries available" +msgstr "{num} доступных бинарных файлов найдено" + +msgid "default katago option" +msgstr "Определить платформу и использовать соответствующий бинарный файл" + +msgid "All binaries downloaded" +msgstr "Все доступные бинарные файлы уже загружены" + +msgid "Engine missing DLL" +msgstr "" +"Не удалось запустить KataGo из-за отсутствующих DLL. Проверьте требования " +"или запустите бинарный файл сам по себе для получения подробностей." + +msgid "show point loss as text" +msgstr "Показывать потерянные очки текстом" diff --git a/katrain/img/board.png b/katrain/img/board.png index fb4bfd25..7dfea11e 100644 Binary files a/katrain/img/board.png and b/katrain/img/board.png differ diff --git a/katrain/popups.kv b/katrain/popups.kv index da94c310..5522888b 100644 --- a/katrain/popups.kv +++ b/katrain/popups.kv @@ -80,23 +80,45 @@ : configfile: configfile model_path: model_path + katago_path: katago_path model_files: model_files + katago_files: katago_files download_progress_box: download_progress_box + katago_download_progress_box: katago_download_progress_box DescriptionLabel: text: i18n._('katago settings') font_size: DESC_FONT_SIZE * 1.5 GridLayout: cols: 2 - rows: 4 - size_hint: 1,4 + rows: 6 + size_hint: 1,6 spacing: CP_SPACING DescriptionLabel: text: i18n._("engine:katago") size_hint: 0.33, 1 AnchorLayout: LabelledPathInput: + id: katago_path input_property: "engine/katago" hint_text: i18n._("engine:katago:hint") + on_text: root.check_katas() + AnchorLayout: + size_hint: 0.33, 1 + AutoSizedRoundedRectangleButton: + text: i18n._("download katago button") + on_press: root.download_katas() + size_hint_y: 0.7 + AnchorLayout: + Spinner: + id: katago_files + text: '' + on_text: + if self.text and self.text == self.values[1]: katago_path.text = '' + elif self.text and self.text != self.values[0]: katago_path.text = args[1] + size_hint_y: 0.7 + sync_height_frac: 1.0 + -font_size: self.height * 0.5 + -background_color: [*[c*255/88 for c in BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture DescriptionLabel: text: i18n._("engine:config") size_hint: 0.33, 1 @@ -126,6 +148,13 @@ sync_height_frac: 1.0 -font_size: self.height * 0.5 -background_color: [*[c*255/88 for c in BOX_BACKGROUND_COLOR[:3]], 1] # compensate for texture + DescriptionLabel: + text: i18n._("engine:altcommand") + size_hint: 0.33, 1 + AnchorLayout: + LabelledPathInput: + input_property: "engine/altcommand" + hint_text: i18n._("engine:altcommand:hint") BoxLayout: size_hint: 1,1 orientation: 'horizontal' @@ -198,11 +227,15 @@ hint_text: i18n._("engine:wide_root_noise:hint") MDBoxLayout: orientation: 'horizontal' - size_hint: 1,1.5 + size_hint: 1,2 MDBoxLayout: - size_hint_x: 4 if self.children else 0.0001 + size_hint_x: 3.5 if self.children else 0.0001 orientation: 'vertical' id: download_progress_box + MDBoxLayout: + size_hint_x: 3.5 if self.children else 0.0001 + orientation: 'vertical' + id: katago_download_progress_box AnchorLayout: AutoSizedRoundedRectangleButton: padding_x: 15 @@ -235,13 +268,13 @@ cols: 2 rows: 4 padding: 4 - size_hint: 0.8, 1 + size_hint: 0.9, 1 DescriptionLabel: font_size: DESC_FONT_SIZE * 0.8 text: i18n._("theme") AnchorLayout: LabelledSpinner: - size_hint: 0.8,0.8 + size_hint: 0.95,0.8 input_property: 'trainer/theme' font_size: DESC_FONT_SIZE * 0.8 id: themes_spinner @@ -252,6 +285,12 @@ LabelledIntInput: size_hint_x: 0.15 input_property: "trainer/eval_off_show_last" + DescriptionLabel: + font_size: DESC_FONT_SIZE * 0.8 + text: i18n._("show point loss as text") + AnchorLayout: + LabelledCheckBox: + input_property: "trainer/text_point_loss" DescriptionLabel: font_size: DESC_FONT_SIZE * 0.8 text: i18n._("show ai dots")