From 13dcdcee5540075456578e102d3eb0a283a54430 Mon Sep 17 00:00:00 2001 From: Sander Land Date: Thu, 27 Feb 2020 22:02:20 +0100 Subject: [PATCH] improvements to analysis, temperature, cutoff and updating of older analysis --- board.py | 29 +++++++++++++++++++++-------- controller.py | 11 ++++++++--- katrain.py | 1 + 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/board.py b/board.py index 8f08965..717b168 100644 --- a/board.py +++ b/board.py @@ -1,5 +1,6 @@ import os import random +import math from datetime import datetime @@ -51,6 +52,15 @@ class Move: def is_pass(self): return self.coords[0] is None + def update_top_move_evaluation(self): # a move's outdated analysis + if self.analysis and self.parent and self.parent.analysis: + for move_dict in self.parent.analysis: + if move_dict["move"] == self.gtp(): + move_dict["outdatedScoreLead"] = move_dict["scoreLead"] + move_dict["scoreLead"] = self.analysis[0]["scoreLead"] + self.parent.update_top_move_evaluation() + return + # various analysis functions def set_analysis(self, analysis_blob, is_pass): if is_pass: @@ -58,10 +68,9 @@ class Move: else: self.analysis = analysis_blob["moveInfos"] self.ownership = analysis_blob["ownership"] - if self.parent and self.parent.analysis and self.parent.analysis[0]["move"] == self.gtp(): - self.parent.analysis[0]["scoreLead"] = self.analysis[0]["scoreLead"] - if self.children and self.children[0].analysis and self.children[0].gtp() == self.analysis[0]["move"]: - self.analysis[0]["scoreLead"] = self.children[0].analysis[0]["scoreLead"] # if received out of order, some edge case with undos ignored + if self.children: + self.children[0].update_top_move_evaluation() + self.update_top_move_evaluation() @property def analysis_ready(self): @@ -127,7 +136,7 @@ class Move: def temperature_stats(self): best = float(self.analysis[0]["scoreLead"]) worst = float(self.pass_analysis[0]["scoreLead"]) - return best, worst, abs(best - worst) + return best, worst, max(-self.player_sign * (best - worst), 0) @property def score(self): @@ -141,14 +150,15 @@ class Move: @property def evaluation(self): best, worst, temp = self.parent.temperature_stats - return self.player_sign * (self.score - worst) / temp + return self.player_sign * (self.score - worst) / temp if temp > 0 else math.nan @property def outdated_evaluation(self): prev_analysis_current_move = [d for d in self.parent.analysis if d["move"] == self.gtp()] if prev_analysis_current_move: best_score, worst_score, prev_temp = self.parent.temperature_stats - return self.player_sign * (prev_analysis_current_move[0]["scoreLead"] - worst_score) / prev_temp + score = prev_analysis_current_move[0].get("outdatedScoreLead") or prev_analysis_current_move[0]["scoreLead"] + return self.player_sign * (score - worst_score) / prev_temp if prev_temp > 0 else math.nan @property def ai_moves(self): @@ -156,7 +166,10 @@ class Move: return [] _, worst_score, temperature = self.temperature_stats for d in self.analysis: - d["evaluation"] = -self.player_sign * (d["scoreLead"] - worst_score) / temperature + if temperature > 0.5: + d["evaluation"] = -self.player_sign * (d["scoreLead"] - worst_score) / temperature + else: + d["evaluation"] = int(-self.player_sign * d["scoreLead"] >= -self.player_sign * self.analysis[0]["scoreLead"]) return self.analysis # various output and conversion functions diff --git a/controller.py b/controller.py index a592bd2..2afc801 100644 --- a/controller.py +++ b/controller.py @@ -1,6 +1,7 @@ import copy import json import os +import math import random import re import shlex @@ -97,16 +98,20 @@ class EngineControls(GridLayout): self.score.text = move.format_score().replace("-", "\u2013") self.temperature.text = f"{move.temperature_stats[2]:.1f}" if move.parent and move.parent.analysis_ready: - self.evaluation.text = f"{move.evaluation:.1%}" + if not math.isnan(move.evaluation): + self.evaluation.text = f"{move.evaluation:.1%}" + else: + self.evaluation.text = f"?" # handles showing completed analysis and triggered actions like auto undo and ai move def update_evaluation(self): current_move = self.board.current_move self.score.set_prisoners(self.board.prisoner_count) - if not self.ai_auto.active(current_move.player) and current_move is not self.board.root: + current_player_is_human_or_both_robots = (not self.ai_auto.active(current_move.player) or self.ai_auto.active(1 - current_move.player)) + if current_player_is_human_or_both_robots and current_move is not self.board.root: self.info.text = current_move.comment(eval=True, hints=self.hints.active(current_move.player)) self.evaluation.text = "" - if not self.ai_auto.active(current_move.player): + if current_player_is_human_or_both_robots: self.show_evaluation_stats(current_move) if current_move.analysis_ready and current_move.parent and current_move.parent.analysis_ready and not current_move.children and not current_move.x_comment.get("undo"): diff --git a/katrain.py b/katrain.py index 95b4a90..6bf4e82 100644 --- a/katrain.py +++ b/katrain.py @@ -55,6 +55,7 @@ class BadukPanWidget(Widget): if self.engine.debug: print("\nAnalysis:\n", stones_here[-1].analysis) print("\nParent Analysis:\n", stones_here[-1].parent.analysis) + print("\nParent Pass Analysis:\n", stones_here[-1].parent.pass_analysis[0]) if not self.engine.ai_lock.active: self.engine.info.text = stones_here[-1].comment(sgf=True) self.engine.show_evaluation_stats(stones_here[-1])