hints for player names, flake8, rankgraph ded
This commit is contained in:
1 parent
0276e4b2a4
commit
2499488a20
35 files changed
+96
-227
No files matched your search
@@ -27,7 +27,7 @@ for lang in locales:
|
||||
pofile[lang] = os.path.join(localedir, lang, "LC_MESSAGES", "katrain.po")
|
||||
po[lang] = polib.pofile(pofile[lang])
|
||||
for entry in po[lang].translated_entries():
|
||||
if "TODO" in entry.comment and not "DEPRECATED" in entry.comment:
|
||||
if "TODO" in entry.comment and "DEPRECATED" not in entry.comment:
|
||||
todos[lang].append(entry)
|
||||
strings_to_langs[entry.msgid][lang] = entry
|
||||
strings_to_keys[entry.msgid][lang] = set(re.findall("{.*?}", entry.msgstr))
|
||||
@@ -75,7 +75,7 @@ for lang in locales:
|
||||
|
||||
for msgid, lang_entries in strings_to_langs.items():
|
||||
if lang in lang_entries and "TODO" in lang_entries[lang].comment:
|
||||
if any(e.msgstr == lang_entries[lang].msgstr for l, e in lang_entries.items() if l != lang):
|
||||
if any(e.msgstr == lang_entries[lang].msgstr for ll, e in lang_entries.items() if ll != lang):
|
||||
todo_comment = (
|
||||
f"TODO - {lang_entries[DEFAULT_LANG].comment}" if lang_entries[DEFAULT_LANG].comment else "TODO"
|
||||
) # update todo
|
||||
|
||||
+5
-5
@@ -74,7 +74,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, ConfigAIPopup
|
||||
from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL, LIGHTGREY
|
||||
from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL
|
||||
from katrain.gui.widgets import *
|
||||
from katrain.gui.badukpan import AnalysisControls, BadukPanControls, BadukPanWidget
|
||||
from katrain.gui.controlspanel import ControlsPanel
|
||||
@@ -108,14 +108,14 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
super().log(message, level)
|
||||
if level == OUTPUT_KATAGO_STDERR and "ERROR" not in self.controls.status.text:
|
||||
if "starting" in message.lower():
|
||||
self.controls.set_status(f"KataGo engine starting...", STATUS_INFO)
|
||||
self.controls.set_status("KataGo engine starting...", STATUS_INFO)
|
||||
if message.startswith("Tuning"):
|
||||
self.controls.set_status(
|
||||
f"KataGo is tuning settings for first startup, please wait." + message, STATUS_INFO
|
||||
"KataGo is tuning settings for first startup, please wait." + message, STATUS_INFO
|
||||
)
|
||||
return
|
||||
if "ready" in message.lower():
|
||||
self.controls.set_status(f"KataGo engine ready.", STATUS_INFO)
|
||||
self.controls.set_status("KataGo engine ready.", STATUS_INFO)
|
||||
if (
|
||||
level == OUTPUT_ERROR
|
||||
or (level == OUTPUT_KATAGO_STDERR and "error" in message.lower() and "tuning" not in message.lower())
|
||||
@@ -450,7 +450,7 @@ class KaTrainGui(Screen, KaTrainBase):
|
||||
def load_sgf_from_clipboard(self):
|
||||
clipboard = Clipboard.paste()
|
||||
if not clipboard:
|
||||
self.controls.set_status(f"Ctrl-V pressed but clipboard is empty.", STATUS_INFO)
|
||||
self.controls.set_status("Ctrl-V pressed but clipboard is empty.", STATUS_INFO)
|
||||
return
|
||||
|
||||
url_match = re.match(r"(?P<url>https?://[^\s]+)", clipboard)
|
||||
|
||||
+3
-3
@@ -203,7 +203,7 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
game, cn, {"playoutDoublingAdvantage": pda, "playoutDoublingAdvantagePla": "BLACK"}
|
||||
)
|
||||
if not handicap_analysis:
|
||||
game.katrain.log(f"Error getting handicap-based move", OUTPUT_ERROR)
|
||||
game.katrain.log("Error getting handicap-based move", OUTPUT_ERROR)
|
||||
ai_mode = AI_DEFAULT
|
||||
|
||||
while not cn.analysis_complete:
|
||||
@@ -225,7 +225,7 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
ai_mode in [AI_LOCAL, AI_TENUKI] and not (cn.move and cn.move.coords)
|
||||
):
|
||||
ai_mode = AI_WEIGHTED
|
||||
ai_thoughts += f"Strategy override, using policy-weighted strategy instead. "
|
||||
ai_thoughts += "Strategy override, using policy-weighted strategy instead. "
|
||||
ai_settings = {"pick_override": 0.9, "weaken_fac": 1, "lower_bound": 0.02}
|
||||
|
||||
if top_5_pass:
|
||||
@@ -336,7 +336,7 @@ def generate_ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move,
|
||||
AI_HANDICAP,
|
||||
]: # don't play suicidal to balance score
|
||||
aimove = top_cand
|
||||
ai_thoughts += f"Top move is pass, so passing regardless of strategy. "
|
||||
ai_thoughts += "Top move is pass, so passing regardless of strategy. "
|
||||
else:
|
||||
if ai_mode == AI_JIGO:
|
||||
sign = cn.player_sign(cn.next_player)
|
||||
|
||||
@@ -10,7 +10,6 @@ from kivy.clock import Clock
|
||||
|
||||
from katrain.core.constants import (
|
||||
ANALYSIS_FORMAT_VERSION,
|
||||
HOMEPAGE,
|
||||
OUTPUT_DEBUG,
|
||||
OUTPUT_INFO,
|
||||
PLAYER_AI,
|
||||
|
||||
@@ -280,7 +280,7 @@ class SGFNode:
|
||||
@property
|
||||
def next_player(self):
|
||||
"""Returns player to move"""
|
||||
if "B" in self.properties or ("AB" in self.properties and not "W" in self.properties): # root or black moved
|
||||
if "B" in self.properties or ("AB" in self.properties and "W" not in self.properties): # root or black moved
|
||||
return "W"
|
||||
else:
|
||||
return "B"
|
||||
@@ -288,7 +288,7 @@ class SGFNode:
|
||||
@property
|
||||
def player(self):
|
||||
"""Returns player that moved last. nb root is considered white played if no handicap stones are placed"""
|
||||
if "B" in self.properties or ("AB" in self.properties and not "W" in self.properties):
|
||||
if "B" in self.properties or ("AB" in self.properties and "W" not in self.properties):
|
||||
return "B"
|
||||
else:
|
||||
return "W"
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import List, Tuple, TypeVar
|
||||
|
||||
try:
|
||||
import importlib.resources as pkg_resources
|
||||
except:
|
||||
except ImportError:
|
||||
import importlib_resources as pkg_resources
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import copy
|
||||
import math
|
||||
import random
|
||||
import time
|
||||
@@ -33,7 +32,7 @@ from katrain.core.constants import (
|
||||
from katrain.core.game import Move
|
||||
from katrain.core.lang import i18n
|
||||
from katrain.core.utils import evaluation_class, format_visits, var_to_grid
|
||||
from katrain.gui.kivyutils import BackgroundMixin, draw_circle, draw_text, cached_texture
|
||||
from katrain.gui.kivyutils import draw_circle, draw_text, cached_texture
|
||||
from katrain.gui.popups import I18NPopup, ReAnalyzeGamePopup
|
||||
from katrain.gui.style import *
|
||||
|
||||
@@ -209,7 +208,7 @@ class BadukPanWidget(Widget):
|
||||
Rectangle(
|
||||
pos=(self.gridpos_x[x] - evalsize, self.gridpos_y[y] - evalsize),
|
||||
size=(2 * evalsize, 2 * evalsize),
|
||||
texture=cached_texture(f"img/dot.png"),
|
||||
texture=cached_texture("img/dot.png"),
|
||||
)
|
||||
if innercol:
|
||||
Color(*innercol)
|
||||
@@ -217,7 +216,7 @@ class BadukPanWidget(Widget):
|
||||
Rectangle(
|
||||
pos=(self.gridpos_x[x] - inner_size, self.gridpos_y[y] - inner_size),
|
||||
size=(2 * inner_size, 2 * inner_size),
|
||||
texture=cached_texture(f"img/inner.png"),
|
||||
texture=cached_texture("img/inner.png"),
|
||||
)
|
||||
|
||||
def eval_color(self, points_lost, show_dots_for_class: List[bool] = None) -> Optional[List[float]]:
|
||||
@@ -504,7 +503,7 @@ class BadukPanWidget(Widget):
|
||||
katrain = self.katrain
|
||||
game_ended = katrain.game.end_result
|
||||
current_node = katrain.game.current_node
|
||||
player, next_player = current_node.player, current_node.next_player
|
||||
next_player = current_node.next_player
|
||||
|
||||
board_size_x, board_size_y = katrain.game.board_size
|
||||
if len(self.gridpos_x) < board_size_x or len(self.gridpos_y) < board_size_y:
|
||||
@@ -580,7 +579,7 @@ class BadukPanWidget(Widget):
|
||||
)
|
||||
if text_on and top_moves_show: # TODO: faster if not sized?
|
||||
keys = {"size": self.grid_size / 3, "smallsize": self.grid_size / 3.33}
|
||||
player_sign = current_node.player_sign(current_node.next_player)
|
||||
player_sign = current_node.player_sign(next_player)
|
||||
if len(top_moves_show) == 1:
|
||||
fmt = "[size={size:.0f}]{" + top_moves_show[0] + "}[/size]"
|
||||
else:
|
||||
|
||||
@@ -135,7 +135,7 @@ class ControlsPanel(BoxLayout):
|
||||
lock_ai = katrain.config("trainer/lock_ai") and katrain.play_analyze_mode == MODE_PLAY
|
||||
details = self.info.detailed and not lock_ai
|
||||
info = ""
|
||||
if current_node.move or current_node.is_root:
|
||||
if move or current_node.is_root:
|
||||
info = self.active_comment_node.comment(
|
||||
teach=katrain.players_info[self.active_comment_node.player].being_taught, details=details
|
||||
)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import functools
|
||||
|
||||
from kivy.cache import Cache
|
||||
from kivy.clock import Clock
|
||||
from kivy.core.image import Image
|
||||
from kivy.core.text import Label as CoreLabel
|
||||
@@ -16,13 +13,12 @@ from kivy.properties import (
|
||||
StringProperty,
|
||||
)
|
||||
from kivy.resources import resource_find
|
||||
from kivy.uix.behaviors import ButtonBehavior, FocusBehavior, ToggleButtonBehavior
|
||||
from kivy.uix.behaviors import ButtonBehavior, ToggleButtonBehavior
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.button import Button
|
||||
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
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.behaviors import CircularRippleBehavior, RectangularRippleBehavior
|
||||
@@ -229,7 +225,7 @@ class KeyValueSpinner(Spinner):
|
||||
def input_value(self):
|
||||
try:
|
||||
return self.value_refs[self.selected_index]
|
||||
except:
|
||||
except KeyError:
|
||||
return ""
|
||||
|
||||
@property
|
||||
|
||||
@@ -207,7 +207,7 @@ class QuickConfigGui(MDBoxLayout):
|
||||
selected = 0
|
||||
try:
|
||||
selected = widget.value_refs.index(value)
|
||||
except:
|
||||
except: # noqa: E722
|
||||
pass
|
||||
widget.text = widget.values[selected]
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from katrain.gui.widgets.filebrowser import I18NFileBrowser
|
||||
from katrain.gui.widgets.graph import RankGraph, ScoreGraph
|
||||
from katrain.gui.widgets.graph import ScoreGraph
|
||||
from katrain.gui.widgets.movetree import MoveTree
|
||||
from katrain.gui.widgets.selection_slider import SelectionSlider
|
||||
|
||||
__all__ = ["ScoreGraph", "RankGraph", "MoveTree", "I18NFileBrowser", "SelectionSlider"]
|
||||
__all__ = ["ScoreGraph", "MoveTree", "I18NFileBrowser", "SelectionSlider"]
|
||||
@@ -38,7 +38,6 @@ a shortcut to the Documents directory added to the favorites bar::
|
||||
:align: right
|
||||
"""
|
||||
import string
|
||||
import warnings
|
||||
from functools import partial
|
||||
from os import walk
|
||||
from os.path import dirname, expanduser, getmtime, isdir, join, sep
|
||||
@@ -81,27 +80,25 @@ def get_drives():
|
||||
drives = []
|
||||
if platform == "win":
|
||||
bitmask = windll.kernel32.GetLogicalDrives()
|
||||
GetVolumeInformationW = windll.kernel32.GetVolumeInformationW
|
||||
for letter in string.ascii_uppercase:
|
||||
if bitmask & 1:
|
||||
name = create_unicode_buffer(64)
|
||||
# get name of the drive
|
||||
drive = letter + u":"
|
||||
res = GetVolumeInformationW(drive + sep, name, 64, None, None, None, None, 0)
|
||||
drive = letter + ":"
|
||||
if isdir(drive):
|
||||
drives.append((drive, name.value))
|
||||
bitmask >>= 1
|
||||
elif platform == "linux":
|
||||
drives.append((sep, sep))
|
||||
drives.append((expanduser(u"~"), "~/"))
|
||||
places = (sep + u"mnt", sep + u"media")
|
||||
drives.append((expanduser("~"), "~/"))
|
||||
places = (sep + "mnt", sep + "media")
|
||||
for place in places:
|
||||
if isdir(place):
|
||||
for directory in next(walk(place))[1]:
|
||||
drives.append((place + sep + directory, directory))
|
||||
elif platform == "macosx" or platform == "ios":
|
||||
drives.append((expanduser(u"~"), "~/"))
|
||||
vol = sep + u"Volume"
|
||||
drives.append((expanduser("~"), "~/"))
|
||||
vol = sep + "Volume"
|
||||
if isdir(vol):
|
||||
for drive in next(walk(vol))[1]:
|
||||
drives.append((vol + sep + drive, drive))
|
||||
|
||||
@@ -7,9 +7,6 @@ from kivy.properties import BooleanProperty, Clock, ListProperty, NumericPropert
|
||||
from kivy.uix.widget import Widget
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from katrain.core.constants import OUTPUT_ERROR
|
||||
from katrain.core.lang import rank_label
|
||||
|
||||
|
||||
class Graph(Widget):
|
||||
marker_font_size = NumericProperty(0)
|
||||
@@ -128,11 +125,11 @@ class ScoreGraph(Graph):
|
||||
xscale = self.width / max(len(score_values) - 1, 15)
|
||||
available_height = self.height
|
||||
score_line_points = [
|
||||
[self.x + i * xscale, self.y + self.height / 2 + available_height / 2 * (val / self.score_scale),]
|
||||
[self.x + i * xscale, self.y + self.height / 2 + available_height / 2 * (val / self.score_scale)]
|
||||
for i, val in enumerate(score_values)
|
||||
]
|
||||
winrate_line_points = [
|
||||
[self.x + i * xscale, self.y + self.height / 2 + available_height / 2 * (val / self.winrate_scale),]
|
||||
[self.x + i * xscale, self.y + self.height / 2 + available_height / 2 * (val / self.winrate_scale)]
|
||||
for i, val in enumerate(winrate_values)
|
||||
]
|
||||
self.score_points = sum(score_line_points, [])
|
||||
@@ -158,144 +155,6 @@ class ScoreGraph(Graph):
|
||||
self.winrate_dot_pos = winrate_dot_point
|
||||
|
||||
|
||||
def averagemod(data):
|
||||
sorteddata = sorted(data)
|
||||
lendata = len(data)
|
||||
return sum(sorteddata[int(lendata * 0.2) : int(lendata * 0.8) + 1]) / (
|
||||
(int(lendata * 0.8) + 1) - int(lendata * 0.2)
|
||||
) # average without the best and worst 20% of ranks
|
||||
|
||||
|
||||
def gauss(data):
|
||||
return math.exp(-1 * (data) ** 2)
|
||||
|
||||
|
||||
class RankGraph(Graph):
|
||||
black_rank_points = ListProperty([])
|
||||
white_rank_points = ListProperty([])
|
||||
segment_length = NumericProperty(80)
|
||||
RANK_CAP = 5
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.calculate_trigger = Clock.create_trigger(lambda *args: self.rank_game(), 0.25)
|
||||
self.rank_by_player = {}
|
||||
|
||||
@staticmethod
|
||||
def calculate_rank_for_player(segment_stats, num_intersec, player):
|
||||
non_obvious_moves = [
|
||||
(nl, r, val)
|
||||
for nl, r, val, pl in segment_stats
|
||||
if nl is not None and val < (0.8 * (1 - (num_intersec - nl) / num_intersec * 0.5)) and pl == player
|
||||
]
|
||||
if not non_obvious_moves:
|
||||
return None
|
||||
num_legal, rank, value = zip(*non_obvious_moves)
|
||||
rank = [min(r, nl * 0.09) for r, nl in zip(rank, num_legal)]
|
||||
averagemod_rank = averagemod(rank)
|
||||
averagemod_len_legal = averagemod(num_legal)
|
||||
norm_avemod_len_legal = averagemod_len_legal / num_intersec
|
||||
if averagemod_rank > 0.1:
|
||||
rank_kyu = (
|
||||
-0.97222
|
||||
* math.log(averagemod_rank)
|
||||
/ (0.24634 + averagemod_rank * gauss(3.3208 * (norm_avemod_len_legal)))
|
||||
+ 12.703 * (norm_avemod_len_legal)
|
||||
+ 11.198 * math.log(averagemod_rank)
|
||||
+ 12.28 * gauss(2.379 * (norm_avemod_len_legal))
|
||||
- 16.544
|
||||
)
|
||||
else:
|
||||
rank_kyu = -4
|
||||
return min(RankGraph.RANK_CAP, 1 - rank_kyu) # dan rank
|
||||
|
||||
@staticmethod
|
||||
def calculate_ranks(segment_stats, num_intersec):
|
||||
return {pl: RankGraph.calculate_rank_for_player(segment_stats, num_intersec, pl) for pl in "BW"}
|
||||
|
||||
def rank_game(self):
|
||||
try:
|
||||
nodes = self.nodes
|
||||
parent_policy_per_move = [node.parent.policy_ranking if node.parent else None for node in nodes]
|
||||
num_legal_moves = [
|
||||
sum(pv >= 0 for pv, _ in policy_ranking) if policy_ranking else 0
|
||||
for policy_ranking in parent_policy_per_move
|
||||
]
|
||||
policy_stats = [
|
||||
[
|
||||
(num_mv, rank, value, mv.player)
|
||||
for rank, (value, mv) in enumerate(policy_ranking)
|
||||
if mv == node.move
|
||||
][0]
|
||||
if policy_ranking and node.move
|
||||
else (None, None, None, None)
|
||||
for node, policy_ranking, num_mv in zip(nodes, parent_policy_per_move, num_legal_moves)
|
||||
]
|
||||
size = self.nodes[0].board_size
|
||||
num_intersec = size[0] * size[1]
|
||||
half_seg = self.segment_length // 2
|
||||
|
||||
ranks = {"B": [], "W": []}
|
||||
dx = self.segment_length // 4
|
||||
for segment_mid in range(dx, len(nodes), dx):
|
||||
bounds = (max(0, segment_mid - half_seg), min(segment_mid + half_seg, len(nodes)))
|
||||
num_analyzed = sum(num_mv is not None for num_mv, _, _, _ in policy_stats[bounds[0] : bounds[1] + 1])
|
||||
if num_analyzed >= self.segment_length * 0.75:
|
||||
for pl, rank in self.calculate_ranks(policy_stats[bounds[0] : bounds[1] + 1], num_intersec).items():
|
||||
ranks[pl].append((segment_mid, rank))
|
||||
self.rank_by_player = ranks
|
||||
except Exception as e:
|
||||
MDApp.get_running_app().gui.log(f"Exception while calculating rank: {e}", OUTPUT_ERROR)
|
||||
self.redraw_trigger()
|
||||
|
||||
def update_value(self, node):
|
||||
super().update_value(node)
|
||||
self.trigger_calculate()
|
||||
|
||||
def trigger_calculate(self):
|
||||
if self.opacity != 0: # recalc here on trigger and only if visible for speed
|
||||
self.calculate_trigger()
|
||||
|
||||
def update_graph(self, *args):
|
||||
if self.rank_by_player:
|
||||
xscale = self.width / max(len(self.nodes) - 1, 15)
|
||||
available_height = self.height
|
||||
|
||||
all_ranks = [rank for lst in self.rank_by_player.values() for seg, rank in lst if rank is not None]
|
||||
if not all_ranks:
|
||||
return
|
||||
|
||||
min_rank = math.floor(min(all_ranks))
|
||||
max_rank = math.ceil(max(all_ranks))
|
||||
if max_rank == min_rank:
|
||||
min_rank -= 1
|
||||
if (max_rank - min_rank) % 2 != 0: # make midpoint whole integer
|
||||
if abs(max_rank - max(all_ranks)) < abs(min(all_ranks) - min_rank) and max_rank < self.RANK_CAP:
|
||||
max_rank += 1
|
||||
else:
|
||||
min_rank -= 1
|
||||
rank_range = max_rank - min_rank
|
||||
|
||||
self.ids.mid_marker.text = rank_label((max_rank + min_rank) / 2)
|
||||
self.ids.top_marker.text = rank_label(max_rank) + ("+" if max_rank == self.RANK_CAP else "")
|
||||
self.ids.bottom_marker.text = rank_label(min_rank)
|
||||
|
||||
graph_points = {}
|
||||
for pl, rank_points in self.rank_by_player.items():
|
||||
graph_points[pl] = [
|
||||
[
|
||||
self.x + i * xscale,
|
||||
self.y + available_height * (val - min_rank) / rank_range if val is not None else math.nan,
|
||||
]
|
||||
for i, val in rank_points
|
||||
]
|
||||
self.black_rank_points = sum(graph_points["B"], [])
|
||||
self.white_rank_points = sum(graph_points["W"], [])
|
||||
else:
|
||||
self.black_rank_points = []
|
||||
self.white_rank_points = []
|
||||
|
||||
|
||||
Builder.load_string(
|
||||
"""
|
||||
#:set GRAPH_CENTER_COLOR [0.5,0.5,0.5]
|
||||
@@ -388,38 +247,5 @@ Builder.load_string(
|
||||
pos:root.pos[0]+1, root.pos[1]
|
||||
text: "{}%".format(50 - root.winrate_scale)
|
||||
opacity: int(root.show_winrate)
|
||||
|
||||
<RankGraph>:
|
||||
background_color: LIGHTER_BACKGROUND_COLOR
|
||||
canvas:
|
||||
Color:
|
||||
rgba: WHITE
|
||||
Line:
|
||||
points: root.white_rank_points
|
||||
width: dp(1.1)
|
||||
Color:
|
||||
rgba: BLACK
|
||||
Line:
|
||||
points: root.black_rank_points
|
||||
width: dp(1.1)
|
||||
# rank ticks
|
||||
GraphMarkerLabel:
|
||||
id: mid_marker
|
||||
font_size: root.marker_font_size
|
||||
color: YELLOW
|
||||
pos: root.x + root.width - self.width-1, root.y + root.height*0.5 - self.height/2 + 2
|
||||
text: '?' + i18n._('strength:kyu')
|
||||
GraphMarkerLabel:
|
||||
id: top_marker
|
||||
font_size: root.marker_font_size
|
||||
color: YELLOW
|
||||
pos: root.x + root.width - self.width-1, root.pos[1]+root.height - self.font_size - 1
|
||||
text: '?' + i18n._('strength:kyu')
|
||||
GraphMarkerLabel:
|
||||
id: bottom_marker
|
||||
font_size: root.marker_font_size
|
||||
color: YELLOW
|
||||
pos: root.x + root.width - self.width-1, root.pos[1]
|
||||
text: '?' + i18n._('strength:kyu')
|
||||
"""
|
||||
)
|
||||
@@ -12,20 +12,14 @@ from kivymd.app import MDApp
|
||||
|
||||
from katrain.gui.kivyutils import BackgroundMixin, draw_circle, draw_text
|
||||
from katrain.gui.style import (
|
||||
BACKGROUND_COLOR,
|
||||
DARKRED,
|
||||
GREEN,
|
||||
LIGHT_ORANGE,
|
||||
LIGHTER_BACKGROUND_COLOR,
|
||||
LIGHTGREY,
|
||||
ORANGE,
|
||||
OUTLINE_COLORS,
|
||||
RED,
|
||||
STONE_COLORS,
|
||||
STONE_TEXT_COLORS,
|
||||
WHITE,
|
||||
YELLOW,
|
||||
GREY,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
from kivy.lang import Builder
|
||||
from kivy.properties import BooleanProperty, ListProperty, NumericProperty
|
||||
from kivy.uix.widget import Widget
|
||||
from kivymd.uix.label import MDLabel
|
||||
from kivymd.uix.selectioncontrol import Thumb
|
||||
|
||||
|
||||
class SelectionSlider(Widget):
|
||||
|
||||
Binary file not shown.
@@ -762,3 +762,10 @@ msgstr "Expand/Collapse"
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -814,3 +814,10 @@ msgstr "Expand/Collapse"
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -360,6 +360,14 @@ msgstr "Setup New Game"
|
||||
msgid "player names"
|
||||
msgstr "Player Names"
|
||||
|
||||
#. hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
|
||||
msgid "board size"
|
||||
msgstr "Board size"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -821,3 +821,10 @@ msgstr "Expand/Collapse"
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -847,3 +847,11 @@ msgstr "Expand/Collapse"
|
||||
#. TODO - Menu option
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -804,3 +804,11 @@ msgstr "Expand/Collapse"
|
||||
#. TODO - Menu option
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -775,3 +775,10 @@ msgstr "Expand/Collapse"
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
Binary file not shown.
@@ -811,3 +811,10 @@ msgstr "Expand/Collapse"
|
||||
msgid "analysis:playtoend"
|
||||
msgstr "Fast playout to game end"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "black player name hint"
|
||||
msgstr "Black player's name"
|
||||
|
||||
#. TODO - hint on player name input
|
||||
msgid "white player name hint"
|
||||
msgstr "White player's name"
|
||||
@@ -393,11 +393,13 @@
|
||||
LabelledTextInput:
|
||||
text: ''
|
||||
id: black_player_name
|
||||
hint_text: i18n._("black player name hint")
|
||||
size_hint: 0.75, None
|
||||
AnchorLayout:
|
||||
LabelledTextInput:
|
||||
text: ''
|
||||
id: white_player_name
|
||||
hint_text: i18n._("white player name hint")
|
||||
size_hint: 0.75, None
|
||||
DescriptionLabel:
|
||||
text: i18n._("board size")
|
||||
|
||||
@@ -5,7 +5,7 @@ from setuptools import find_packages, setup
|
||||
|
||||
package_data = {"": ["*.json", "*.kv", "*.wav"], "katrain": [], "tests": []}
|
||||
packages = find_packages(exclude=["tests"])
|
||||
version = re.search('^VERSION\s*=\s*"(.*)"', open("katrain/core/constants.py").read(), re.M).group(1)
|
||||
version = re.search(r'^VERSION\s*=\s*"(.*)"', open("katrain/core/constants.py").read(), re.M).group(1)
|
||||
|
||||
|
||||
def include_data_files(directory):
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from katrain.core.base_katrain import OUTPUT_INFO, KaTrainBase
|
||||
from katrain.core.base_katrain import KaTrainBase
|
||||
from katrain.core.game import Game, IllegalMoveException, Move
|
||||
from katrain.core.game_node import GameNode
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import os
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from katrain.core.base_katrain import KaTrainBase
|
||||
from katrain.core.engine import KataGoEngine
|
||||
from katrain.core.game import Game, KaTrainSGF
|
||||
from katrain.core.sgf_parser import SGF, SGFNode
|
||||
|
||||
@@ -107,7 +106,7 @@ def test_old_server_style():
|
||||
|
||||
def test_ogs():
|
||||
file = os.path.join(os.path.dirname(__file__), "data/ogs.sgf")
|
||||
tree = SGF.parse_file(file)
|
||||
SGF.parse_file(file)
|
||||
|
||||
|
||||
def test_gibo():
|
||||
|
||||
Reference in new issue
Block a user