stuff
This commit is contained in:
1 parent
24bfdf3e4a
commit
7530eff4d3
8 files changed
+85
-50
No files matched your search
@@ -256,6 +256,7 @@ class KaTrainGui(Screen, KaTrainBase):
|
|||||||
player_info.name = move_tree.root.get_property("P" + bw)
|
player_info.name = move_tree.root.get_property("P" + bw)
|
||||||
self.update_player(bw)
|
self.update_player(bw)
|
||||||
self.controls.graph.initialize_from_game(self.game.root)
|
self.controls.graph.initialize_from_game(self.game.root)
|
||||||
|
self.controls.rank_graph.initialize_from_game(self.game.root)
|
||||||
self.update_state(redraw_board=True)
|
self.update_state(redraw_board=True)
|
||||||
|
|
||||||
def _do_ai_move(self, node=None):
|
def _do_ai_move(self, node=None):
|
||||||
|
|||||||
+17
-7
@@ -101,12 +101,15 @@ class KataGoEngine:
|
|||||||
self.shutdown(finish=False)
|
self.shutdown(finish=False)
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def check_alive(self, exception_if_dead=False):
|
def check_alive(self, os_error='', exception_if_dead=False):
|
||||||
ok = self.katago_process and self.katago_process.poll() is None
|
ok = self.katago_process and self.katago_process.poll() is None
|
||||||
if not ok and exception_if_dead:
|
if not ok and exception_if_dead:
|
||||||
raise EngineDiedException(
|
if self.katago_process:
|
||||||
f"Engine died (process {self.katago_process}, poll {self.katago_process and self.katago_process.poll()}) config {self.config}"
|
os_error += f"status {self.katago_process and self.katago_process.poll()}"
|
||||||
)
|
died_msg = i18n._("Engine died unexpectedly").format(error=os_error)
|
||||||
|
self.katrain.log(died_msg, OUTPUT_ERROR)
|
||||||
|
self.katago_process = None
|
||||||
|
raise EngineDiedException(died_msg)
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def shutdown(self, finish=False):
|
def shutdown(self, finish=False):
|
||||||
@@ -134,15 +137,22 @@ class KataGoEngine:
|
|||||||
self.katrain.log(line.decode(errors="ignore").strip(), OUTPUT_KATAGO_STDERR)
|
self.katrain.log(line.decode(errors="ignore").strip(), OUTPUT_KATAGO_STDERR)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("ERROR in processing KataGo stderr:", line, "Exception", e)
|
print("ERROR in processing KataGo stderr:", line, "Exception", e)
|
||||||
except:
|
else:
|
||||||
|
self.check_alive(exception_if_dead=True)
|
||||||
|
except Exception as e:
|
||||||
|
self.katrain.log(f"Exception in reading stdout {e}" , OUTPUT_DEBUG)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _analysis_read_thread(self):
|
def _analysis_read_thread(self):
|
||||||
while self.katago_process is not None:
|
while self.katago_process is not None:
|
||||||
try:
|
try:
|
||||||
line = self.katago_process.stdout.readline()
|
line = self.katago_process.stdout.readline()
|
||||||
|
if not line:
|
||||||
|
self.check_alive(exception_if_dead=True)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise EngineDiedException(i18n("Engine died unexpectedly").format(error=e))
|
self.check_alive(os_error=str(e),exception_if_dead=True)
|
||||||
|
return
|
||||||
|
|
||||||
if b"Uncaught exception" in line:
|
if b"Uncaught exception" in line:
|
||||||
self.katrain.log(f"KataGo Engine Failed: {line.decode(errors='ignore')}", OUTPUT_ERROR)
|
self.katrain.log(f"KataGo Engine Failed: {line.decode(errors='ignore')}", OUTPUT_ERROR)
|
||||||
return
|
return
|
||||||
@@ -193,7 +203,7 @@ class KataGoEngine:
|
|||||||
self.katago_process.stdin.write((json.dumps(query) + "\n").encode())
|
self.katago_process.stdin.write((json.dumps(query) + "\n").encode())
|
||||||
self.katago_process.stdin.flush()
|
self.katago_process.stdin.flush()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self.katrain.log(i18n._("Engine died unexpectedly").format(error=e), OUTPUT_ERROR)
|
self.check_alive(os_error=str(e),exception_if_dead=True)
|
||||||
return # do not raise, since there's nothing to catch it
|
return # do not raise, since there's nothing to catch it
|
||||||
|
|
||||||
def request_analysis(
|
def request_analysis(
|
||||||
|
|||||||
+18
-8
@@ -7,10 +7,18 @@ from typing import Dict, List, Optional, Union
|
|||||||
|
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
|
||||||
from katrain.core.constants import HOMEPAGE, OUTPUT_DEBUG, OUTPUT_INFO, STATUS_ANALYSIS, STATUS_INFO, STATUS_TEACHING
|
from katrain.core.constants import (
|
||||||
|
HOMEPAGE,
|
||||||
|
OUTPUT_DEBUG,
|
||||||
|
OUTPUT_INFO,
|
||||||
|
STATUS_ANALYSIS,
|
||||||
|
STATUS_INFO,
|
||||||
|
STATUS_TEACHING,
|
||||||
|
PLAYER_AI,
|
||||||
|
)
|
||||||
from katrain.core.engine import KataGoEngine
|
from katrain.core.engine import KataGoEngine
|
||||||
from katrain.core.game_node import GameNode
|
from katrain.core.game_node import GameNode
|
||||||
from katrain.core.lang import i18n
|
from katrain.core.lang import i18n, rank_label
|
||||||
from katrain.core.sgf_parser import SGF, Move
|
from katrain.core.sgf_parser import SGF, Move
|
||||||
from katrain.core.utils import var_to_grid
|
from katrain.core.utils import var_to_grid
|
||||||
|
|
||||||
@@ -270,12 +278,14 @@ class Game:
|
|||||||
def player_name(player_info):
|
def player_name(player_info):
|
||||||
return f"{i18n._(player_info.player_type)} ({i18n._(player_info.player_subtype)})"
|
return f"{i18n._(player_info.player_type)} ({i18n._(player_info.player_subtype)})"
|
||||||
|
|
||||||
player_names = {
|
if "KaTrain" in self.root.get_property("AP", ""):
|
||||||
bw: re.sub(
|
for bw in "BW":
|
||||||
r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw) or player_name(self.katrain.players_info[bw])
|
self.root.set_property("P" + bw, player_name(self.katrain.players_info[bw]))
|
||||||
)
|
player_info = self.katrain.players_info[bw]
|
||||||
for bw in "BW"
|
if player_info.player_type == PLAYER_AI:
|
||||||
}
|
self.root.set_property(bw + "R", rank_label(player_info.calculated_rank))
|
||||||
|
|
||||||
|
player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P" + bw, 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)
|
||||||
|
|||||||
@@ -85,4 +85,4 @@ def rank_label(rank):
|
|||||||
if rank > 0:
|
if rank > 0:
|
||||||
return f"{rank:.0f}{i18n._('strength:dan')}"
|
return f"{rank:.0f}{i18n._('strength:dan')}"
|
||||||
else:
|
else:
|
||||||
return f"{1-rank:.0f}{i18n._('strength:kyu')}"
|
return f"{1-rank:.0f}{i18n._('strength:kyu')}"
|
||||||
@@ -31,8 +31,8 @@ EVAL_COLORS = [
|
|||||||
[0.8, 0, 0, 1],
|
[0.8, 0, 0, 1],
|
||||||
[0.9, 0.4, 0.1, 1],
|
[0.9, 0.4, 0.1, 1],
|
||||||
[0.85, 0.89, 0.3, 1],
|
[0.85, 0.89, 0.3, 1],
|
||||||
[0.67, 0.9, 0.18, 1.0],
|
[0.67, 0.9, 0.18, 1],
|
||||||
[0.117, 0.588, 0, 1.0],
|
[0.117, 0.588, 0, 1],
|
||||||
]
|
]
|
||||||
EVAL_DOT_MAX_SIZE = 0.5
|
EVAL_DOT_MAX_SIZE = 0.5
|
||||||
EVAL_DOT_MIN_SIZE = 0.25
|
EVAL_DOT_MIN_SIZE = 0.25
|
||||||
|
|||||||
@@ -4,23 +4,25 @@ import threading
|
|||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
from kivy.metrics import dp
|
from kivy.metrics import dp
|
||||||
from kivy.properties import BooleanProperty, Clock, ListProperty, NumericProperty, StringProperty
|
from kivy.properties import BooleanProperty, Clock, ListProperty, NumericProperty, StringProperty
|
||||||
|
from kivy.uix.widget import Widget
|
||||||
from kivymd.app import MDApp
|
from kivymd.app import MDApp
|
||||||
|
|
||||||
from katrain.core.constants import OUTPUT_ERROR
|
from katrain.core.constants import OUTPUT_ERROR
|
||||||
from katrain.core.lang import rank_label
|
from katrain.core.lang import rank_label
|
||||||
from katrain.gui.kivyutils import BackgroundMixin
|
|
||||||
|
|
||||||
|
|
||||||
class Graph(BackgroundMixin):
|
class Graph(Widget):
|
||||||
marker_font_size = NumericProperty(0)
|
marker_font_size = NumericProperty(0)
|
||||||
background_image = StringProperty("img/graph_bg.png")
|
background_image = StringProperty("img/graph_bg.png")
|
||||||
|
background_color = ListProperty([1, 1, 1, 1])
|
||||||
|
highlighted_index = NumericProperty(0)
|
||||||
nodes = ListProperty([])
|
nodes = ListProperty([])
|
||||||
hidden = BooleanProperty(False)
|
hidden = BooleanProperty(False)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.Lock()
|
||||||
|
self.redraw_on_highlight_change = True
|
||||||
self.bind(pos=self.update_graph, size=self.update_graph)
|
self.bind(pos=self.update_graph, size=self.update_graph)
|
||||||
self.redraw_trigger = Clock.create_trigger(self.update_graph, 0.1)
|
self.redraw_trigger = Clock.create_trigger(self.update_graph, 0.1)
|
||||||
|
|
||||||
@@ -31,19 +33,24 @@ class Graph(BackgroundMixin):
|
|||||||
node = node.ordered_children[0]
|
node = node.ordered_children[0]
|
||||||
self.nodes.append(node)
|
self.nodes.append(node)
|
||||||
self.highlighted_index = 0
|
self.highlighted_index = 0
|
||||||
|
self.redraw_trigger()
|
||||||
|
|
||||||
def update_graph(self, *args):
|
def update_graph(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def update_value(self, node):
|
def update_value(self, node):
|
||||||
with self._lock:
|
with self._lock:
|
||||||
|
changed = (self.redraw_on_highlight_change and self.highlighted_index != node.depth)
|
||||||
self.highlighted_index = index = node.depth
|
self.highlighted_index = index = node.depth
|
||||||
self.nodes.extend([None] * max(0, index - (len(self.nodes) - 1)))
|
self.nodes.extend([None] * max(0, index - (len(self.nodes) - 1)))
|
||||||
|
if self.nodes[index]!=node:
|
||||||
|
changed=True
|
||||||
self.nodes[index] = node
|
self.nodes[index] = node
|
||||||
if index > 1 and node.parent: # sometimes things go so fast
|
if index > 1 and node.parent: # sometimes there are gaps
|
||||||
backfill, bfnode = index - 1, node.parent
|
backfill, bfnode = index - 1, node.parent
|
||||||
while bfnode is not None and self.nodes[backfill] != bfnode:
|
while bfnode is not None and self.nodes[backfill] != bfnode:
|
||||||
self.nodes[backfill] = bfnode
|
self.nodes[backfill] = bfnode
|
||||||
|
changed = True
|
||||||
backfill -= 1
|
backfill -= 1
|
||||||
bfnode = bfnode.parent
|
bfnode = bfnode.parent
|
||||||
|
|
||||||
@@ -51,11 +58,13 @@ class Graph(BackgroundMixin):
|
|||||||
node is None or not node.children or self.nodes[index + 1] != node.ordered_children[0]
|
node is None or not node.children or self.nodes[index + 1] != node.ordered_children[0]
|
||||||
):
|
):
|
||||||
self.nodes = self.nodes[: index + 1] # on branch switching, don't show history from other branch
|
self.nodes = self.nodes[: index + 1] # on branch switching, don't show history from other branch
|
||||||
|
changed = True
|
||||||
if index == len(self.nodes) - 1: # possibly just switched branch or the line above triggered
|
if index == len(self.nodes) - 1: # possibly just switched branch or the line above triggered
|
||||||
while node.children: # add children back
|
while node.children: # add children back
|
||||||
node = node.ordered_children[0]
|
node = node.ordered_children[0]
|
||||||
self.nodes.append(node)
|
self.nodes.append(node)
|
||||||
self.redraw_trigger()
|
if changed:
|
||||||
|
self.redraw_trigger()
|
||||||
|
|
||||||
|
|
||||||
class ScoreGraph(Graph):
|
class ScoreGraph(Graph):
|
||||||
@@ -67,7 +76,6 @@ class ScoreGraph(Graph):
|
|||||||
|
|
||||||
score_dot_pos = ListProperty([0, 0])
|
score_dot_pos = ListProperty([0, 0])
|
||||||
winrate_dot_pos = ListProperty([0, 0])
|
winrate_dot_pos = ListProperty([0, 0])
|
||||||
highlighted_index = NumericProperty(None)
|
|
||||||
highlight_size = NumericProperty(dp(6))
|
highlight_size = NumericProperty(dp(6))
|
||||||
|
|
||||||
score_scale = NumericProperty(5)
|
score_scale = NumericProperty(5)
|
||||||
@@ -173,9 +181,11 @@ class RankGraph(Graph):
|
|||||||
black_rank_points = ListProperty([])
|
black_rank_points = ListProperty([])
|
||||||
white_rank_points = ListProperty([])
|
white_rank_points = ListProperty([])
|
||||||
segment_length = NumericProperty(80)
|
segment_length = NumericProperty(80)
|
||||||
|
RANK_CAP = 5
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
self.redraw_on_highlight_change = False
|
||||||
self.calculate_trigger = Clock.create_trigger(lambda *args: self.rank_game(), 0.25)
|
self.calculate_trigger = Clock.create_trigger(lambda *args: self.rank_game(), 0.25)
|
||||||
self.rank_by_player = {}
|
self.rank_by_player = {}
|
||||||
|
|
||||||
@@ -189,11 +199,7 @@ class RankGraph(Graph):
|
|||||||
if not non_obvious_moves:
|
if not non_obvious_moves:
|
||||||
return None
|
return None
|
||||||
num_legal, rank, value = zip(*non_obvious_moves)
|
num_legal, rank, value = zip(*non_obvious_moves)
|
||||||
rank = list(rank)
|
rank = [min(r, nl * 0.09) for r, nl in zip(rank, num_legal)]
|
||||||
for (i, item) in enumerate(rank):
|
|
||||||
if item > num_legal[i] * 0.09:
|
|
||||||
rank[i] = num_legal[i] * 0.09
|
|
||||||
rank = tuple(rank)
|
|
||||||
averagemod_rank = averagemod(rank)
|
averagemod_rank = averagemod(rank)
|
||||||
averagemod_len_legal = averagemod(num_legal)
|
averagemod_len_legal = averagemod(num_legal)
|
||||||
norm_avemod_len_legal = averagemod_len_legal / num_intersec
|
norm_avemod_len_legal = averagemod_len_legal / num_intersec
|
||||||
@@ -209,9 +215,7 @@ class RankGraph(Graph):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
rank_kyu = -4
|
rank_kyu = -4
|
||||||
if rank_kyu < -4:
|
return min(RankGraph.RANK_CAP,1 - rank_kyu) # dan rank
|
||||||
rank_kyu = -4
|
|
||||||
return 1 - rank_kyu # dan rank
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def calculate_ranks(segment_stats, num_intersec):
|
def calculate_ranks(segment_stats, num_intersec):
|
||||||
@@ -241,10 +245,11 @@ class RankGraph(Graph):
|
|||||||
|
|
||||||
ranks = {"B": [], "W": []}
|
ranks = {"B": [], "W": []}
|
||||||
dx = self.segment_length // 4
|
dx = self.segment_length // 4
|
||||||
for segment_mid in range(0, len(nodes), dx):
|
for segment_mid in range(dx, len(nodes), dx):
|
||||||
bounds = (max(0, segment_mid - half_seg), min(segment_mid + half_seg, len(nodes)))
|
bounds = (max(0, segment_mid - half_seg), min(segment_mid + half_seg, len(nodes)))
|
||||||
for pl, rank in self.calculate_ranks(policy_stats[bounds[0] : bounds[1] + 1], num_intersec).items():
|
num_analyzed = sum(num_mv is not None for num_mv, _, _, _ in policy_stats[bounds[0] : bounds[1] + 1])
|
||||||
if bounds[1] - bounds[0] > self.segment_length * 0.75:
|
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))
|
ranks[pl].append((segment_mid, rank))
|
||||||
self.rank_by_player = ranks
|
self.rank_by_player = ranks
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -270,15 +275,17 @@ class RankGraph(Graph):
|
|||||||
|
|
||||||
min_rank = math.floor(min(all_ranks))
|
min_rank = math.floor(min(all_ranks))
|
||||||
max_rank = math.ceil(max(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 (max_rank - min_rank) % 2 != 0: # make midpoint whole integer
|
||||||
if abs(max_rank - max(all_ranks)) < abs(min(all_ranks) - min_rank):
|
if abs(max_rank - max(all_ranks)) < abs(min(all_ranks) - min_rank) and max_rank < self.RANK_CAP:
|
||||||
max_rank += 1
|
max_rank += 1
|
||||||
else:
|
else:
|
||||||
min_rank -= 1
|
min_rank -= 1
|
||||||
rank_range = max_rank - min_rank
|
rank_range = max_rank - min_rank
|
||||||
|
|
||||||
self.ids.mid_marker.text = rank_label((max_rank + min_rank) / 2)
|
self.ids.mid_marker.text = rank_label((max_rank + min_rank) / 2)
|
||||||
self.ids.top_marker.text = rank_label(max_rank)
|
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)
|
self.ids.bottom_marker.text = rank_label(min_rank)
|
||||||
|
|
||||||
graph_points = {}
|
graph_points = {}
|
||||||
@@ -292,12 +299,16 @@ class RankGraph(Graph):
|
|||||||
]
|
]
|
||||||
self.black_rank_points = sum(graph_points["B"], [])
|
self.black_rank_points = sum(graph_points["B"], [])
|
||||||
self.white_rank_points = sum(graph_points["W"], [])
|
self.white_rank_points = sum(graph_points["W"], [])
|
||||||
|
else:
|
||||||
|
self.black_rank_points = []
|
||||||
|
self.white_rank_points = []
|
||||||
|
|
||||||
Builder.load_string(
|
Builder.load_string(
|
||||||
"""
|
"""
|
||||||
#:set GRAPH_CENTER_COLOR [0.5,0.5,0.5]
|
#:set GRAPH_CENTER_COLOR [0.5,0.5,0.5]
|
||||||
#:set GRAPH_DOT_COLOR [0.85, 0.3, 0.3,1]
|
#:set GRAPH_DOT_COLOR [0.85,0.3,0.3,1]
|
||||||
|
#:set WINRATE_MARKER_COLOR [0.05, 0.7, 0.05, 1]
|
||||||
|
#:set SCORE_MARKER_COLOR [0.2, 0.6, 0.8, 1]
|
||||||
|
|
||||||
#:import LIGHTER_BACKGROUND_COLOR katrain.gui.style.LIGHTER_BACKGROUND_COLOR
|
#:import LIGHTER_BACKGROUND_COLOR katrain.gui.style.LIGHTER_BACKGROUND_COLOR
|
||||||
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
|
#:import BOX_BACKGROUND_COLOR katrain.gui.style.BOX_BACKGROUND_COLOR
|
||||||
@@ -307,11 +318,15 @@ Builder.load_string(
|
|||||||
#:import WHITE katrain.gui.style.WHITE
|
#:import WHITE katrain.gui.style.WHITE
|
||||||
#:import YELLOW katrain.gui.style.YELLOW
|
#:import YELLOW katrain.gui.style.YELLOW
|
||||||
|
|
||||||
|
|
||||||
<Graph>:
|
<Graph>:
|
||||||
background_color: BOX_BACKGROUND_COLOR
|
background_color: BOX_BACKGROUND_COLOR
|
||||||
marker_font_size: 0.1 * self.height
|
marker_font_size: 0.1 * self.height
|
||||||
canvas:
|
canvas.before:
|
||||||
|
Color:
|
||||||
|
rgba: root.background_color
|
||||||
|
Rectangle:
|
||||||
|
size: self.size
|
||||||
|
pos: self.pos
|
||||||
Color:
|
Color:
|
||||||
rgba: [1,1,1,1]
|
rgba: [1,1,1,1]
|
||||||
Rectangle:
|
Rectangle:
|
||||||
@@ -320,7 +335,7 @@ Builder.load_string(
|
|||||||
source: root.background_image
|
source: root.background_image
|
||||||
|
|
||||||
<ScoreGraph>:
|
<ScoreGraph>:
|
||||||
canvas.after:
|
canvas:
|
||||||
Color:
|
Color:
|
||||||
rgba: SCORE_COLOR
|
rgba: SCORE_COLOR
|
||||||
Line:
|
Line:
|
||||||
@@ -351,39 +366,39 @@ Builder.load_string(
|
|||||||
# score ticks
|
# score ticks
|
||||||
GraphMarkerLabel:
|
GraphMarkerLabel:
|
||||||
font_size: root.marker_font_size
|
font_size: root.marker_font_size
|
||||||
color: SCORE_COLOR
|
color: SCORE_MARKER_COLOR
|
||||||
pos: root.x + root.width - self.width-1, root.pos[1]+root.height - self.font_size - 1
|
pos: root.x + root.width - self.width-1, root.pos[1]+root.height - self.font_size - 1
|
||||||
text: 'B+{}'.format(root.score_scale)
|
text: 'B+{}'.format(root.score_scale)
|
||||||
opacity: int(root.show_score)
|
opacity: int(root.show_score)
|
||||||
GraphMarkerLabel:
|
GraphMarkerLabel:
|
||||||
font_size: root.marker_font_size
|
font_size: root.marker_font_size
|
||||||
color: SCORE_COLOR
|
color: SCORE_MARKER_COLOR
|
||||||
pos: root.x + root.width - self.width-1, root.y + root.height*0.5 - self.height/2 + 2
|
pos: root.x + root.width - self.width-1, root.y + root.height*0.5 - self.height/2 + 2
|
||||||
text: i18n._('Jigo')
|
text: i18n._('Jigo')
|
||||||
opacity: int(root.show_score)
|
opacity: int(root.show_score)
|
||||||
GraphMarkerLabel:
|
GraphMarkerLabel:
|
||||||
font_size: root.marker_font_size
|
font_size: root.marker_font_size
|
||||||
color: SCORE_COLOR
|
color: SCORE_MARKER_COLOR
|
||||||
pos: root.x + root.width - self.width-1, root.pos[1]
|
pos: root.x + root.width - self.width-1, root.pos[1]
|
||||||
text: 'W+' + str(int(root.score_scale))
|
text: 'W+' + str(int(root.score_scale))
|
||||||
opacity: int(root.show_score)
|
opacity: int(root.show_score)
|
||||||
# wr ticks
|
# wr ticks
|
||||||
GraphMarkerLabel:
|
GraphMarkerLabel:
|
||||||
font_size: root.marker_font_size
|
font_size: root.marker_font_size
|
||||||
color: WINRATE_COLOR
|
color: WINRATE_MARKER_COLOR
|
||||||
pos: root.pos[0]+1, root.pos[1] + root.height - self.font_size - 1
|
pos: root.pos[0]+1, root.pos[1] + root.height - self.font_size - 1
|
||||||
text: "{}%".format(50 + root.winrate_scale)
|
text: "{}%".format(50 + root.winrate_scale)
|
||||||
opacity: int(root.show_winrate)
|
opacity: int(root.show_winrate)
|
||||||
GraphMarkerLabel:
|
GraphMarkerLabel:
|
||||||
font_size: root.marker_font_size
|
font_size: root.marker_font_size
|
||||||
color: WINRATE_COLOR
|
color: WINRATE_MARKER_COLOR
|
||||||
pos:root.pos[0]+1, root.pos[1]
|
pos:root.pos[0]+1, root.pos[1]
|
||||||
text: "{}%".format(50 - root.winrate_scale)
|
text: "{}%".format(50 - root.winrate_scale)
|
||||||
opacity: int(root.show_winrate)
|
opacity: int(root.show_winrate)
|
||||||
|
|
||||||
<RankGraph>:
|
<RankGraph>:
|
||||||
background_color: LIGHTER_BACKGROUND_COLOR
|
background_color: LIGHTER_BACKGROUND_COLOR
|
||||||
canvas.after:
|
canvas:
|
||||||
Color:
|
Color:
|
||||||
rgba: WHITE
|
rgba: WHITE
|
||||||
Line:
|
Line:
|
||||||
|
|||||||
@@ -635,4 +635,3 @@ msgstr "Estimated Strength"
|
|||||||
#. TODO - label in little popup for analyzing entire game
|
#. TODO - label in little popup for analyzing entire game
|
||||||
msgid "reanalyze max visits"
|
msgid "reanalyze max visits"
|
||||||
msgstr "Number of visits per move"
|
msgstr "Number of visits per move"
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.2 KiB |
Reference in new issue
Block a user