diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 1f37d7a..e1b4b25 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -5,6 +5,7 @@ Many thanks to these additional authors:
Matthew Allred ("Kameone") for design of the v1.1 UI and providing MacOS installation instructions.
"isty2e" for Korean translation.
"Dontbtme" for detailed feedback and early testing of v1.0, and French translation.
+"bale-go" for implementing and calibrating the 'calibrated rank' AI.
Additional thanks to:
"Seventeen" for explanatory youtube videos.
diff --git a/INSTALL.md b/INSTALL.md
index 76046cf..7cc515d 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -2,11 +2,12 @@
# Installation for MacOS users
## Installation pre-requisites
-* Download and install [Python 3.7.5](https://www.python.org/downloads/release/python-375/)
* Install [Homebrew](https://brew.sh) by running the following command in terminal:
* ```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
+* Install Python using [Homebrew](https://brew.sh/) by executing `brew install python3`
+ * Alternatively download and install [Python 3.7.5](https://www.python.org/downloads/release/python-375/)
* Install Katago using [Homebrew](https://brew.sh/) by executing `brew install katago`
* You can also follow instructions [here](https://github.com/lightvector/KataGo) to compile KataGo yourself.
diff --git a/README.md b/README.md
index 1f50bd3..047275b 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-# KaTrain v1.1
+# KaTrain v1.1
[](https://github.com/sanderland/katrain/releases)
[](https://en.wikipedia.org/wiki/MIT_License)

diff --git a/katrain/__main__.py b/katrain/__main__.py
index a7117cb..efd0895 100644
--- a/katrain/__main__.py
+++ b/katrain/__main__.py
@@ -64,7 +64,7 @@ from katrain.core.game import Game, IllegalMoveException, KaTrainSGF
from katrain.core.sgf_parser import Move, ParseError
from katrain.gui.kivyutils import *
from katrain.gui.popups import ConfigPopup, LoadSGFPopup, NewGamePopup, AIPopup
-from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL
+from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL, LIGHTGREY
from katrain.gui.widgets.graph import ScoreGraph
from katrain.gui.widgets.filebrowser import I18NFileBrowser
from katrain.gui.badukpan import AnalysisControls, BadukPanControls, BadukPanWidget
@@ -431,21 +431,28 @@ class KaTrainGui(Screen, KaTrainBase):
class KaTrainApp(MDApp):
gui = ObjectProperty(None)
language = StringProperty(DEFAULT_LANGUAGE)
+
+ def __init__(self):
+ super().__init__()
+# self.theme_cls.selected_color = WHITE
+# self.theme_cls.secondary_text_color = LIGHTGREY
+
def build(self):
self.icon = ICON # how you're supposed to set an icon
+ self.title = f"KaTrain v{VERSION}"
+ self.theme_cls.theme_style = "Dark"
+ self.theme_cls.primary_palette = "Gray"
+ self.theme_cls.primary_hue = "200"
+
kv_file = find_package_resource("katrain/gui.kv")
popup_kv_file = find_package_resource("katrain/popups.kv")
resource_add_path(os.path.split(kv_file)[0])
Builder.load_file(kv_file)
Builder.load_file(popup_kv_file)
- self.gui = KaTrainGui()
- self.title = f"KaTrain v{VERSION}"
- self.theme_cls.theme_style = "Dark"
- self.theme_cls.primary_palette = "Blue"
-
Window.bind(on_request_close=self.on_request_close)
+ self.gui = KaTrainGui()
return self.gui
def on_language(self, _instance, language):
@@ -459,7 +466,7 @@ class KaTrainApp(MDApp):
self.gui.controls.set_status("")
def webbrowser(self, site_key):
- WEBSITES = {"homepage": HOMEPAGE, "support": HOMEPAGE + "#support"}
+ WEBSITES = {"homepage": HOMEPAGE + "#manual", "support": HOMEPAGE + "#support"}
if site_key in WEBSITES:
webbrowser.open(WEBSITES[site_key])
diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py
index 527b5d3..d832775 100644
--- a/katrain/core/game_node.py
+++ b/katrain/core/game_node.py
@@ -29,6 +29,7 @@ class GameNode(SGFNode):
def sgf_properties(self, save_comments_player=None, save_comments_class=None, eval_thresholds=None):
properties = copy.copy(super().sgf_properties())
+ note = self.note.strip()
if self.points_lost and save_comments_class is not None and eval_thresholds is not None:
show_class = save_comments_class[evaluation_class(self.points_lost, eval_thresholds)]
else:
@@ -39,7 +40,7 @@ class GameNode(SGFNode):
and self.analysis_ready
and self.parent
and self.parent.analysis_ready
- ):
+ ) or note:
candidate_moves = self.parent.candidate_moves
top_x = Move.from_gtp(candidate_moves[0]["move"]).sgf(self.board_size)
best_sq = [
@@ -59,7 +60,7 @@ class GameNode(SGFNode):
+ "\n".join(properties.get("C", ""))
+ "\nSGF with review generated by KaTrain."
]
- if self.note.strip():
+ if note:
properties["C"] = ["\n".join(properties.get("C", "")) + f"\nNote: {self.note}"]
return properties
@@ -154,7 +155,7 @@ class GameNode(SGFNode):
pvtext = f"[u][ref={pvtext}][color={INFO_PV_COLOR}]{pvtext}[/color][/ref][/u]"
return pvtext
- def comment(self, sgf=False, teach=False, hints=False, interactive=True):
+ def comment(self, sgf=False, teach=False, details=False, interactive=True):
single_move = self.move
if not self.parent or not single_move: # root
return ""
@@ -167,7 +168,7 @@ class GameNode(SGFNode):
text += i18n._("Info:winrate").format(winrate=self.format_winrate()) + "\n"
if self.parent and self.parent.analysis_ready:
previous_top_move = self.parent.candidate_moves[0]
- if sgf or hints:
+ if sgf or details:
if previous_top_move["move"] != single_move.gtp():
points_lost = self.points_lost
if sgf and points_lost > 0.5:
@@ -181,7 +182,7 @@ class GameNode(SGFNode):
)
else:
text += i18n._("Info:best move") + "\n"
- if previous_top_move.get("pv") and (sgf or hints):
+ if previous_top_move.get("pv") and (sgf or details):
text += (
i18n._("Info:PV").format(
pv=self.make_pv(single_move.player, previous_top_move["pv"], interactive)
@@ -189,7 +190,7 @@ class GameNode(SGFNode):
+ "\n"
)
- if sgf or hints or teach:
+ if sgf or details or teach:
policy_ranking = self.parent.policy_ranking
currmove_policy_with_ix = [
(ix + 1, p)
@@ -203,7 +204,7 @@ class GameNode(SGFNode):
)
+ "\n"
)
- if not currmove_policy_with_ix or currmove_policy_with_ix[0] != 1 and (sgf or hints):
+ if not currmove_policy_with_ix or currmove_policy_with_ix[0] != 1 and (sgf or details):
text += (
i18n._("Info:policy best").format(
move=policy_ranking[0][1].gtp(), probability=policy_ranking[0][0]
@@ -215,7 +216,7 @@ class GameNode(SGFNode):
top_pv = self.analysis_ready and self.candidate_moves[0].get("pv")
if top_pv:
text += i18n._("Info:undo predicted PV").format(pv=f"{self.next_player}{' '.join(top_pv)}") + "\n"
- if self.ai_thoughts and (sgf or hints):
+ if self.ai_thoughts and (sgf or details):
text += "\n" + i18n._("Info:AI thoughts").format(thoughts=self.ai_thoughts)
else:
text = i18n._("No analysis available") if sgf else i18n._("Analyzing move...")
diff --git a/katrain/gui.kv b/katrain/gui.kv
index 3998790..c7471f7 100644
--- a/katrain/gui.kv
+++ b/katrain/gui.kv
@@ -12,6 +12,7 @@
#:import RED katrain.gui.style.RED
#:import WHITE katrain.gui.style.WHITE
+#:import LIGHTGREY katrain.gui.style.LIGHTGREY
#:import BACKGROUND_COLOR katrain.gui.style.BACKGROUND_COLOR
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
#:import TEXT_COLOR katrain.gui.style.TEXT_COLOR
@@ -19,14 +20,13 @@
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
#:set SPINNER_OPTION_COLOR [64 / 255, 85 / 255, 110 / 255, 1]
-#:set LIGHTGREY [0.7,0.7,0.7,1]
#:set BLACK [0.05,0.05,0.05,1]
#:set GREY [0.5,0.5,0.5,1]
#:set GREEN [0.1,0.8,0.1,1]
#:set LIGHTBLUE [0.3,0.7,0.9,1]
#:set YELLOW [0.8,0.8,0.1,1]
#:set DARKRED [0.3,0.1,0.1,1]
-
+#:set ORANGE [242/255,96/255,34/255,1]
#:set SCORE_COLOR LIGHTBLUE
#:set POINTLOSS_COLOR YELLOW
@@ -65,6 +65,7 @@
# new widgets
+
:
ripple_duration_in_slow: 0.6
text_color: TEXT_COLOR
@@ -301,7 +302,7 @@
min_size: min(self.height,self.width)
inactive_line_color: WHITE
inactive_fill_color: [1,1,1,0]
- active_line_color: [242/255,96/255,34/255,1]
+ active_line_color: ORANGE
active_fill_color: [1,1,1,0]
line_width: max(1.1,self.min_size/20)
line_color: root.active_line_color if self.active else root.inactive_line_color
@@ -332,7 +333,8 @@
- color: GREEN
+ timeout: False
+ color: ORANGE if self.timeout else GREEN
markup: True
multiline: False
font_name: 'fonts/digital-7 (mono).ttf'
@@ -341,6 +343,7 @@
spacing: CP_SPACING
padding: CP_PADDING * 4, CP_PADDING * 2
paused: True
+ timeout: self.state[1] <= 0
MDBoxLayout:
size_hint: 0.7,1
MDFloatLayout:
@@ -355,6 +358,7 @@
valign: 'middle'
TimerLabel:
id: timer
+ timeout: root.timeout
text: "{:01d}:{:02d}".format(int(root.state[0]+0.99)//60,int((root.state[0]+0.99) % 60) )
text_size: self.size
font_size: 0.85*self.height
@@ -368,6 +372,7 @@
text_size: self.width, self.height * 0.95
halign: 'right'
valign: 'top'
+ timeout: root.timeout
TimerLabel:
size_hint: 0.1,1
font_size: self.height * 0.35
@@ -377,6 +382,7 @@
id: periods
text: str(root.state[1])
multiline: False
+ timeout: root.timeout
MDBoxLayout:
size_hint: 0.2,1
PauseButton:
@@ -631,14 +637,16 @@
CollapsablePanel:
size_hint_y_open: 1
closed_label: 'closedlabel:info¬es'
- options: ['info','notes']
- option_colors: [WHITE,WHITE]
- option_active: [True,False]
+ options: ['info','info-details','notes']
+ option_colors: [WHITE,WHITE,YELLOW]
+ option_active: [True,False,False]
on_option_state:
info.size_hint_y = int(args[1]['info'])+1e-9
info.opacity = int(args[1]['info'])
+ info.detailed = args[1]['info-details']
notebox.size_hint_y = int(args[1]['notes'])*0.66+1e-9
notebox.opacity = int(args[1]['notes'])
+ app.gui.update_state()
options_height: root.tab_option_height
BGBoxLayout:
background_color: BOX_BACKGROUND_COLOR
@@ -651,6 +659,7 @@
background_color: DARKRED
ScrollableLabel:
id: info
+ detailed: False
line_height: 1.25
markup: True
on_ref_press: root.katrain.board_gui.show_pv_from_comments(args[1])
@@ -700,8 +709,6 @@
pos_hint: {'center_y': 0.5}
width: self.height
active: root.default_active
- selected_color: WHITE
- unselected_color: LIGHTGREY
on_active: if app.gui: app.gui.update_state()
:
diff --git a/katrain/gui/controlspanel.py b/katrain/gui/controlspanel.py
index 8b35aac..35dc18c 100644
--- a/katrain/gui/controlspanel.py
+++ b/katrain/gui/controlspanel.py
@@ -84,11 +84,11 @@ class ControlsPanel(BoxLayout):
self.active_comment_node = current_node.parent
lock_ai = katrain.config("trainer/lock_ai") and katrain.play_analyze_mode == MODE_PLAY
- hints = katrain.analysis_controls.hints.active and not lock_ai
+ details = self.info.detailed and not lock_ai
info = ""
if current_node.move and not current_node.is_root:
info = self.active_comment_node.comment(
- teach=katrain.players_info[self.active_comment_node.player].being_taught, hints=hints
+ teach=katrain.players_info[self.active_comment_node.player].being_taught, details=details
)
if self.active_comment_node.analysis_ready:
diff --git a/katrain/gui/kivyutils.py b/katrain/gui/kivyutils.py
index ae52b16..be9060a 100644
--- a/katrain/gui/kivyutils.py
+++ b/katrain/gui/kivyutils.py
@@ -302,7 +302,7 @@ class PlayerInfo(MDBoxLayout, BackgroundMixin):
class Timer(BGBoxLayout):
state = ListProperty([30, 5, 1])
-
+ timeout = BooleanProperty(False)
class AnalysisToggle(MDBoxLayout):
text = StringProperty("")
diff --git a/katrain/gui/style.py b/katrain/gui/style.py
index 53eddc9..cd35d55 100644
--- a/katrain/gui/style.py
+++ b/katrain/gui/style.py
@@ -7,6 +7,7 @@ DEFAULT_FONT = "fonts/NotoSans-Regular.ttf"
# basic color definitions
RED = [0.8, 0.1, 0.1, 1]
WHITE = [0.95, 0.95, 0.95, 1]
+LIGHTGREY = [0.7,0.7,0.7,1]
# gui colors
diff --git a/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/en/LC_MESSAGES/katrain.mo
index 88acc05..9f3add4 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 7e43428..c5ea05a 100644
--- a/katrain/i18n/locales/en/LC_MESSAGES/katrain.po
+++ b/katrain/i18n/locales/en/LC_MESSAGES/katrain.po
@@ -133,6 +133,9 @@ msgstr "Point Loss"
msgid "tab:info"
msgstr "Info"
+msgid "tab:info-details"
+msgstr "Details"
+
msgid "tab:notes"
msgstr "Notes"
diff --git a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.mo
index 8df582d..6d3bc57 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 06f18df..5a4cd90 100644
--- a/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po
+++ b/katrain/i18n/locales/fr/LC_MESSAGES/katrain.po
@@ -608,3 +608,7 @@ msgstr ""
#. TODO
msgid "ai:p:rank"
msgstr "Calibrated Rank Bot"
+
+#. TODO
+msgid "tab:info-details"
+msgstr "+Analysis"
diff --git a/katrain/i18n/locales/haha/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/haha/LC_MESSAGES/katrain.mo
index 801b4f4..6dc15a2 100644
Binary files a/katrain/i18n/locales/haha/LC_MESSAGES/katrain.mo and b/katrain/i18n/locales/haha/LC_MESSAGES/katrain.mo differ
diff --git a/katrain/i18n/locales/haha/LC_MESSAGES/katrain.po b/katrain/i18n/locales/haha/LC_MESSAGES/katrain.po
index 41118a5..55f8578 100644
--- a/katrain/i18n/locales/haha/LC_MESSAGES/katrain.po
+++ b/katrain/i18n/locales/haha/LC_MESSAGES/katrain.po
@@ -538,3 +538,6 @@ msgstr ""
msgid "ai:p:rank"
msgstr "ㅋㅋCalibrated Rank Bot"
+
+msgid "tab:info-details"
+msgstr "ㅋㅋ+Analysis"
diff --git a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.mo
index ecd9e06..edd3fa5 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 8eb7175..d5e073a 100644
--- a/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po
+++ b/katrain/i18n/locales/ko/LC_MESSAGES/katrain.po
@@ -549,3 +549,7 @@ msgstr ""
#. TODO
msgid "ai:p:rank"
msgstr "Calibrated Rank Bot"
+
+#. TODO
+msgid "tab:info-details"
+msgstr "+Analysis"
diff --git a/katrain/popups.kv b/katrain/popups.kv
index c3ec740..8bb3904 100644
--- a/katrain/popups.kv
+++ b/katrain/popups.kv
@@ -28,10 +28,12 @@
helper_text_mode: "none"
hint_text: ""
helper_text: ""
+ color_mode: 'custom'
+ line_color_focus: TEXT_COLOR
:
font_size: dp(16)
- multiline: True # just for wrapping
+ multiline: False
helper_text_mode: "on_error"
helper_text: i18n._("file not found")
@@ -47,6 +49,7 @@
size: DESC_FONT_SIZE*2,DESC_FONT_SIZE*2
size_hint: None,None
+
on_left_press: if self.target: self.target.text = self.text
size: DESC_FONT_SIZE * 2, DESC_FONT_SIZE * 2
@@ -78,17 +81,22 @@
:
configfile: configfile
+ BoxLayout:
+ size_hint: 1,1
+ orientation: 'horizontal'
+ DescriptionLabel:
+ text: i18n._('general settings')
+ font_size: DESC_FONT_SIZE * 1.5
+ DescriptionLabel:
+ font_size: DESC_FONT_SIZE * 1.5
+ text: i18n._('engine settings')
BoxLayout:
size_hint: 1,9
orientation: 'horizontal'
GridLayout:
cols: 2
- rows: 8
+ rows: 7
spacing: CP_SPACING
- Label:
- DescriptionLabel:
- text: i18n._('general settings')
- font_size: DESC_FONT_SIZE * 1.5
DescriptionLabel:
text: i18n._("general:sgf_load")
AnchorLayout:
@@ -126,12 +134,8 @@
width: 2
GridLayout:
cols: 2
- rows: 8
+ rows: 7
spacing: CP_SPACING
- Label:
- DescriptionLabel:
- font_size: DESC_FONT_SIZE * 1.5
- text: i18n._('engine settings')
DescriptionLabel:
text: i18n._("engine:katago")
AnchorLayout: