tsumego solver 5000 is go

This commit is contained in:
Sander Land committed 2020-12-03 22:09:46 +01:00
1 parent da42fc4e0f
commit 0ade2524ce
27 files changed
+252 -83

No files matched your search

+1 -1
View File
@@ -5,7 +5,7 @@ For on related licenses for these binaries and libraries see https://github.com/
2. Icons from www.flaticon.com, used with permission with the following attributions:
- Equalize icon and Thrash Icon: derived from work by bqlqn from www.flaticon.com
- Local search icon: derived from work by Pixel Perfect from www.flaticon.com
- Local search icon, Insert icon: derived from work by Pixel Perfect from www.flaticon.com
- Other Menu icons and Flag icons: derived from work by Freepik from www.flaticon.com
3. The True Type Font DIGITAL-7 version 1.02 by Sizenko Alexander, which is free for non-commercial use.
+3 -2
View File
@@ -101,12 +101,13 @@ for lang in locales:
print("Fixed", pofile[lang], "and converted ->", mofile)
for file in glob.glob("katrain/**/*.py") + glob.glob("katrain/**/*.kv"):
for file in glob.glob("**/*.py") + glob.glob("**/*.kv"):
with open(file, "r") as f:
for i, line in enumerate(f.readlines()):
matches = [m.strip() for m in re.findall(r"i18n._\((.*?)\)", line)]
for msgid in matches:
if msgid[0] in ['"', "'"] and msgid.strip("\"'") not in strings_to_langs: # not code
stripped_msgid = msgid.strip("\"'")
if stripped_msgid and msgid[0] in ['"', "'"] and stripped_msgid not in strings_to_langs: # not code
print(f"Missing {msgid} used in code at \t{file}:{i} \t'{line.strip()}'")
errors += 1
+5 -1
View File
@@ -324,6 +324,10 @@ class KaTrainGui(Screen, KaTrainBase):
def _do_analyze_extra(self, mode, **kwargs):
self.game.analyze_extra(mode, **kwargs)
def _do_select_box(self):
self.controls.set_status(i18n._("analysis:region:start"), STATUS_INFO)
self.board_gui.selecting_region_of_interest = True
def _do_new_game_popup(self):
self.controls.timer.paused = True
if not self.new_game_popup:
@@ -489,7 +493,7 @@ class KaTrainGui(Screen, KaTrainBase):
"s": ("analyze-extra", "equalize"),
"d": ("analyze-extra", "sweep"),
"f": ("analyze-extra", "alternative"),
"g": ("analyze-extra", "local"),
"g": ("select-box",),
"i": ("insert-mode",),
"p": ("play", None),
"n": ("next-mistake",),
+9 -10
View File
@@ -6,7 +6,7 @@ import subprocess
import threading
import time
import traceback
from typing import Callable, Dict, Optional
from typing import Callable, Dict, Optional, List
from kivy.utils import platform
@@ -112,6 +112,7 @@ class KataGoEngine:
self.terminate_query(query_id)
self.queries = {}
def restart(self):
self.queries = {}
self.shutdown(finish=False)
@@ -249,7 +250,7 @@ class KataGoEngine:
analyze_fast: bool = False,
time_limit=True,
find_alternatives: bool = False,
find_local: bool = False,
region_of_interest: Optional[List] = None,
priority: int = 0,
ownership: Optional[bool] = None,
next_move: Optional[GameNode] = None,
@@ -278,22 +279,20 @@ class KataGoEngine:
"untilDepth": 1,
}
]
elif find_local:
distance = 5
last_move = analysis_node.move
if last_move is None or last_move.is_pass:
return
elif region_of_interest:
xmin, xmax, ymin, ymax = region_of_interest
avoid = [
{
"moves": [
Move((x, y)).gtp()
for x in range(0, size_x)
for y in range(0, size_y)
if max(abs(x - last_move.coords[0]), abs(y - last_move.coords[1])) > distance
if x < xmin or x > xmax or y < ymin or y > ymax
],
"player": analysis_node.next_player,
"untilDepth": 1,
"player": player,
"untilDepth": 10000,
}
for player in "BW"
]
else:
avoid = []
+19 -6
View File
@@ -62,6 +62,8 @@ class Game:
self.insert_mode = False
self.insert_after = None
self.region_of_interest = None
if move_tree:
self.root = move_tree
self.komi = self.root.komi
@@ -233,7 +235,11 @@ class Game:
played_node = self.current_node.play(move)
self.current_node = played_node
if analyze:
played_node.analyze(self.engines[played_node.next_player])
if self.region_of_interest:
played_node.analyze(self.engines[played_node.next_player],analyze_fast=True)
played_node.analyze(self.engines[played_node.next_player],region_of_interest=self.region_of_interest)
else:
played_node.analyze(self.engines[played_node.next_player])
return played_node
def set_current_node(self, node):
@@ -410,6 +416,17 @@ class Game:
f.write(sgf)
return i18n._("sgf written").format(file_name=filename)
def set_region_of_interest(self,region_of_interest):
x1, x2, y1, y2 =region_of_interest
xmin, xmax = min(x1, x2), max(x1, x2)
ymin, ymax = min(y1, y2), max(y1, y2)
if not (xmin==xmax and ymin==ymax):
self.region_of_interest = [xmin,xmax,ymin,ymax]
else:
self.region_of_interest = None
self.katrain.controls.set_status("",OUTPUT_INFO)
def analyze_extra(self, mode, **kwargs):
stones = {s.coords for s in self.stones}
cn = self.current_node
@@ -426,7 +443,7 @@ class Game:
visits = cn.analysis_visits_requested + engine.config["max_visits"]
self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS)
self.katrain.controls.set_status(i18n._("extra analysis").format(visits=visits), STATUS_ANALYSIS)
cn.analyze(engine, visits=visits, priority=-1_000, time_limit=False)
cn.analyze(engine, visits=visits, priority=-1_000, region_of_interest=self.region_of_interest, time_limit=False)
return
if mode == "game":
nodes = self.root.nodes_in_tree
@@ -467,10 +484,6 @@ class Game:
visits = engine.config["fast_visits"]
self.katrain.controls.set_status(i18n._("sweep analysis").format(visits=visits), STATUS_ANALYSIS)
priority = -1_000_000_000
elif mode == "local": # also do a quick update on current candidates so it doesn't look too weird
self.katrain.controls.set_status(i18n._("local analysis"), STATUS_ANALYSIS)
cn.analyze(engine, priority=-500, time_limit=False, find_local="local")
return
elif mode in ["equalize", "alternative", "local"]:
if not cn.analysis_complete and mode != "local":
self.katrain.controls.set_status(i18n._("wait-before-equalize"), STATUS_INFO, self.current_node)
+4 -3
View File
@@ -145,13 +145,14 @@ class GameNode(SGFNode):
refine_move=None,
analyze_fast=False,
find_alternatives=False,
find_local=False,
region_of_interest = None,
report_every=0.25,
):
additional_moves = bool(find_alternatives or region_of_interest)
engine.request_analysis(
self,
callback=lambda result, partial_result: self.set_analysis(
result, refine_move, find_alternatives or find_local, partial_result
result, refine_move, additional_moves, partial_result
),
priority=priority,
visits=visits,
@@ -159,7 +160,7 @@ class GameNode(SGFNode):
time_limit=time_limit,
next_move=refine_move,
find_alternatives=find_alternatives,
find_local=find_local,
region_of_interest=region_of_interest,
report_every=report_every,
)
+3 -3
View File
@@ -751,13 +751,13 @@
shortcut: 'f'
on_action: root.katrain("analyze-extra", "alternative")
AnalysisMenuItem:
text: i18n._("analysis:local")
text: i18n._("analysis:region")
icon: 'img/local.png'
shortcut: 'g'
on_action: root.katrain("analyze-extra", "local")
on_action: root.katrain("select-box",)
AnalysisMenuItem:
text: i18n._("analysis:insert")
icon: 'img/local.png'
icon: 'img/insert.png'
shortcut: 'i'
on_action: root.katrain("insert-mode")
AnalysisMenuItem:
+70 -19
View File
@@ -48,6 +48,9 @@ class BadukPanWidget(Widget):
self.gridpos_y = []
self.grid_size = 0
self.stone_size = 0
self.selecting_region_of_interest = False
self.region_of_interest = []
self.active_pv_moves = []
self.animating_pv = None
self.last_mouse_pos = (0, 0)
@@ -57,6 +60,12 @@ class BadukPanWidget(Widget):
self.bind(size=self.redraw_trigger, pos=self.redraw_trigger)
Clock.schedule_interval(self.animate_pv, 0.1)
def play_stone_sound(self, *_args):
if self.katrain.config("timer/sound"):
sound = random.choice(self.stones_sounds)
if sound:
sound.play()
# stone placement functions
def _find_closest(self, pos, gridpos):
return sorted([(abs(p - pos), i) for i, p in enumerate(gridpos)])[0]
@@ -74,23 +83,42 @@ class BadukPanWidget(Widget):
if prev_ghost != self.ghost_stone:
self.draw_hover_contents()
def update_box_selection(self, touch, second_point=True):
if not self.gridpos_x:
return
_, xp = self._find_closest(touch.x, self.gridpos_x)
_, yp = self._find_closest(touch.y, self.gridpos_y)
if second_point and len(self.region_of_interest) == 4:
self.region_of_interest[1] = xp
self.region_of_interest[3] = yp
else:
self.region_of_interest = [xp, xp, yp, yp]
self.draw_hover_contents()
def on_touch_down(self, touch):
self.set_animating_pv(None, None) # any click kills PV from label/move
if "button" in touch.profile and touch.button != "left":
return
self.check_next_move_ghost(touch)
if self.selecting_region_of_interest:
self.update_box_selection(touch, second_point=False)
else:
self.check_next_move_ghost(touch)
def on_touch_move(self, touch):
if "button" in touch.profile and touch.button != "left":
return
return self.check_next_move_ghost(touch)
if self.selecting_region_of_interest:
return self.update_box_selection(touch)
else:
return self.check_next_move_ghost(touch)
def on_mouse_pos(self, *args): # https://gist.github.com/opqopq/15c707dc4cffc2b6455f
if self.get_root_window(): # don't proceed if I'm not displayed <=> If have no parent
pos = args[1]
rel_pos = self.to_widget(*pos) # compensate for relative layout
inside = self.collide_point(*rel_pos)
if inside and self.active_pv_moves:
if inside and self.active_pv_moves and not self.selecting_region_of_interest:
near_move = [
(pv, node)
for move, pv, node in self.active_pv_moves
@@ -109,17 +137,17 @@ class BadukPanWidget(Widget):
self.set_animating_pv(None, None) # any click kills PV from label/move
self.last_mouse_pos = pos
def play_stone_sound(self, *_args):
if self.katrain.config("timer/sound"):
sound = random.choice(self.stones_sounds)
if sound:
sound.play()
def on_touch_up(self, touch):
if ("button" in touch.profile and touch.button != "left") or not self.gridpos_x:
return
katrain = self.katrain
if self.ghost_stone and ("button" not in touch.profile or touch.button == "left"):
if self.selecting_region_of_interest:
if len(self.region_of_interest) == 4:
self.katrain.game.set_region_of_interest(self.region_of_interest)
self.region_of_interest = []
self.selecting_region_of_interest = False
elif self.ghost_stone and ("button" not in touch.profile or touch.button == "left"):
game = self.katrain and self.katrain.game
current_node = game and self.katrain.game.current_node
if (
@@ -429,6 +457,20 @@ class BadukPanWidget(Widget):
self.draw_hover_contents()
def draw_roi_box(self,region_of_interest,width=2):
xmin, xmax, ymin, ymax = region_of_interest
Color(*LIGHTER_BACKGROUND_COLOR)
Line(
rectangle=(
self.gridpos_x[xmin] - self.grid_size/6,
self.gridpos_y[ymin] - self.grid_size/6,
(xmax - xmin + 1/3) * self.grid_size,
(ymax - ymin + 1/3) * self.grid_size,
),
dash_length=10,dash_offset=10,
width=width,
)
def draw_hover_contents(self, *_args):
ghost_alpha = POLICY_ALPHA
katrain = self.katrain
@@ -442,6 +484,7 @@ class BadukPanWidget(Widget):
with self.canvas.after:
self.canvas.after.clear()
self.active_pv_moves = []
# hints or PV
hint_moves = []
@@ -582,16 +625,24 @@ class BadukPanWidget(Widget):
width=dp(1.2),
)
# hover next move ghost stone
if self.ghost_stone:
self.draw_stone(*self.ghost_stone, next_player, alpha=ghost_alpha)
if self.selecting_region_of_interest and len(self.region_of_interest) == 4:
x1, x2, y1, y2 = self.region_of_interest
self.draw_roi_box([min(x1, x2), max(x1, x2), min(y1, y2), max(y1, y2)],width=2)
else:
# hover next move ghost stone
if self.ghost_stone:
self.draw_stone(*self.ghost_stone, next_player, alpha=ghost_alpha)
animating_pv = self.animating_pv
if animating_pv:
pv, node, start_time, _ = animating_pv
delay = self.katrain.config("general/anim_pv_time", 0.5)
up_to_move = (time.time() - start_time) / delay
self.draw_pv(pv, node, up_to_move)
if self.katrain.game.region_of_interest:
self.draw_roi_box(self.katrain.game.region_of_interest, width=1) # dashed
animating_pv = self.animating_pv
if animating_pv:
pv, node, start_time, _ = animating_pv
delay = self.katrain.config("general/anim_pv_time", 0.5)
up_to_move = (time.time() - start_time) / delay
self.draw_pv(pv, node, up_to_move)
def animate_pv(self, _dt):
if self.animating_pv:
Binary file not shown.
+17 -3
View File
@@ -657,9 +657,6 @@ msgstr ""
msgid "ai:simple"
msgstr "简明风格"
msgid "analysis:local"
msgstr "寻找局部走法"
msgid "local analysis"
msgstr "正在寻找局部走法"
@@ -739,3 +736,20 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+17 -3
View File
@@ -707,9 +707,6 @@ msgstr ""
msgid "ai:simple"
msgstr "Einfacher Stil"
msgid "analysis:local"
msgstr "Finde lokale Antworten"
msgid "local analysis"
msgstr "Suche nach lokalen Antworten"
@@ -791,3 +788,20 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+16 -3
View File
@@ -109,9 +109,14 @@ msgstr "Deeper full game analysis"
msgid "analysis:alternatives"
msgstr "Find alternative moves"
#. Analyze again but allow only nearby moves
msgid "analysis:local"
msgstr "Find local responses"
#. Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
#. Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. Keep improving current position analysis when there is nothing else to do
msgid "analysis:continuous"
@@ -120,6 +125,10 @@ msgstr "Toggle continuous analysis"
msgid "analysis:aimove"
msgstr "Force AI Move"
#. Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. status message
msgid "extra analysis"
msgstr "Performing additional analysis to {visits} visits"
@@ -343,6 +352,10 @@ msgstr "Update Timer"
msgid "New Game title"
msgstr "Setup New Game"
#. in new game options
msgid "player names"
msgstr "Player Names"
msgid "board size"
msgstr "Board size"
Binary file not shown.
+17 -4
View File
@@ -713,10 +713,6 @@ msgstr "Plays moves that lead to simplifying the board state."
msgid "ai:simple"
msgstr "Simple Style"
#. TODO - Analyze again but allow only nearby moves
msgid "analysis:local"
msgstr "Find local responses"
#. TODO - status message
msgid "local analysis"
msgstr "Searching for local responses"
@@ -799,3 +795,20 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+17 -3
View File
@@ -743,9 +743,6 @@ msgstr ""
msgid "ai:simple"
msgstr "Modéré"
msgid "analysis:local"
msgstr "Proposer des coups locaux"
msgid "local analysis"
msgstr "Recherche de coups locaux."
@@ -825,3 +822,20 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+17 -4
View File
@@ -698,10 +698,6 @@ msgstr ""
msgid "ai:simple"
msgstr "簡明派"
#. Analyze again but allow only nearby moves
msgid "analysis:local"
msgstr "近辺の応手に絞って分析"
#. status message
msgid "local analysis"
msgstr "近辺の応手を分析中"
@@ -783,3 +779,20 @@ msgstr "Inserting exchange done and copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+16 -3
View File
@@ -671,9 +671,6 @@ msgstr ""
msgid "ai:simple"
msgstr "간명한 기풍"
msgid "analysis:local"
msgstr "국지적인 응수 찾기"
msgid "local analysis"
msgstr "국지적인 응수를 찾고 있습니다"
@@ -753,3 +750,19 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr "Drag to select the region of interest."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.
+17 -3
View File
@@ -706,9 +706,6 @@ msgstr ""
msgid "ai:simple"
msgstr "Простой стиль"
msgid "analysis:local"
msgstr "Найти локальные ответы"
msgid "local analysis"
msgstr "Поиск локальных ответов"
@@ -788,3 +785,20 @@ msgstr "Inserting exchange(s) done, copied {num_copied} following moves."
msgid "finish inserting before navigating"
msgstr ""
"Navigation is disabled in insert mode, finish insert mode by pressing 'i'. "
#. TODO - in new game options
msgid "player names"
msgstr "Player Names"
#. TODO - Option in dropdown to insert some moves between the current and next
msgid "analysis:insert"
msgstr "Insert moves"
#. TODO - Status message
msgid "analysis:region:start"
msgstr ""
"Drag to select the region of interest. Selecting a single point removes it."
#. TODO - Restrict analysis to a specific region
msgid "analysis:region"
msgstr "Set region of interest"
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+4 -12
View File
@@ -310,17 +310,9 @@
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
text: i18n._("show stats if")
BoxLayout:
Label:
text: '>'
size_hint: 0.1, 1
AnchorLayout:
LabelledIntInput:
input_property: "trainer/low_visits"
Label:
size_hint: 0.1, 1
text: i18n._('visits')
Label:
AnchorLayout:
LabelledIntInput:
input_property: "trainer/low_visits"
DescriptionLabel:
font_size: DESC_FONT_SIZE * 0.8
text: i18n._("show ai dots")
@@ -396,7 +388,7 @@
spacing: CP_SPACING
padding: CP_PADDING
DescriptionLabel:
text: i18n._("names")
text: i18n._("player names")
AnchorLayout:
LabelledTextInput:
text: ''