From edb4b19de1290b466b1a18f6c5fc84cb587c9916 Mon Sep 17 00:00:00 2001 From: Sander Land Date: Mon, 30 Nov 2020 14:32:33 +0100 Subject: [PATCH] fixes --- katrain/__main__.py | 6 +++-- katrain/core/constants.py | 3 +-- katrain/core/game.py | 13 ++++++--- katrain/core/game_node.py | 56 ++++++++++++++++++++++----------------- katrain/core/utils.py | 6 +++++ 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/katrain/__main__.py b/katrain/__main__.py index 6d5dce1..9463fdb 100644 --- a/katrain/__main__.py +++ b/katrain/__main__.py @@ -260,7 +260,9 @@ class KaTrainGui(Screen, KaTrainBase): self.play_mode.switch_ui_mode() # for new game, go to play, for loaded, analyze self.board_gui.animating_pv = None self.engine.on_new_game() # clear queries - self.game = Game(self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast,loaded_from_file=loaded_from_file) + self.game = Game( + self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast, loaded_from_file=loaded_from_file + ) if move_tree: for bw, player_info in self.players_info.items(): player_info.player_type = PLAYER_HUMAN @@ -369,7 +371,7 @@ class KaTrainGui(Screen, KaTrainBase): except ParseError as e: self.log(i18n._("Failed to load SGF").format(error=e), OUTPUT_ERROR) return - self._do_new_game(move_tree=move_tree, analyze_fast=fast,loaded_from_file=file) + self._do_new_game(move_tree=move_tree, analyze_fast=fast, loaded_from_file=file) if not rewind: self.game.redo(999) diff --git a/katrain/core/constants.py b/katrain/core/constants.py index e0b9423..b48a438 100644 --- a/katrain/core/constants.py +++ b/katrain/core/constants.py @@ -239,6 +239,5 @@ TOP_MOVE_OPTIONS = [ TOP_MOVE_NOTHING, ] -SGF_COMMENTS_MARKER = "\u200b\u3164" -SGF_NOTE_MARKER = "\u200b\u200b" +SGF_INTERNAL_COMMENTS_MARKER = "\u200b\u3164" SGF_SEPARATOR_MARKER = "\u3164\u3164" diff --git a/katrain/core/game.py b/katrain/core/game.py index 92d0bcc..92e4079 100644 --- a/katrain/core/game.py +++ b/katrain/core/game.py @@ -16,7 +16,8 @@ from katrain.core.constants import ( STATUS_INFO, STATUS_TEACHING, PLAYER_HUMAN, - VERSION, PROGRAM_NAME, + VERSION, + PROGRAM_NAME, ) from katrain.core.engine import KataGoEngine from katrain.core.game_node import GameNode @@ -45,7 +46,7 @@ class Game: move_tree: GameNode = None, analyze_fast=False, game_properties: Optional[Dict] = None, - loaded_from_file = None + loaded_from_file=None, ): self.katrain = katrain self._lock = threading.Lock() @@ -55,7 +56,6 @@ class Game: self.game_id = datetime.strftime(datetime.now(), "%Y-%m-%d %H %M %S") self.loaded_from_file = loaded_from_file - if move_tree: self.root = move_tree self.komi = self.root.komi @@ -326,7 +326,12 @@ class Game: base_game_name = f"katrain_{player_names['B']} vs {player_names['W']}" game_name = f"{base_game_name} {self.game_id}" - if self.loaded_from_file and base_game_name in self.loaded_from_file and PROGRAM_NAME in self.root.get_property("AP","") and self.loaded_from_file.endswith('sgf'): + if ( + self.loaded_from_file + and base_game_name in self.loaded_from_file + and PROGRAM_NAME in self.root.get_property("AP", "") + and self.loaded_from_file.endswith("sgf") + ): file_name = self.loaded_from_file else: file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf")) diff --git a/katrain/core/game_node.py b/katrain/core/game_node.py index 3d7fc02..e6005d7 100644 --- a/katrain/core/game_node.py +++ b/katrain/core/game_node.py @@ -2,13 +2,19 @@ import copy import random from typing import Dict, List, Optional, Tuple -from katrain.core.constants import HOMEPAGE, VERSION, SGF_COMMENTS_MARKER, SGF_SEPARATOR_MARKER, SGF_NOTE_MARKER, PROGRAM_NAME +from katrain.core.constants import ( + VERSION, + SGF_INTERNAL_COMMENTS_MARKER, + SGF_SEPARATOR_MARKER, + PROGRAM_NAME, +) 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 import base64 import gzip +import json class GameNode(SGFNode): @@ -16,8 +22,6 @@ class GameNode(SGFNode): def __init__(self, parent=None, properties=None, move=None): super().__init__(parent=parent, properties=properties, move=move) - self.ownership = None - self.policy = None self.auto_undo = None # None = not analyzed. False: not undone (good move). True: undone (bad move) self.ai_thoughts = "" self.note = "" @@ -31,45 +35,41 @@ class GameNode(SGFNode): def add_list_property(self, property: str, values: List): if property == "KT": try: - import bson - - self.analysis = bson.loads(gzip.decompress(base64.standard_b64decode(values[0]))) + self.analysis = json.loads(gzip.decompress(base64.standard_b64decode(values[0]))) self.analysis_loaded = True except Exception as e: - print(e) + print(f"Error in loading analysis: {e}") elif property == "C": comments = [ # strip out all previously auto generated comments - c for v in values for c in v.split(SGF_SEPARATOR_MARKER) + c + for v in values + for c in v.split(SGF_SEPARATOR_MARKER) + if c.strip() and SGF_INTERNAL_COMMENTS_MARKER not in c ] - self.note = "".join(c for c in comments if SGF_NOTE_MARKER in c) - super().add_list_property( - property, - [c for c in comments if c.strip() and SGF_COMMENTS_MARKER not in c and SGF_NOTE_MARKER not in c], - ) + self.note = "".join(comments) # no super call intended, just save as note to be editable else: return super().add_list_property(property, values) def clear_analysis(self): self.analysis_visits_requested = 0 - self.analysis = {"moves": {}, "root": None, "completed": False} + self.analysis = {"moves": {}, "root": None, "ownership": None, "policy": None, "completed": False} def sgf_properties( self, save_comments_player=None, save_comments_class=None, eval_thresholds=None, save_analysis=False ): properties = copy.copy(super().sgf_properties()) note = self.note.strip() - print(save_analysis, self.analysis_complete) if save_analysis and self.analysis_complete: try: - import bson - analysis = copy.deepcopy(self.analysis) for movedict in analysis["moves"].values(): if "ownership" in movedict: del movedict["ownership"] - properties["KT"] = [base64.standard_b64encode(gzip.compress(bson.dumps(analysis))).decode("utf-8")] + properties["KT"] = [ + base64.standard_b64encode(gzip.compress(json.dumps(analysis).encode("utf-8"))).decode("utf-8") + ] except Exception as e: - print(e) + print(f"Error in saving analysis: {e}") if self.points_lost and save_comments_class is not None and eval_thresholds is not None: show_class = save_comments_class[evaluation_class(self.points_lost, eval_thresholds)] else: @@ -93,12 +93,12 @@ class GameNode(SGFNode): comments.append(self.comment(sgf=True, interactive=False)) if self.is_root: comments = [ - i18n._("SGF start message") + SGF_COMMENTS_MARKER, + i18n._("SGF start message") + SGF_INTERNAL_COMMENTS_MARKER + "\n", *comments, - f"SGF with generated by {PROGRAM_NAME} {VERSION}{SGF_COMMENTS_MARKER}.", + f"\nSGF with generated by {PROGRAM_NAME} {VERSION}{SGF_INTERNAL_COMMENTS_MARKER}.\n", ] if note: - comments.append(f"\nNote: {self.note}{SGF_NOTE_MARKER}") + comments.append(f"{self.note}") if comments: properties["C"] = [SGF_SEPARATOR_MARKER.join(comments)] elif "C" in properties: @@ -169,8 +169,8 @@ class GameNode(SGFNode): move_dict["order"] = 999 # old moves to end for move_analysis in analysis_json["moveInfos"]: self.update_move_analysis(move_analysis, move_analysis["move"]) - self.ownership = analysis_json.get("ownership") - self.policy = analysis_json.get("policy") + self.analysis["ownership"] = analysis_json.get("ownership") + self.analysis["policy"] = analysis_json.get("policy") if not additional_moves: self.analysis["root"] = analysis_json["rootInfo"] if self.parent and self.move: @@ -183,6 +183,14 @@ class GameNode(SGFNode): is_normal_query = refine_move is None and not additional_moves self.analysis["completed"] = self.analysis["completed"] or (is_normal_query and not partial_result) + @property + def ownership(self): + return self.analysis.get("ownership") + + @property + def policy(self): + return self.analysis.get("policy") + @property def analysis_exists(self): return self.analysis["root"] is not None diff --git a/katrain/core/utils.py b/katrain/core/utils.py index 4adf592..a8d1e70 100644 --- a/katrain/core/utils.py +++ b/katrain/core/utils.py @@ -1,4 +1,5 @@ import os +import struct import sys from typing import List, Tuple, TypeVar @@ -55,6 +56,11 @@ def find_package_resource(path, silent_errors=False): return os.path.abspath(os.path.expanduser(path)) # absolute path +def pack_floats(float_list): + return struct.pack('%sf' % len(float_list), *float_list) + + + def format_visits(n): if n < 1000: return str(n)