Merge pull request #130 from sanderland/v1.3.1

V1.3.1
This commit is contained in:
sanderland authored and GitHub committed 2020-07-08 19:39:43 +02:00
commit 7848e920de
7 files changed
+109 -10

No files matched your search

+1 -1
View File
@@ -48,7 +48,7 @@ Many thanks to these additional authors:
* "nowoowoo" for a fix to the parser for SGF files with extra line breaks.
* "nimets123" for the timer sound effects and board/stone graphics.
* Jordan Seaward for the stone sound effects.
* "fohristiwhirl" for the Gibo format parsing code.
* "fohristiwhirl" for the Gibo and NGF formats parsing code.
## Translators
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = "1.3.0"
VERSION = "1.3.1"
HOMEPAGE = "https://github.com/sanderland/katrain"
CONFIG_MIN_VERSION = "1.3.0" # keep config files from this version
+97 -3
View File
@@ -332,20 +332,23 @@ class SGF:
@classmethod
def parse_file(cls, filename, encoding=None) -> SGFNode:
is_gib = filename.lower().endswith(".gib")
is_ngf = filename.lower().endswith(".ngf")
"""Parse a file as SGF, encoding will be detected if not given."""
with open(filename, "rb") as f:
bin_contents = f.read()
if not encoding:
if not is_gib:
if is_gib or is_ngf:
encoding = "utf8"
else: # sgf
match = re.search(rb"CA\[(.*?)\]", bin_contents)
if match:
encoding = match[1].decode("ascii", errors="ignore")
else:
encoding = "ISO-8859-1" # default
else:
encoding = "utf8" # ?
decoded = bin_contents.decode(encoding=encoding, errors="ignore")
if is_ngf:
return cls.parse_ngf(decoded)
if is_gib:
return cls.parse_gib(decoded)
else: # sgf
@@ -382,6 +385,97 @@ class SGF:
raise ParseError(f"Parse Error: unexpected character at {self.contents[self.ix:self.ix+25]}")
raise ParseError("Parse Error: expected ')' at end of input.")
# NGF parser adapted from https://github.com/fohristiwhirl/gofish/
@classmethod
def parse_ngf(cls, ngf):
ngf = ngf.strip()
lines = ngf.split("\n")
try:
boardsize = int(lines[1])
handicap = int(lines[5])
pw = lines[2].split()[0]
pb = lines[3].split()[0]
rawdate = lines[8][0:8]
komi = float(lines[7])
if handicap == 0 and int(komi) == komi:
komi += 0.5
except (IndexError, ValueError):
boardsize = 19
handicap = 0
pw = ""
pb = ""
rawdate = ""
komi = 0
re = ""
try:
if "hite win" in lines[10]:
re = "W+"
elif "lack win" in lines[10]:
re = "B+"
except:
pass
if handicap < 0 or handicap > 9:
raise ParseError(f"Handicap {handicap} out of range")
root = cls._NODE_CLASS()
node = root
# Set root values...
root.set_property("SZ", boardsize)
if handicap >= 2:
root.set_property("HA", handicap)
root.place_handicap_stones(handicap, tygem=True) # While this isn't Tygem, it uses the same layout
if komi:
root.set_property("KM", komi)
if len(rawdate) == 8:
ok = True
for n in range(8):
if rawdate[n] not in "0123456789":
ok = False
if ok:
date = rawdate[0:4] + "-" + rawdate[4:6] + "-" + rawdate[6:8]
root.set_property("DT", date)
if pw:
root.set_property("PW", pw)
if pb:
root.set_property("PB", pb)
if re:
root.set_property("RE", re)
# Main parser...
for line in lines:
line = line.strip().upper()
if len(line) >= 7:
if line[0:2] == "PM":
if line[4] in ["B", "W"]:
# move format is similar to SGF, but uppercase and out-by-1
key = line[4]
raw_move = line[5:7].lower()
value = chr(ord(raw_move[0]) - 1) + chr(ord(raw_move[1]) - 1)
node = cls._NODE_CLASS(parent=node)
node.set_property(key, value)
if len(root.children) == 0: # We'll assume we failed in this case
raise ParseError("Found no moves")
return root
# GIB parser adapted from https://github.com/fohristiwhirl/gofish/
@classmethod
def parse_gib(cls, gib):
+4
View File
@@ -380,6 +380,10 @@ class BadukPanWidget(Widget):
current_node = katrain.game.current_node
player, next_player = current_node.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:
return # race condition
with self.canvas.after:
self.canvas.after.clear()
self.active_pv_moves = []
+3 -3
View File
@@ -225,11 +225,11 @@ class RankGraph(Graph):
[
(num_mv, rank, value, mv.player)
for rank, (value, mv) in enumerate(policy_ranking)
if mv == move.move
if mv == node.move
][0]
if policy_ranking
if policy_ranking and node.move
else (None, None, None, None)
for move, policy_ranking, num_mv in zip(nodes, parent_policy_per_move, num_legal_moves)
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]
+1 -1
View File
@@ -502,6 +502,6 @@
I18NFileBrowser:
id: filesel
multiselect: False
filters: ["*.sgf","*.gib"]
filters: ["*.sgf","*.gib","*.ngf"]
path: "."
size_hint: 1,7
+2 -1
View File
@@ -19,6 +19,7 @@ def include_data_files(directory):
include_data_files("katrain/KataGo")
include_data_files("katrain/models")
include_data_files("katrain/fonts")
include_data_files("katrain/sounds")
include_data_files("katrain/img/")
include_data_files("katrain/img/flaticon")
include_data_files("katrain/i18n")
@@ -41,7 +42,7 @@ setup(
"wheel",
"setuptools",
"importlib_resources ;python_version<'3.7'",
"pygame", # some mac versions need this for kivy
"pygame;platform_system=='Darwin'", # some mac versions need this for kivy
"cython>=0.24,<=0.29.14,!=0.27,!=0.27.2", # kivy wants this
"kivy_deps.glew;platform_system=='Windows'",
"kivy_deps.sdl2;platform_system=='Windows'",