diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4427d98..1f37d7a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -8,6 +8,7 @@ Matthew Allred ("Kameone") for design of the v1.1 UI and providing MacOS install Additional thanks to: "Seventeen" for explanatory youtube videos. +"wonderingabout" for helping with the French translation. diff --git a/README.md b/README.md index 757beba..3a8e54a 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ This section describes the available AIs, with strength based on their current O The Engine based AIs (KataGo, ScoreLoss, KataJigo) are affected by both the model and choice of visits and maximum time, while the policy net based AIs are affected by the choice of model file, but work identically with 1 visit. +Further technical details and discussion on these AIs can be found on [this](https://lifein19x19.com/viewtopic.php?f=10&t=17488&sid=b11e42c005bb6f4f48c83771e6a27eff) thread at the life in 19x19 forums. + ## Analysis AI moves, teaching mode and timers are suspended in analysis mode, diff --git a/i18n.py b/i18n.py index c7fbe4e..1204c57 100644 --- a/i18n.py +++ b/i18n.py @@ -30,7 +30,7 @@ for lang in locales: strings_to_langs[entry.msgid][lang] = entry.msgstr strings_to_keys[entry.msgid][lang] = set(re.findall("{.*?}", entry.msgstr)) if entry.msgid in lang_to_strings[lang]: - print('duplicate',entry.msgid,'in',lang ) + print("duplicate", entry.msgid, "in", lang) errors = True lang_to_strings[lang].add(entry.msgid) if num_todo[lang]: diff --git a/katrain/KataGo/katago b/katrain/KataGo/katago index a47e296..6516368 100755 Binary files a/katrain/KataGo/katago and b/katrain/KataGo/katago differ diff --git a/katrain/__main__.py b/katrain/__main__.py index 3bde3c2..504bc52 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -24,6 +24,7 @@ from kivy.resources import resource_add_path from kivy.uix.popup import Popup from kivy.uix.screenmanager import Screen from katrain.core.ai import ai_move +from kivy.core.window import Window from katrain.core.lang import DEFAULT_LANGUAGE, i18n from katrain.core.constants import ( diff --git a/katrain/core/ai.py b/katrain/core/ai.py index bf4561b..f19be7e 100644 --- a/katrain/core/ai.py +++ b/katrain/core/ai.py @@ -18,7 +18,8 @@ from katrain.core.constants import ( AI_INFLUENCE, AI_LOCAL, AI_TENUKI, - AI_TERRITORY, AI_PICK, + AI_TERRITORY, + AI_PICK, ) from katrain.core.engine import EngineDiedException from katrain.core.game import Game, GameNode, Move diff --git a/katrain/core/base_katrain.py b/katrain/core/base_katrain.py index 18b83de..7d9918b 100644 --- a/katrain/core/base_katrain.py +++ b/katrain/core/base_katrain.py @@ -1,9 +1,11 @@ -from kivy import Config -from kivy.properties import ObjectProperty -from kivy.storage.jsonstore import JsonStore -import os, sys, shutil -from katrain.core.constants import * +import os +import shutil +import sys +from kivy import Config +from kivy.storage.jsonstore import JsonStore + +from katrain.core.constants import * from katrain.core.utils import find_package_resource diff --git a/katrain/core/engine.py b/katrain/core/engine.py index 7f60288..ecf6748 100644 --- a/katrain/core/engine.py +++ b/katrain/core/engine.py @@ -1,6 +1,5 @@ import copy import json -import shlex import subprocess import sys import threading @@ -39,16 +38,11 @@ class KataGoEngine: else: # e.g. MacOS after brewing executable = "katago" - modelfile, configfile, exefile = ( - find_package_resource(config["model"]), - find_package_resource(config["config"]), - find_package_resource(executable), - ) - self.command = ( - f'"{exefile}" analysis -model "{modelfile}" -config "{configfile}" -analysis-threads {config["threads"]}' - ) - if not sys.platform.startswith("win"): - self.command = shlex.split(self.command) + model = find_package_resource(config["model"]) + cfg = find_package_resource(config["config"]) + exe = find_package_resource(executable) + + self.command = f'"{exe}" analysis -model "{model}" -config "{cfg}" -analysis-threads {config["threads"]}' self.queries = {} # outstanding query id -> start time and callback self.config = config self.query_counter = 0 @@ -127,33 +121,37 @@ class KataGoEngine: return if not line: continue - analysis = json.loads(line) - if analysis["id"] not in self.queries: - self.katrain.log(f"Query result {analysis['id']} discarded -- recent new game?", OUTPUT_DEBUG) - continue - query_id = analysis["id"] - callback, error_callback, start_time, next_move = self.queries[query_id] - if "error" in analysis: - del self.queries[query_id] - if error_callback: - error_callback(analysis) - elif not (next_move and "Illegal move" in analysis["error"]): # sweep - self.katrain.log(f"{analysis} received from KataGo", OUTPUT_ERROR) - elif "warning" in analysis: - self.katrain.log(f"{analysis} received from KataGo", OUTPUT_DEBUG) - else: - del self.queries[query_id] - time_taken = time.time() - start_time - self.katrain.log( - f"[{time_taken:.1f}][{analysis['id']}] KataGo Analysis Received: {analysis.keys()}", OUTPUT_DEBUG - ) - self.katrain.log(line, OUTPUT_EXTRA_DEBUG) - try: - callback(analysis) - except Exception as e: - self.katrain.log(f"Error in engine callback for query {query_id}: {e}", OUTPUT_ERROR) - if getattr(self.katrain, "update_state", None): # easier mocking etc - self.katrain.update_state() + try: + analysis = json.loads(line) + if analysis["id"] not in self.queries: + self.katrain.log(f"Query result {analysis['id']} discarded -- recent new game?", OUTPUT_DEBUG) + continue + query_id = analysis["id"] + callback, error_callback, start_time, next_move = self.queries[query_id] + if "error" in analysis: + del self.queries[query_id] + if error_callback: + error_callback(analysis) + elif not (next_move and "Illegal move" in analysis["error"]): # sweep + self.katrain.log(f"{analysis} received from KataGo", OUTPUT_ERROR) + elif "warning" in analysis: + self.katrain.log(f"{analysis} received from KataGo", OUTPUT_DEBUG) + else: + del self.queries[query_id] + time_taken = time.time() - start_time + self.katrain.log( + f"[{time_taken:.1f}][{analysis['id']}] KataGo Analysis Received: {analysis.keys()}", + OUTPUT_DEBUG, + ) + self.katrain.log(line, OUTPUT_EXTRA_DEBUG) + try: + callback(analysis) + except Exception as e: + self.katrain.log(f"Error in engine callback for query {query_id}: {e}", OUTPUT_ERROR) + if getattr(self.katrain, "update_state", None): # easier mocking etc + self.katrain.update_state() + except Exception as e: + self.katrain.log(f"Unexpected exception while processing KataGo output {line}", OUTPUT_ERROR) def send_query(self, query, callback, error_callback, next_move=None): with self._lock: diff --git a/katrain/core/game.py b/katrain/core/game.py index 4f0d2ba..0f5f6b3 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -3,14 +3,14 @@ import os import re import threading from datetime import datetime -from typing import Dict, List, Union, Optional +from typing import Dict, List, Optional, Union -from katrain.core.utils import var_to_grid -from katrain.core.lang import i18n -from katrain.core.constants import OUTPUT_INFO, OUTPUT_DEBUG, HOMEPAGE +from katrain.core.constants import HOMEPAGE, OUTPUT_DEBUG, OUTPUT_INFO from katrain.core.engine import KataGoEngine from katrain.core.game_node import GameNode +from katrain.core.lang import i18n from katrain.core.sgf_parser import SGF, Move +from katrain.core.utils import var_to_grid class IllegalMoveException(Exception): diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py index d363bd5..527b5d3 100644 --- a/katrain/core/game_node.py +++ b/katrain/core/game_node.py @@ -2,9 +2,9 @@ import copy import random from typing import Dict, List, Optional, Tuple -from katrain.core.utils import evaluation_class, var_to_grid from katrain.core.lang import i18n from katrain.core.sgf_parser import Move, SGFNode +from katrain.core.utils import evaluation_class, var_to_grid from katrain.gui.style import INFO_PV_COLOR diff --git a/katrain/core/lang.py b/katrain/core/lang.py index e5eb979..62f4f98 100644 --- a/katrain/core/lang.py +++ b/katrain/core/lang.py @@ -71,7 +71,7 @@ class Lang(Observable): except ReferenceError: pass # proxy no longer exists except Exception as e: - print("Error in switching languages",e) + print("Error in switching languages", e) for cb in self.callbacks: try: cb(self) diff --git a/katrain/fonts/__init__.py b/katrain/fonts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/katrain/gui/badukpan.py b/katrain/gui/badukpan.py index 7c447a6..0c33d43 100644 --- a/katrain/gui/badukpan.py +++ b/katrain/gui/badukpan.py @@ -4,42 +4,21 @@ import time from typing import List, Optional from kivy.clock import Clock +from kivy.core.window import Window from kivy.graphics.context_instructions import Color from kivy.graphics.vertex_instructions import Ellipse, Line, Rectangle -from kivy.metrics import sp -from kivy.properties import ListProperty, StringProperty, NumericProperty -from kivy.uix.boxlayout import BoxLayout +from kivy.properties import ListProperty from kivy.uix.widget import Widget from kivymd.app import MDApp -from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.floatlayout import MDFloatLayout -from kivymd.uix.menu import MDDropdownMenu, RightContent +from kivymd.uix.menu import MDDropdownMenu -from katrain.core.utils import evaluation_class -from katrain.core.lang import i18n -from katrain.core.constants import OUTPUT_DEBUG, MODE_PLAY +from katrain.core.constants import MODE_PLAY, OUTPUT_DEBUG from katrain.core.game import Move +from katrain.core.lang import i18n +from katrain.core.utils import evaluation_class, var_to_grid from katrain.gui.kivyutils import draw_circle, draw_text -from katrain.core.utils import var_to_grid -from kivy.core.window import Window - -from katrain.gui.style import ( - EVAL_COLORS, - LINE_COLOR, - POLICY_COLOR, - GHOST_ALPHA, - TOP_MOVE_ALPHA, - STONE_COLORS, - OUTLINE_COLORS, - CHILD_SCALE, - EVAL_DOT_MIN_SIZE, - EVAL_DOT_MAX_SIZE, - BOARD_COLOR, - STARPOINT_SIZE, - STONE_SIZE, - VISITS_FRAC_SMALL, - ENGINE_DOWN_COL, -) +from katrain.gui.style import * class BadukPanWidget(Widget): diff --git a/katrain/gui/kivyutils.py b/katrain/gui/kivyutils.py index cd633e0..d276f99 100644 --- a/katrain/gui/kivyutils.py +++ b/katrain/gui/kivyutils.py @@ -1,46 +1,33 @@ -import json -import random -import re - from kivy.clock import Clock -from kivy.core.window import Window +from kivy.core.text import Label as CoreLabel from kivy.graphics import * from kivy.properties import ( BooleanProperty, ListProperty, NumericProperty, - StringProperty, - OptionProperty, ObjectProperty, + OptionProperty, + StringProperty, ) -from kivy.uix.behaviors import ToggleButtonBehavior, ButtonBehavior +from kivy.uix.behaviors import ButtonBehavior, ToggleButtonBehavior from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button -from kivy.uix.checkbox import CheckBox -from kivy.uix.filechooser import FileChooserLayout, FileChooserListLayout -from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.scrollview import ScrollView from kivy.uix.spinner import Spinner -from kivy.uix.textinput import TextInput from kivy.uix.widget import Widget - - -# --new from kivymd.app import MDApp -from kivymd.uix.behaviors import RectangularRippleBehavior, CircularRippleBehavior +from kivymd.uix.behaviors import CircularRippleBehavior, RectangularRippleBehavior from kivymd.uix.boxlayout import MDBoxLayout -from kivymd.uix.button import BasePressedButton, BaseFlatButton +from kivymd.uix.button import BaseFlatButton, BasePressedButton from kivymd.uix.navigationdrawer import MDNavigationDrawer -from kivy.core.text import Label as CoreLabel -from katrain.core.constants import GAME_TYPES, AI_STRATEGIES_RECOMMENDED_ORDER, PLAYER_HUMAN, PLAYER_AI +from katrain.core.constants import AI_STRATEGIES_RECOMMENDED_ORDER, GAME_TYPES, PLAYER_AI from katrain.core.lang import i18n +from katrain.gui.style import DEFAULT_FONT, WHITE -# -# --- new mixins -from katrain.gui.style import WHITE, DEFAULT_FONT +# -- mixins class BackgroundMixin(Widget): @@ -177,7 +164,7 @@ class BGBoxLayout(BoxLayout, BackgroundMixin): pass -# -- new gui elements +# -- gui elements class I18NSpinner(Spinner): diff --git a/katrain/gui/popups.py b/katrain/gui/popups.py index 44c72d8..5b91caf 100644 --- a/katrain/gui/popups.py +++ b/katrain/gui/popups.py @@ -1,8 +1,9 @@ -import re, os -from typing import Dict, Tuple, Any, Union, List +import os +import re +from typing import Any, Dict, List, Tuple, Union from kivy.clock import Clock -from kivy.properties import StringProperty, BooleanProperty, NumericProperty +from kivy.properties import BooleanProperty, NumericProperty, StringProperty from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label @@ -13,17 +14,17 @@ from kivymd.uix.selectioncontrol import MDCheckbox from kivymd.uix.textfield import MDTextField from katrain.core.constants import ( - OUTPUT_ERROR, - OUTPUT_DEBUG, - OUTPUT_INFO, - AI_DEFAULT, AI_CONFIG_DEFAULT, + AI_DEFAULT, AI_STRATEGIES_RECOMMENDED_ORDER, + OUTPUT_DEBUG, + OUTPUT_ERROR, + OUTPUT_INFO, ) from katrain.core.engine import KataGoEngine -from katrain.core.utils import find_package_resource from katrain.core.lang import i18n -from katrain.gui.kivyutils import I18NSpinner, BackgroundMixin +from katrain.core.utils import find_package_resource +from katrain.gui.kivyutils import BackgroundMixin, I18NSpinner from katrain.gui.style import DEFAULT_FONT, EVAL_COLORS diff --git a/katrain/gui/widgets/filebrowser.py b/katrain/gui/widgets/filebrowser.py index 388abf0..b8ffb39 100644 --- a/katrain/gui/widgets/filebrowser.py +++ b/katrain/gui/widgets/filebrowser.py @@ -37,19 +37,20 @@ a shortcut to the Documents directory added to the favorites bar:: .. image:: _static/filebrowser.png :align: right """ -from kivy import Config -from kivy.uix.boxlayout import BoxLayout -from kivy.uix.treeview import TreeViewLabel, TreeView -from kivy.uix.filechooser import FileChooserListView, FileChooserListLayout -from kivy.properties import ObjectProperty, StringProperty, OptionProperty, ListProperty, BooleanProperty -from kivy.lang import Builder -from kivy.utils import platform -from kivy.clock import Clock import string -from os.path import sep, dirname, expanduser, isdir, join, getmtime -from os import walk -from functools import partial import warnings +from functools import partial +from os import walk +from os.path import dirname, expanduser, getmtime, isdir, join, sep + +from kivy import Config +from kivy.clock import Clock +from kivy.lang import Builder +from kivy.properties import BooleanProperty, ListProperty, ObjectProperty, OptionProperty, StringProperty +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.filechooser import FileChooserListLayout, FileChooserListView +from kivy.uix.treeview import TreeView, TreeViewLabel +from kivy.utils import platform from katrain.gui.style import DEFAULT_FONT diff --git a/katrain/gui/widgets/graph.py b/katrain/gui/widgets/graph.py index 9ee51a4..a92fc8f 100644 --- a/katrain/gui/widgets/graph.py +++ b/katrain/gui/widgets/graph.py @@ -1,6 +1,6 @@ import math -from kivy.properties import ListProperty, NumericProperty, BooleanProperty +from kivy.properties import BooleanProperty, ListProperty, NumericProperty from katrain.gui.kivyutils import BackgroundMixin diff --git a/katrain/popups.kv b/katrain/popups.kv index 4a9030b..d487425 100644 --- a/katrain/popups.kv +++ b/katrain/popups.kv @@ -2,6 +2,7 @@ #:import i18n katrain.core.lang.i18n #:import expanduser os.path.expanduser #:import abspath os.path.abspath +#:import kivy_version kivy.__version__ #:set CP_SPACING 6 #:set CP_SMALL_SPACING 3 @@ -52,7 +53,8 @@ font_size: DESC_FONT_SIZE : - background_color: [*[c*255/66 for c in BACKGROUND_COLOR[:3]], 1] + background_color: BACKGROUND_COLOR + background: self.background if kivy_version < '2.0' else '' title: i18n._(self.title_key) title_size: DESC_FONT_SIZE title_font: self.font_name