nearly ready!

This commit is contained in:
Sander Land committed 2020-05-30 19:09:35 +02:00
1 parent 48f6166d48
commit 42b1df2015
18 files changed
+63 -786

No files matched your search

+12 -32
View File
@@ -1,10 +1,10 @@
# KaTrain v1.0.6 # KaTrain v1.1
[![Latest Release](https://img.shields.io/github/release/sanderland/katrain?label=download)](https://github.com/sanderland/katrain/releases) [![Latest Release](https://img.shields.io/github/release/sanderland/katrain?label=download)](https://github.com/sanderland/katrain/releases)
[![Latest version on PyPI](https://img.shields.io/pypi/v/katrain.svg)](https://pypi.org/project/katrain) [![Latest version on PyPI](https://img.shields.io/pypi/v/katrain.svg)](https://pypi.org/project/katrain)
![License:MIT](https://img.shields.io/pypi/l/katrain) ![License:MIT](https://img.shields.io/pypi/l/katrain)
![Build Status](https://github.com/sanderland/katrain/workflows/release/badge.svg) ![Build Status](https://github.com/sanderland/katrain/workflows/release/badge.svg)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/katrain.svg)](#Installation) ![GitHub Downloads](https://img.shields.io/github/downloads/sanderland/katrain/total?color=%23336699&label=github%20downloads)
[![Code style: Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI Downloads](https://pepy.tech/badge/katrain)](https://pepy.tech/project/katrain)
[![Discord](https://img.shields.io/discord/417022162348802048?logo=discord)](https://discord.com/channels/417022162348802048/629446365688365067) [![Discord](https://img.shields.io/discord/417022162348802048?logo=discord)](https://discord.com/channels/417022162348802048/629446365688365067)
KaTrain is a tool for analyzing and playing go with AI feedback from KataGo. KaTrain is a tool for analyzing and playing go with AI feedback from KataGo.
@@ -24,19 +24,11 @@ but has since grown to include a wide range of features, including:
| ------------- | ------------- | | ------------- | ------------- |
| ![screenshot](katrain/img/anim_analyze.gif) | ![screenshot](katrain/img/anim_teach.gif) | | ![screenshot](katrain/img/anim_analyze.gif) | ![screenshot](katrain/img/anim_teach.gif) |
## Quickstart
* You can right-click most button or checkbox labels to get a tooltip with help.
* To analyze a game, load it using the button in the bottom right, or press `ctrl-L`
* To play against AI, pick an AI from the dropdown and either 'human' or 'teach' for yourself and start playing.
* For different board sizes, use the button with the little goban in the bottom right for a new game.
# Documentation # Documentation
## Installation ## Installation
* See the [releases tab](https://github.com/sanderland/katrain/releases) for pre-built installers for windows. * See the [releases tab](https://github.com/sanderland/katrain/releases) for pre-built installers for windows.
* Alternatively use `pip3 install -U katrain` to install the latest version from PyPI on any OS. * Alternatively use `pip3 install -U katrain` to install the latest version from PyPI on any 64-bit OS.
* Note that on MacOS you will need to set up KataGo using brew, as described [here](INSTALL.md). * Note that on MacOS you will need to set up KataGo using brew, as described [here](INSTALL.md).
* See [here](INSTALL.md#MacPrereq) for detailed instructions for running from source files on Window, Linux and MacOS, * See [here](INSTALL.md#MacPrereq) for detailed instructions for running from source files on Window, Linux and MacOS,
as well as setting up KataGo to use multiple GPUs. as well as setting up KataGo to use multiple GPUs.
@@ -44,37 +36,27 @@ but has since grown to include a wide range of features, including:
## Manual ## Manual
### Play ### Play
* Select the players in the main menu, or under 'New Game'.
* In a teaching game, KaTrain will analyze your moves and automatically undo those that are sufficiently bad.
Under the 'play' tab you can select who is playing black and white. #### Instant feedback while playing.
* Human is simple play with potential feedback, but without auto-undo. The dots on the move indicate how many points were lost by that move.
* Teach will give you instant feedback, and auto-undo bad moves to give you a second chance.
* Settings for this mode can be found under 'Configure Teacher'
* AI will activate the AI in the dropdown menu next to the buttons.
* Settings for all AIs can be found under 'Configure AIs'
If you do not want to see 'Points lost' or other feedback for your moves,
set 'show last n dots' to 0 under 'Configure Teacher', and click on the words 'Points lost' to hide its value.
#### What are all these coloured dots?
The dots indicate how many points were lost by that move.
* The colour indicates the size of the mistake according to KataGo * The colour indicates the size of the mistake according to KataGo
* The size indicates if the mistake was actually punished. Going from fully punished at maximal size, * The size indicates if the mistake was actually punished. Going from fully punished at maximal size,
to no actual effect on the score at minimal size. to no actual effect on the score at minimal size.
In short, if you are a weaker player you should mostly on large dots that are red or purple, In short, if you are a weaker player you should mostly on large dots that are red or purple,
while stronger players can pay more attention to smaller mistakes. If you want to hide some colours, you while stronger players can pay more attention to smaller mistakes. If you want to hide some colours
can do so under 'Configure Teacher'. on the board or not output details for them in SGFs,you can do so under 'Configure Teacher'.
#### AIs #### AIs
Available AIs, with strength indicating an estimate for the default settings based on their current OGS rankings, are: Available AIs, with strength indicating an estimate for the default settings based on their current OGS rankings, are:
* **[9p+]** **Default** is full KataGo, above professional level. * **[9p+]** **KataGo** is full KataGo, above professional level.
* **(RECOMMENDED)** **[~5k]** **ScoreLoss** is KataGo making moves with probability `~ e^(-strength * points lost)`, playing a varied style with small mistakes. * <font color="#336699">**[~5k]** **ScoreLoss**</font> is KataGo making moves with probability `~ e^(-strength * points lost)`, playing a varied style with small mistakes.
* **Balance** is KataGo occasionally making weaker moves, attempting to win by ~2 points. It can still win by more if you make too many mistakes.
* **Jigo** is KataGo aggressively making weaker moves, attempting to win by 0.5 points. * **Jigo** is KataGo aggressively making weaker moves, attempting to win by 0.5 points.
* **[~4d]** **Policy** uses the top move from the policy network (it's 'shape sense' without reading), should be around high dan level depending on the model used. There is a setting to increase variety in the opening, but otherwise it plays deterministically. * **[~4d]** **Policy** uses the top move from the policy network (it's 'shape sense' without reading), should be around high dan level depending on the model used. There is a setting to increase variety in the opening, but otherwise it plays deterministically.
* **(RECOMMENDED)** **[~3k]**: **P:Weighted** picks a random move weighted by the policy, * **(RECOMMENDED)** **[~3k]**: **P:Weighted** picks a random move weighted by the policy,
@@ -175,5 +157,3 @@ In addition to shortcuts mentioned above, there are:
* You can also contact me on [discord](https://discord.gg/AjTPFpN) (Sander#3278), [KakaoTalk](https://open.kakao.com/o/gTsMJCac) or [Reddit](http://reddit.com/u/sanderbaduk) to give feedback, or simply show your appreciation. * You can also contact me on [discord](https://discord.gg/AjTPFpN) (Sander#3278), [KakaoTalk](https://open.kakao.com/o/gTsMJCac) or [Reddit](http://reddit.com/u/sanderbaduk) to give feedback, or simply show your appreciation.
* Some people have also asked me how to donate. Something go-related such as a book or teaching time is highly appreciated. * Some people have also asked me how to donate. Something go-related such as a book or teaching time is highly appreciated.
![GitHub Downloads](https://img.shields.io/github/downloads/sanderland/katrain/total?color=%23336699&label=github%20downloads)
[![PyPI Downloads](https://pepy.tech/badge/katrain)](https://pepy.tech/project/katrain)
+8
View File
@@ -9,6 +9,7 @@ locales = set(os.listdir(localedir))
print("locales found:", locales) print("locales found:", locales)
strings_to_langs = defaultdict(dict) strings_to_langs = defaultdict(dict)
strings_to_keys = defaultdict(dict)
lang_to_strings = defaultdict(set) lang_to_strings = defaultdict(set)
DEFAULT_LANG = "en" DEFAULT_LANG = "en"
@@ -27,12 +28,19 @@ for lang in locales:
num_todo[lang] += 1 num_todo[lang] += 1
else: else:
strings_to_langs[entry.msgid][lang] = entry.msgstr strings_to_langs[entry.msgid][lang] = entry.msgstr
strings_to_keys[entry.msgid][lang] = set(re.findall("{.*?}",entry.msgstr))
lang_to_strings[lang].add(entry.msgid) lang_to_strings[lang].add(entry.msgid)
if num_todo[lang]: if num_todo[lang]:
print(f"{lang} has {num_todo[lang]} TODO entries") print(f"{lang} has {num_todo[lang]} TODO entries")
for lang in locales: for lang in locales:
if lang != DEFAULT_LANG:
for msgid in lang_to_strings[lang]:
if DEFAULT_LANG in strings_to_keys[msgid] and strings_to_keys[msgid][lang] != strings_to_keys[msgid][DEFAULT_LANG]:
print(f"{msgid} has inconstent formatting keys for {lang}: ",strings_to_keys[msgid][lang],'is different from default', strings_to_keys[msgid][DEFAULT_LANG])
errors=True
for msgid in strings_to_langs.keys() - lang_to_strings[lang]: for msgid in strings_to_langs.keys() - lang_to_strings[lang]:
if lang == DEFAULT_LANG: if lang == DEFAULT_LANG:
print("Message id", msgid, "found as ", strings_to_langs[msgid], "but missing in default", DEFAULT_LANG) print("Message id", msgid, "found as ", strings_to_langs[msgid], "but missing in default", DEFAULT_LANG)
+7 -13
View File
@@ -265,12 +265,6 @@ class KaTrainGui(Screen, KaTrainBase):
self.fileselect_popup.open() self.fileselect_popup.open()
def _do_output_sgf(self): def _do_output_sgf(self):
for pl in Move.PLAYERS:
if not self.game.root.get_property(f"P{pl}"):
_, model_file = os.path.split(self.engine.config["model"])
self.game.root.set_property(
f"P{pl}", f"AI {self.controls.ai_mode(pl)} (KataGo { os.path.splitext(model_file)[0]})" if "ai" in self.controls.player_mode(pl) else "Player"
)
msg = self.game.write_sgf(self.config("general/sgf_save")) msg = self.game.write_sgf(self.config("general/sgf_save"))
self.log(msg, OUTPUT_INFO) self.log(msg, OUTPUT_INFO)
self.controls.set_status(msg) self.controls.set_status(msg)
@@ -330,13 +324,7 @@ class KaTrainGui(Screen, KaTrainBase):
first_child.dismiss() first_child.dismiss()
shortcuts = self.shortcuts shortcuts = self.shortcuts
if keycode[1] in shortcuts.keys(): if keycode[1] == "tab":
shortcut = shortcuts[keycode[1]]
if isinstance(shortcut, Widget):
shortcut.trigger_action(duration=0)
else:
self(*shortcut)
elif keycode[1] == "tab":
self.play_mode.switch_mode() self.play_mode.switch_mode()
elif keycode[1] == "shift": elif keycode[1] == "shift":
self.nav_drawer.set_state("toggle") self.nav_drawer.set_state("toggle")
@@ -361,6 +349,12 @@ class KaTrainGui(Screen, KaTrainBase):
self.controls.set_status(i18n._("Copied SGF to clipboard.")) self.controls.set_status(i18n._("Copied SGF to clipboard."))
elif keycode[1] == "v" and "ctrl" in modifiers: elif keycode[1] == "v" and "ctrl" in modifiers:
self.load_sgf_from_clipboard() self.load_sgf_from_clipboard()
elif keycode[1] in shortcuts.keys() and "ctrl" not in modifiers:
shortcut = shortcuts[keycode[1]]
if isinstance(shortcut, Widget):
shortcut.trigger_action(duration=0)
else:
self(*shortcut)
return True return True
+1 -1
View File
@@ -64,7 +64,7 @@
true true
], ],
"eval_off_show_last": 3, "eval_off_show_last": 3,
"eval_show_ai": true, "eval_show_ai": false,
"lock_ai": true "lock_ai": true
}, },
"ai": { "ai": {
+6 -31
View File
@@ -5,7 +5,7 @@ import time
from typing import Dict, List, Tuple from typing import Dict, List, Tuple
from katrain.core.utils import var_to_grid from katrain.core.utils import var_to_grid
from katrain.core.constants import OUTPUT_INFO, OUTPUT_DEBUG, AI_STRATEGIES_POLICY, AI_POLICY, AI_WEIGHTED from katrain.core.constants import OUTPUT_INFO, OUTPUT_DEBUG, AI_STRATEGIES_POLICY, AI_POLICY, AI_WEIGHTED, AI_STRATEGIES_PICK, AI_JIGO, AI_SCORELOSS, AI_DEFAULT
from katrain.core.engine import EngineDiedException from katrain.core.engine import EngineDiedException
from katrain.core.game import Game, GameNode, Move from katrain.core.game import Game, GameNode, Move
@@ -44,7 +44,7 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
top_policy_move = policy_moves[0][1] top_policy_move = policy_moves[0][1]
ai_thoughts += f"Using policy based strategy, base top 5 moves are {fmt_moves(policy_moves[:5])}. " ai_thoughts += f"Using policy based strategy, base top 5 moves are {fmt_moves(policy_moves[:5])}. "
if ai_mode == AI_POLICY and cn.depth <= ai_settings["opening_moves"]: if ai_mode == AI_POLICY and cn.depth <= ai_settings["opening_moves"]:
ai_mode = "p:weighted" ai_mode = AI_WEIGHTED
ai_thoughts += f"Switching to weighted strategy in the opening {int(ai_settings['opening_moves'] * (game.board_size[0]*game.board_size[1]))} moves. " ai_thoughts += f"Switching to weighted strategy in the opening {int(ai_settings['opening_moves'] * (game.board_size[0]*game.board_size[1]))} moves. "
ai_settings = {"pick_override": 0.9, "weaken_fac": 1, "lower_bound": 0.02} ai_settings = {"pick_override": 0.9, "weaken_fac": 1, "lower_bound": 0.02}
if top_5_pass: if top_5_pass:
@@ -77,21 +77,7 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
ai_thoughts += f"Playing policy-weighted random move {aimove.gtp()} ({policy_value:.1%})" + ( ai_thoughts += f"Playing policy-weighted random move {aimove.gtp()} ({policy_value:.1%})" + (
" because no other moves were found." if not top else f" because strategy is weighted (lower bound={lower_bound:.2%}, num moves > lb={len(weighted_coords)})." " because no other moves were found." if not top else f" because strategy is weighted (lower bound={lower_bound:.2%}, num moves > lb={len(weighted_coords)})."
) )
elif "noise" in ai_mode: # DEPRECATED elif ai_mode in AI_STRATEGIES_PICK:
noise_str = ai_settings["noise_strength"]
lower_bound = max(0, ai_settings["lower_bound"])
selected_policy_moves = [(pol, mv) for pol, mv in policy_moves if not mv.is_pass if pol > lower_bound]
d_noise = dirichlet_noise(len(selected_policy_moves))
noisy_policy_moves = [(((1 - noise_str) * pol + noise_str * noise), mv) for ((pol, mv), noise) in zip(selected_policy_moves, d_noise)]
new_top = heapq.nlargest(5, noisy_policy_moves)
ai_thoughts += f"Noisy policy strategy (strength={noise_str:.2f}) generated 5 moves {fmt_moves(new_top)} "
aimove = new_top[0][1]
if new_top[0][0] < pass_policy:
ai_thoughts += f", but found pass ({pass_policy:.2%} to be higher rated than {aimove.gtp()} ({new_top[0][0]:.2%}) so will play top policy move instead."
aimove = top_policy_move
else:
ai_thoughts += f" so picked {aimove.gtp()} ({policy_grid[aimove.coords[1]][aimove.coords[0]]:.2%})."
elif "p:" in ai_mode:
legal_policy_moves = [(pol, mv) for pol, mv in policy_moves if not mv.is_pass if pol > 0] legal_policy_moves = [(pol, mv) for pol, mv in policy_moves if not mv.is_pass if pol > 0]
n_moves = int(ai_settings["pick_frac"] * len(legal_policy_moves) + ai_settings["pick_n"]) n_moves = int(ai_settings["pick_frac"] * len(legal_policy_moves) + ai_settings["pick_n"])
if "influence" in ai_mode or "territory" in ai_mode: if "influence" in ai_mode or "territory" in ai_mode:
@@ -151,30 +137,19 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
aimove = top_cand aimove = top_cand
ai_thoughts += f"Top move is pass, so passing regardless of strategy." ai_thoughts += f"Top move is pass, so passing regardless of strategy."
else: else:
if "balance" in ai_mode: # deprecated if ai_mode == AI_JIGO:
sign = cn.player_sign(cn.next_player)
sel_moves = [ # top move, or anything not too bad, or anything that makes you still ahead
move
for i, move in enumerate(candidate_ai_moves)
if i == 0
or move["visits"] >= ai_settings["min_visits"]
and (move["pointsLost"] < ai_settings["random_loss"] or move["pointsLost"] < ai_settings["max_loss"] and sign * move["scoreLead"] > ai_settings["target_score"])
]
aimove = Move.from_gtp(random.choice(sel_moves)["move"], player=cn.next_player)
ai_thoughts += f"Balance strategy selected moves {sel_moves} based on target score and max points lost, and randomly chose {aimove.gtp()}."
elif "jigo" in ai_mode:
sign = cn.player_sign(cn.next_player) sign = cn.player_sign(cn.next_player)
jigo_move = min(candidate_ai_moves, key=lambda move: abs(sign * move["scoreLead"] - ai_settings["target_score"])) jigo_move = min(candidate_ai_moves, key=lambda move: abs(sign * move["scoreLead"] - ai_settings["target_score"]))
aimove = Move.from_gtp(jigo_move["move"], player=cn.next_player) aimove = Move.from_gtp(jigo_move["move"], player=cn.next_player)
ai_thoughts += f"Jigo strategy found {len(candidate_ai_moves)} candidate moves (best {top_cand.gtp()}) and chose {aimove.gtp()} as closest to 0.5 point win" ai_thoughts += f"Jigo strategy found {len(candidate_ai_moves)} candidate moves (best {top_cand.gtp()}) and chose {aimove.gtp()} as closest to 0.5 point win"
elif "scoreloss" in ai_mode: elif ai_mode == AI_SCORELOSS:
c = ai_settings["strength"] c = ai_settings["strength"]
moves = [(d["pointsLost"], math.exp(min(200, -c * max(0, d["pointsLost"]))), Move.from_gtp(d["move"], player=cn.next_player)) for d in candidate_ai_moves] moves = [(d["pointsLost"], math.exp(min(200, -c * max(0, d["pointsLost"]))), Move.from_gtp(d["move"], player=cn.next_player)) for d in candidate_ai_moves]
topmove = weighted_selection_without_replacement(moves, 1)[0] topmove = weighted_selection_without_replacement(moves, 1)[0]
aimove = topmove[2] aimove = topmove[2]
ai_thoughts += f"ScoreLoss strategy found {len(candidate_ai_moves)} candidate moves (best {top_cand.gtp()}) and chose {aimove.gtp()} (weight {topmove[1]:.3f}, point loss {topmove[0]:.1f}) based on score weights." ai_thoughts += f"ScoreLoss strategy found {len(candidate_ai_moves)} candidate moves (best {top_cand.gtp()}) and chose {aimove.gtp()} (weight {topmove[1]:.3f}, point loss {topmove[0]:.1f}) based on score weights."
else: else:
if "default" not in ai_mode and "katago" not in ai_mode: if ai_mode != AI_DEFAULT:
game.katrain.log(f"Unknown AI mode {ai_mode} or policy missing, using default.", OUTPUT_INFO) game.katrain.log(f"Unknown AI mode {ai_mode} or policy missing, using default.", OUTPUT_INFO)
ai_thoughts += f"Strategy {ai_mode} not found or unexpected fallback." ai_thoughts += f"Strategy {ai_mode} not found or unexpected fallback."
aimove = top_cand aimove = top_cand
+2 -1
View File
@@ -22,7 +22,8 @@ AI_TERRITORY = "ai:p:territory"
AI_CONFIG_DEFAULT = AI_SCORELOSS AI_CONFIG_DEFAULT = AI_SCORELOSS
AI_STRATEGIES_ENGINE = [AI_DEFAULT, AI_SCORELOSS, AI_JIGO] AI_STRATEGIES_ENGINE = [AI_DEFAULT, AI_SCORELOSS, AI_JIGO]
AI_STRATEGIES_POLICY = [AI_WEIGHTED, AI_POLICY, AI_PICK, AI_LOCAL, AI_TENUKI, AI_INFLUENCE, AI_TERRITORY] AI_STRATEGIES_PICK = [AI_PICK, AI_LOCAL, AI_TENUKI, AI_INFLUENCE, AI_TERRITORY]
AI_STRATEGIES_POLICY = [AI_WEIGHTED, AI_POLICY] + AI_STRATEGIES_PICK
AI_STRATEGIES = AI_STRATEGIES_ENGINE + AI_STRATEGIES_POLICY AI_STRATEGIES = AI_STRATEGIES_ENGINE + AI_STRATEGIES_POLICY
AI_STRATEGIES_RECOMMENDED_ORDER = [AI_DEFAULT, AI_SCORELOSS, AI_WEIGHTED, AI_PICK, AI_POLICY, AI_LOCAL, AI_TENUKI, AI_TERRITORY, AI_INFLUENCE, AI_JIGO] AI_STRATEGIES_RECOMMENDED_ORDER = [AI_DEFAULT, AI_SCORELOSS, AI_WEIGHTED, AI_PICK, AI_POLICY, AI_LOCAL, AI_TENUKI, AI_TERRITORY, AI_INFLUENCE, AI_JIGO]
+5 -2
View File
@@ -246,12 +246,15 @@ class Game:
if eval_thresholds is None: if eval_thresholds is None:
eval_thresholds = self.katrain.config("trainer/eval_thresholds") eval_thresholds = self.katrain.config("trainer/eval_thresholds")
player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw) or str(self.katrain.players_info[bw])) for bw in "BW"} def player_name(player_info):
return f"{i18n._(player_info.player_type)} ({i18n._(player_info.player_subtype)})"
player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw) or player_name(self.katrain.players_info[bw])) for bw in "BW"}
game_name = f"katrain_{player_names['B']} vs {player_names['W']} {self.game_id}" 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")) file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf"))
os.makedirs(os.path.dirname(file_name), exist_ok=True) os.makedirs(os.path.dirname(file_name), exist_ok=True)
show_dots_for = {bw: trainer_config.get("eval_show_ai", True) or pl.human for bw, pl in self.players.items()} show_dots_for = {bw: trainer_config.get("eval_show_ai", True) or pl.human for bw, pl in self.katrain.players_info.items()}
sgf = self.root.sgf(save_comments_player=show_dots_for, save_comments_class=save_feedback, eval_thresholds=eval_thresholds) sgf = self.root.sgf(save_comments_player=show_dots_for, save_comments_class=save_feedback, eval_thresholds=eval_thresholds)
with open(file_name, "w") as f: with open(file_name, "w") as f:
f.write(sgf) f.write(sgf)
+2 -2
View File
@@ -125,7 +125,7 @@ class GameNode(SGFNode):
if not self.parent or not single_move: # root if not self.parent or not single_move: # root
return "" return ""
text = f"Move {self.depth}: {single_move.player} {single_move.gtp()}\n" text = f"{i18n._('move')} {self.depth}: {single_move.player} {single_move.gtp()}\n"
if self.analysis_ready: if self.analysis_ready:
score = self.score score = self.score
if sgf: if sgf:
@@ -137,7 +137,7 @@ class GameNode(SGFNode):
if previous_top_move["move"] != single_move.gtp(): if previous_top_move["move"] != single_move.gtp():
points_lost = self.points_lost points_lost = self.points_lost
if sgf and points_lost > 0.5: if sgf and points_lost > 0.5:
text += i18n._("Info:point loss").format(points=points_lost) + "\n" text += i18n._("Info:point loss").format(points_lost=points_lost) + "\n"
text += i18n._("Info:top move").format(top_move=previous_top_move["move"], score=self.format_score(previous_top_move["scoreLead"])) + "\n" text += i18n._("Info:top move").format(top_move=previous_top_move["move"], score=self.format_score(previous_top_move["scoreLead"])) + "\n"
else: else:
text += i18n._("Info:best move") + "\n" text += i18n._("Info:best move") + "\n"
+8 -15
View File
@@ -31,22 +31,18 @@
#:set WINRATE_COLOR GREEN #:set WINRATE_COLOR GREEN
#:set GRAPH_DOT_COLOR [0.85, 0.3, 0.3,1] #:set GRAPH_DOT_COLOR [0.85, 0.3, 0.3,1]
#:set BUTTON_INACTIVE_COLOR LIGHTGREY #:set BUTTON_INACTIVE_COLOR LIGHTGREY
#:set NOTES_FONT_SIZE dp(18) #:set NOTES_FONT_SIZE dp(18)
# for sizing help # for sizing help
<Label>: #<Label>:
canvas.before: # canvas.before:
Color: # Color:
rgba: RED # rgba: RED
Line: # Line:
rectangle: (*self.pos,*self.size) # rectangle: (*self.pos,*self.size)
width: 1 # width: 1
# mixins # mixins
<BackgroundMixin>: <BackgroundMixin>:
@@ -903,7 +899,7 @@
text: i18n._('menu:save') text: i18n._('menu:save')
icon: 'img/flaticon/floppy-disk.png' icon: 'img/flaticon/floppy-disk.png'
shortcut: 'Ctrl-S' shortcut: 'Ctrl-S'
on_action: root.katrain("analyze-sgf-popup") on_action: root.katrain("output-sgf")
MainMenuItem: MainMenuItem:
text: i18n._('menu:load') text: i18n._('menu:load')
icon: 'img/flaticon/folder.png' icon: 'img/flaticon/folder.png'
@@ -937,9 +933,6 @@
LangButton: LangButton:
icon: 'img/flaticon/flag-uk.png' icon: 'img/flaticon/flag-uk.png'
on_press: app.language = 'en' on_press: app.language = 'en'
LangButton:
icon: 'img/flaticon/flag-nl.png'
on_press: app.language = 'nl'
LangButton: LangButton:
icon: 'img/flaticon/flag-ko.png' icon: 'img/flaticon/flag-ko.png'
on_press: app.language = 'ko' on_press: app.language = 'ko'
+1 -1
View File
@@ -236,7 +236,7 @@ class BadukPanWidget(Widget):
for m in katrain.game.stones: for m in katrain.game.stones:
has_stone[m.coords] = m.player has_stone[m.coords] = m.player
show_dots_for = {p: self.trainer_config["eval_show_ai"] or katrain.game.players[p].human for p in Move.PLAYERS} show_dots_for = {p: self.trainer_config["eval_show_ai"] or katrain.players_info[p].human for p in Move.PLAYERS}
show_dots_for_class = self.trainer_config["show_dots"] show_dots_for_class = self.trainer_config["show_dots"]
nodes = katrain.game.current_node.nodes_from_root nodes = katrain.game.current_node.nodes_from_root
realized_points_lost = None realized_points_lost = None
Binary file not shown.
@@ -187,6 +187,10 @@ msgstr "Win rate: {winrate}"
msgid "Info:point loss" msgid "Info:point loss"
msgstr "Estimated point loss: {points_lost:.1f}" msgstr "Estimated point loss: {points_lost:.1f}"
#. as in 'Move 125: B5'
msgid "move"
msgstr "Move"
msgid "Info:top move" msgid "Info:top move"
msgstr "Predicted top move was {top_move} ({score})." msgstr "Predicted top move was {top_move} ({score})."
Binary file not shown.
@@ -512,3 +512,6 @@ msgstr "ㅋㅋYour SGF notes for this position here."
msgid "pass-button-text" msgid "pass-button-text"
msgstr "ㅋㅋPass" msgstr "ㅋㅋPass"
msgid "move"
msgstr "ㅋㅋMove"
Binary file not shown.
@@ -648,3 +648,7 @@ msgstr "Manual"
#. TODO #. TODO
msgid "ai settings" msgid "ai settings"
msgstr "Advanced AI Settings" msgstr "Advanced AI Settings"
#. TODO
msgid "move"
msgstr "Move"
Binary file not shown.
@@ -1,688 +0,0 @@
# KaTrain i18n file
msgid ""
msgstr ""
"Language: Nederlands\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "pass-button-text"
msgstr "Pas"
#. TODO
msgid "tab:info"
msgstr "Info"
#. TODO
msgid "Info:PV"
msgstr "PV: {pv}"
#. TODO
msgid "board-pass"
msgstr "pass"
#. TODO
msgid "closedlabel:scoregraph"
msgstr "Score Graph"
#. TODO
msgid "Starting default Kata failed"
msgstr ""
"Starting KataGo with command '{command}' failed with error {error}. If on "
"MacOS, see the manual on how to use brew to install katago first, and add it"
" to your path or 'engine/katago' setting."
#. TODO
msgid "Failed to load SGF"
msgstr "Failed to load SGF. Parse Error: {error}"
#. TODO
msgid "Info:AI thoughts"
msgstr "AI thought process: {thoughts}"
#. TODO
msgid "tab:winrate"
msgstr "Win Rate"
#. TODO
msgid "Info:undo predicted PV"
msgstr "Predicted follow-up: {pv}"
#. TODO
msgid "tab:notes"
msgstr "Notes"
#. TODO
msgid "SGF start message"
msgstr ""
"Moves marked 'X' indicate the top move according to KataGo, those with a "
"square are moves that lose less than 0.5 points"
#. TODO
msgid "Info:teaching undo"
msgstr "Move was automatically undone in teaching mode."
#. TODO
msgid "Failed to import from clipboard"
msgstr ""
"Failed to import game from clipboard: {error}\n"
"Clipboard contents: {contents}..."
#. TODO
msgid "Info:policy best"
msgstr "Top policy move was {move} ({probability:.1%})."
#. TODO
msgid "Info:policy rank"
msgstr "Move was #{rank} according to policy ({probability:.2%})."
#. TODO
msgid "Analyzing move..."
msgstr "Analyzing move..."
#. TODO
msgid "Copied SGF to clipboard."
msgstr "Copied SGF to clipboard."
#. TODO
msgid "Engine died unexpectedly"
msgstr ""
"Engine died unexpectedly without sending output, possibly due to out of "
"memory: {e}"
#. TODO
msgid "board-game-end"
msgstr ""
"game\n"
"end"
#. TODO
msgid "Starting Kata failed"
msgstr ""
"Starting kata with command '{command}' failed with error {error}. Please "
"make sure the 'katago' value under 'engine' in settings points to the "
"correct KataGo executable."
#. TODO
msgid "closedlabel:movestats"
msgstr "Move Stats"
#. TODO
msgid "Info:top move"
msgstr "Predicted top move was {top_move} ({score})."
#. TODO
msgid "Info:score"
msgstr "Score: {score}"
#. TODO
msgid "Info:point loss"
msgstr "Estimated point loss: {points_lost:.1f}"
#. TODO
msgid "No analysis available"
msgstr "No analysis available"
#. TODO
msgid "tab:score"
msgstr "Score"
#. TODO
msgid "Info:best move"
msgstr "Move was predicted best move"
#. TODO
msgid "tab:points"
msgstr "Point Loss"
#. TODO
msgid "Info:winrate"
msgstr "Win rate: {winrate}"
#. TODO
msgid "closedlabel:info&notes"
msgstr "Move Info & Notes"
#. TODO
msgid "btn:Analysis"
msgstr "Analysis"
#. TODO
msgid "btn:Play"
msgstr "Play"
#. TODO
msgid "stats:winrate"
msgstr "Win Rate"
#. TODO
msgid "stats:pointslost"
msgstr "Points Lost"
#. TODO
msgid "stats:score"
msgstr "Estimated Score"
#. TODO
msgid "stats:pointsgained"
msgstr "Points Gained"
#. TODO
msgid "SGF Notes Hint"
msgstr "Your SGF notes for this position here."
#. TODO
msgid "analysis:territory"
msgstr ""
"Expected\n"
"Territory"
#. TODO
msgid "analysis:topmoves"
msgstr ""
"Top\n"
"Moves"
#. TODO
msgid "analysis:dots"
msgstr ""
"Show\n"
"Dots"
#. TODO
msgid "analysis:nextmoves"
msgstr ""
"Next\n"
"Moves"
#. TODO
msgid "analysis:policy"
msgstr ""
"Policy\n"
"Moves"
#. TODO
msgid "ai-ponder"
msgstr ""
"This simply indicates the Engine status, going from green (idle) to orange "
"(processing queries). It turns red when the engine has crashed or fails to "
"start."
#. TODO
msgid "menu:newgame"
msgstr "New Game"
#. TODO
msgid "menu:load"
msgstr "Load Game"
#. TODO
msgid "menu:save"
msgstr "Save Game"
#. TODO
msgid "menu:lang"
msgstr "Language"
#. TODO
msgid "menu:settings"
msgstr "General Settings"
#. TODO
msgid "menu:playersetup"
msgstr "Player Setup"
#. TODO
msgid "analysis:sweep"
msgstr "Fast analysis of all moves"
#. TODO
msgid "analysis:equalize"
msgstr "Equalize visits of potential moves"
#. TODO
msgid "analysis:aimove"
msgstr "Force AI Move"
#. TODO
msgid "analysis:extra"
msgstr "Deeper analysis"
#. TODO
msgid "undo-button-text"
msgstr "Undo"
#. TODO
msgid "menu:support"
msgstr "Support or Contribute"
#. TODO
msgid "wait-before-equalize"
msgstr "Wait for initial analysis to complete before requesting a refinement."
#. TODO
msgid "game:teaching"
msgstr "Teaching Game"
#. TODO
msgid "aistrategy"
msgstr "AI Strategy"
#. TODO
msgid "game:normal"
msgstr "Normal Game"
#. TODO
msgid "player:human"
msgstr "Mens"
#. TODO
msgid "player:type"
msgstr "Player"
#. TODO
msgid "gametype"
msgstr "Game Type"
#. TODO
msgid "player:ai"
msgstr "AI"
#. TODO
msgid "game:teach"
msgstr "Teaching Game"
#. TODO
msgid "menu:clocksettings"
msgstr "Timer Settings"
#. TODO
msgid "menu:teachsettings"
msgstr "Teaching Game Settings"
#. TODO
msgid "menu:aisettings"
msgstr "AI Settings"
#. TODO
msgid "timer settings"
msgstr "Adjust Timer Settings"
#. TODO
msgid "update timer"
msgstr "Update Timer Settings"
#. TODO
msgid "byoyomi length"
msgstr "Time per Byo-yomi Period"
#. TODO
msgid "byoyomi periods"
msgstr "Number of Periods"
#. TODO
msgid "japanese"
msgstr "Japanese Rules"
#. TODO
msgid "aga"
msgstr "American Go Association Rules"
#. TODO
msgid "new game"
msgstr "Start New Game"
#. TODO
msgid "board size"
msgstr "Board size"
#. TODO
msgid "ruleset"
msgstr "Rules"
#. TODO
msgid "komi"
msgstr "Komi"
#. TODO
msgid "avoids replaying"
msgstr ""
"'avoids replaying\n"
"identical games"
#. TODO
msgid "clear cache"
msgstr "Clear Cache"
#. TODO
msgid "korean"
msgstr "Korean Rules"
#. TODO
msgid "chinese"
msgstr "Chinese Rules"
#. TODO
msgid "non square board hint"
msgstr "Use x:y (e.g. 19:9) to play on a non-square board."
#. TODO
msgid "handicap"
msgstr "Handicap"
#. TODO
msgid "handicap hint"
msgstr "Note that handicaps above 9 are not supported on non-square boards."
#. TODO
msgid "New Game title"
msgstr "Setup New Game"
#. TODO
msgid "sgf written"
msgstr "SGF with analysis written to {file_name}"
#. TODO
msgid "ainame:jigo"
msgstr "KataJigo"
#. TODO
msgid "aihelp:policy"
msgstr ""
"Plays the top move from the policy network, without any reading. Strength is"
" mainly affected by `model` in engine settings. The opening moves setting "
"affects how many moves in the opening are more random."
#. TODO
msgid "ainame:policy"
msgstr "Policy"
#. TODO
msgid "ainame:scoreloss"
msgstr "Score Loss"
#. TODO
msgid "aihelp:default"
msgstr ""
"Full strength KataGo AI. Strength is mainly affected by `max_visits` and "
"`model` in the general settings `engine` section."
#. TODO
msgid "aihelp:jigo"
msgstr ""
"Will try to win by a set amount of points (default 0.5), without further "
"restrictions."
#. TODO
msgid "aihelp:scoreloss"
msgstr ""
"Plays moves that lead to more points lost with lower probability. Likely to "
"play more varied/weaker with higher visits settings."
#. TODO
msgid "ainame:default"
msgstr "KataGo"
#. TODO
msgid "strength:kyu"
msgstr "k"
#. TODO
msgid "strength:dan"
msgstr "d"
#. TODO
msgid "aihelp:p:weighted"
msgstr ""
"Plays moves according to policy probability, with `weaken_fac` influencing "
"how much more likely weaker moves are played. A high negative value plays "
"like the `Policy` AI.`pick_override` determines when top move is chosen "
"without randomness, and `lower_bound` determines the lower bound policy "
"value that is allowed."
#. TODO
msgid "aihelp:p:pick"
msgstr ""
"Picks `pick_n + pick_frac * <number of legal moves>` at random and plays the"
" best one. For `pick_frac=1` plays like the `Policy` AI. Plays top move if "
"policy value is above `pick_override` to avoid obvious mistakes."
#. TODO
msgid "ai:p:influence"
msgstr "Influential Style"
#. TODO
msgid "ai:p:local"
msgstr "Respond Locally"
#. TODO
msgid "aihelp:p:tenuki"
msgstr ""
"Picks `pick_n + pick_frac * <number of legal moves>` weighted away from the "
"last move and plays the best one. Plays top move if policy value is above "
"`pick_override` to avoid obvious mistakes."
#. TODO
msgid "ai:scoreloss"
msgstr "Score Loss"
#. TODO
msgid "aihelp:p:influence"
msgstr ""
"Picks moves biased above the `threshold` line and plays the best "
"one.Increase `line_weight` to penalize moves near the edge more. Stops "
"strategy after the 'endgame' fraction of the board is filled."
#. TODO
msgid "ai:default"
msgstr "KataGo"
#. TODO
msgid "ai:p:tenuki"
msgstr "Tenuki Style"
#. TODO
msgid "ai:p:pick"
msgstr "Blinded Policy"
#. TODO
msgid "ai:p:weighted"
msgstr "Policy Weighted"
#. TODO
msgid "ai:policy"
msgstr "Policy"
#. TODO
msgid "ai:jigo"
msgstr "KataJigo"
#. TODO
msgid "aihelp:p:local"
msgstr ""
"Picks moves biased below the `threshold` line and plays the best "
"one.Increase `line_weight` to penalize moves near the center more. Stops "
"strategy after the 'endgame' fraction of the board is filled."
#. TODO
msgid "aihelp:p:territory"
msgstr ""
"Picks moves biased below the `threshold` line and plays the best "
"one.Increase `line_weight` to penalize moves near the center more. Stops "
"strategy after the 'endgame' fraction of the board is filled."
#. TODO
msgid "ai:p:territory"
msgstr "Respond Locally"
#. TODO
msgid "save dots"
msgstr "Save in SGF"
#. TODO
msgid "num undos"
msgstr "Number of undos"
#. TODO
msgid "teacher settings"
msgstr "Edit Teacher Settings"
#. TODO
msgid "show dots"
msgstr "Show dots"
#. TODO
msgid "point loss threshold"
msgstr "Point loss greater than"
#. TODO
msgid "dot color"
msgstr "Colour (fixed)"
#. TODO
msgid "show ai dots"
msgstr "Show dots/SGF comments for AI players"
#. TODO
msgid "restarting engine"
msgstr "Restarting Engine after Settings Change."
#. TODO
msgid "lock ai when teaching"
msgstr "Disable analysis while in teach mode"
#. TODO
msgid "show last n dots"
msgstr "Show dots for the last <this many> moves"
#. TODO
msgid "update teacher"
msgstr "Update Teaching Game Settings"
#. TODO
msgid "engine:max_visits"
msgstr "Maximum number of visits in analysis"
#. TODO
msgid "general settings"
msgstr "General Settings"
#. TODO
msgid "update settings"
msgstr "Update Settings"
#. TODO
msgid "engine:max_time"
msgstr "Maximum time for analysis"
#. TODO
msgid "engine:fast_visits"
msgstr "Maximum number of visits in fast analysis"
#. TODO
msgid "engine:config"
msgstr "Path to KataGo config file"
#. TODO
msgid "general:sgf_save"
msgstr "Path for saving SGF files"
#. TODO
msgid "general:sgf_load"
msgstr "Path for loading SGF files"
#. TODO
msgid "general:debug_level"
msgstr "Debug level in the console"
#. TODO
msgid "general settings title"
msgstr "General and Engine Settings"
#. TODO
msgid "engine settings"
msgstr "KataGo Engine Settings"
#. TODO
msgid "engine:model"
msgstr "Path to KataGo model file"
#. TODO
msgid "general:anim_pv_time"
msgstr "Time between moves when animating a sequence"
#. TODO
msgid "engine:katago"
msgstr "Path to KataGo executable"
#. TODO
msgid "general:debug_level:hint"
msgstr "Use 0 for little output, 1 for getting details when reporting errors"
#. TODO
msgid "engine:max_time:hint"
msgstr "Time in seconds"
#. TODO
msgid "engine:time:hint"
msgstr "Time in seconds"
#. TODO
msgid "engine:katago:hint"
msgstr "Leave blank to use included executable"
#. TODO
msgid "file not found"
msgstr "Path does not exist"
#. TODO
msgid "engine:wide_root_noise:hint"
msgstr ""
"Use a value of 0.02-0.1 to show more possible moves, at the cost of "
"weakening analysis."
#. TODO
msgid "engine:wide_root_noise"
msgstr "Wide root noise (increases variety of moves considered)"
#. TODO
msgid "lock ai when playing"
msgstr ""
"Disable analysis\n"
" while in play mode"
#. TODO
msgid "update ai settings"
msgstr "Update AI Settings"
#. TODO
msgid "Select AI"
msgstr "Select AI strategy to configure"
#. TODO
msgid "load sgf rewind"
msgstr "Rewind to start"
#. TODO
msgid "load sgf fast analysis"
msgstr "Use fast analysis"
#. TODO
msgid "load sgf title"
msgstr "Load SGF File to Analyze"
#. TODO
msgid "btn:Analyze"
msgstr "Analyze"
#. TODO
msgid "menu:homepage"
msgstr "Homepage"
#. TODO
msgid "menu:manual"
msgstr "Manual"
#. TODO
msgid "ai settings"
msgstr "Advanced AI Settings"