extra analysis
This commit is contained in:
1 parent
0a331cf294
commit
6fc6332f9d
6 files changed
+116
-25
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import copy
|
||||||
|
|
||||||
|
|
||||||
class IllegalMoveException(Exception):
|
class IllegalMoveException(Exception):
|
||||||
@@ -13,7 +14,7 @@ class Move:
|
|||||||
SGF_COORD = [chr(i) for i in range(97, 123)]
|
SGF_COORD = [chr(i) for i in range(97, 123)]
|
||||||
_move_id_counter = -1
|
_move_id_counter = -1
|
||||||
|
|
||||||
def __init__(self, player, coords=None, gtpcoords=None, sgfcoords=None, robot=False):
|
def __init__(self, player=0, coords=None, gtpcoords=None, sgfcoords=None, robot=False):
|
||||||
Move._move_id_counter += 1
|
Move._move_id_counter += 1
|
||||||
self.id = Move._move_id_counter
|
self.id = Move._move_id_counter
|
||||||
self.player = player
|
self.player = player
|
||||||
@@ -108,9 +109,12 @@ class Move:
|
|||||||
elif not self.is_pass and self.parent.analysis[0]["move"] != self.gtp():
|
elif not self.is_pass and self.parent.analysis[0]["move"] != self.gtp():
|
||||||
if sgf: # shown in stats anyway
|
if sgf: # shown in stats anyway
|
||||||
text += f"Evaluation: {self.evaluation:.1%} efficient\n"
|
text += f"Evaluation: {self.evaluation:.1%} efficient\n"
|
||||||
outdated_evaluation = self.outdated_evaluation
|
outdated_evaluation, outdated_details = self.outdated_evaluation
|
||||||
if outdated_evaluation and outdated_evaluation > self.evaluation and outdated_evaluation > self.evaluation + 0.05:
|
if outdated_evaluation and outdated_evaluation > self.evaluation and outdated_evaluation > self.evaluation + 0.05:
|
||||||
text += f"(Was considered last move as {outdated_evaluation:.0%})\n"
|
text += f"(Was considered last move as {outdated_evaluation:.0%})\n"
|
||||||
|
if outdated_evaluation > self.evaluation + 0.15:
|
||||||
|
with open("outdated_log.txt", "a") as f:
|
||||||
|
f.write(f"logs.append({repr(outdated_details)})\n")
|
||||||
points_lost = self.player_sign * (prev_best_score - score)
|
points_lost = self.player_sign * (prev_best_score - score)
|
||||||
if points_lost > 0.5:
|
if points_lost > 0.5:
|
||||||
text += f"Estimated point loss: {points_lost:.1f}\n"
|
text += f"Estimated point loss: {points_lost:.1f}\n"
|
||||||
@@ -158,24 +162,26 @@ class Move:
|
|||||||
|
|
||||||
prev_analysis_current_move = [d for d in self.parent.analysis if d["move"] == self.gtp()]
|
prev_analysis_current_move = [d for d in self.parent.analysis if d["move"] == self.gtp()]
|
||||||
if prev_analysis_current_move:
|
if prev_analysis_current_move:
|
||||||
best_score, worst_score, prev_temp = self.parent.temperature_stats
|
|
||||||
best_score = outdated_score(self.parent.analysis[0])
|
best_score = outdated_score(self.parent.analysis[0])
|
||||||
worst_score = self.parent.pass_analysis[0]["scoreLead"]
|
worst_score = self.parent.pass_analysis[0]["scoreLead"]
|
||||||
prev_temp = max(self.player_sign * (best_score - worst_score), 0)
|
prev_temp = max(self.player_sign * (best_score - worst_score), 0)
|
||||||
score = outdated_score(prev_analysis_current_move[0])
|
score = outdated_score(prev_analysis_current_move[0])
|
||||||
return self.player_sign * (score - worst_score) / prev_temp if prev_temp > 0 else None
|
return (self.player_sign * (score - worst_score) / prev_temp if prev_temp > 0 else None), prev_analysis_current_move
|
||||||
|
else:
|
||||||
|
return None, None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ai_moves(self):
|
def ai_moves(self):
|
||||||
if not self.analysis_ready:
|
if not self.analysis_ready:
|
||||||
return []
|
return []
|
||||||
_, worst_score, temperature = self.temperature_stats
|
_, worst_score, temperature = self.temperature_stats
|
||||||
for d in self.analysis:
|
analysis = copy.copy(self.analysis) # not deep, so eval is saved, but avoids race conditions
|
||||||
|
for d in analysis:
|
||||||
if temperature > 0.5:
|
if temperature > 0.5:
|
||||||
d["evaluation"] = -self.player_sign * (d["scoreLead"] - worst_score) / temperature
|
d["evaluation"] = -self.player_sign * (d["scoreLead"] - worst_score) / temperature
|
||||||
else:
|
else:
|
||||||
d["evaluation"] = int(-self.player_sign * d["scoreLead"] >= -self.player_sign * self.analysis[0]["scoreLead"])
|
d["evaluation"] = int(-self.player_sign * d["scoreLead"] >= -self.player_sign * self.analysis[0]["scoreLead"])
|
||||||
return self.analysis
|
return analysis
|
||||||
|
|
||||||
# various output and conversion functions
|
# various output and conversion functions
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -335,6 +341,21 @@ class Board:
|
|||||||
return 1 - self.current_move.player
|
return 1 - self.current_move.player
|
||||||
|
|
||||||
def store_analysis(self, json):
|
def store_analysis(self, json):
|
||||||
|
if json["id"].startswith("AA:"): # board sweep analyze all
|
||||||
|
_, move_id, gtpcoords = json["id"].split(":")
|
||||||
|
move = self.all_moves.get(int(move_id))
|
||||||
|
if not move.analysis:
|
||||||
|
return # should have been prevented, but better not to crash
|
||||||
|
cur_analysis = [d for d in move.analysis if d["move"] == gtpcoords]
|
||||||
|
move_analysis = {k: v for k, v in json["moveInfos"][0].items() if k not in {"move", "pv"}}
|
||||||
|
move_analysis["visits"] = sum(d["visits"] for d in json["moveInfos"]) # TODO: ??
|
||||||
|
if cur_analysis:
|
||||||
|
if cur_analysis[0]["visits"] < move_analysis["visits"]:
|
||||||
|
cur_analysis[0].update(move_analysis)
|
||||||
|
else:
|
||||||
|
move.analysis.append({"move": gtpcoords, **move_analysis})
|
||||||
|
return
|
||||||
|
|
||||||
if json["id"].startswith("PASS_"):
|
if json["id"].startswith("PASS_"):
|
||||||
move_id = int(json["id"].lstrip("PASS_"))
|
move_id = int(json["id"].lstrip("PASS_"))
|
||||||
is_pass = True
|
is_pass = True
|
||||||
|
|||||||
+3
-1
@@ -3,7 +3,9 @@
|
|||||||
"pass_visits": 100,
|
"pass_visits": 100,
|
||||||
"pass_visits_fast": 25,
|
"pass_visits_fast": 25,
|
||||||
"visits": 2000,
|
"visits": 2000,
|
||||||
"visits_fast": 500
|
"visits_fast": 500,
|
||||||
|
"analyze_all_visits": 500,
|
||||||
|
"analyze_all_visits_fast": 100
|
||||||
},
|
},
|
||||||
"board": {
|
"board": {
|
||||||
"size": 19,
|
"size": 19,
|
||||||
|
|||||||
+38
-15
@@ -37,11 +37,15 @@ class EngineControls(GridLayout):
|
|||||||
self.command = shlex.split(self.command)
|
self.command = shlex.split(self.command)
|
||||||
|
|
||||||
analysis_settings = Config.get("analysis")
|
analysis_settings = Config.get("analysis")
|
||||||
self.visits = [[analysis_settings["pass_visits"], analysis_settings["visits"]], [analysis_settings["pass_visits_fast"], analysis_settings["visits_fast"]]]
|
self.visits = [
|
||||||
|
[analysis_settings["pass_visits"], analysis_settings["visits"], analysis_settings["analyze_all_visits"]],
|
||||||
|
[analysis_settings["pass_visits_fast"], analysis_settings["visits_fast"], analysis_settings["analyze_all_visits_fast"]],
|
||||||
|
]
|
||||||
self.train_settings = Config.get("trainer")
|
self.train_settings = Config.get("trainer")
|
||||||
self.debug = Config.get("debug")["level"]
|
self.debug = Config.get("debug")["level"]
|
||||||
self.board_size = Config.get("board")["size"]
|
self.board_size = Config.get("board")["size"]
|
||||||
self.ready = False
|
self.ready = False
|
||||||
|
self.ai_thinking = False
|
||||||
self.message_queue = None
|
self.message_queue = None
|
||||||
self.board = Board(self.board_size)
|
self.board = Board(self.board_size)
|
||||||
self.komi = 6.5 # loaded from config in init
|
self.komi = 6.5 # loaded from config in init
|
||||||
@@ -162,7 +166,9 @@ class EngineControls(GridLayout):
|
|||||||
ts = self.train_settings
|
ts = self.train_settings
|
||||||
while not self.board.current_move.analysis_ready:
|
while not self.board.current_move.analysis_ready:
|
||||||
self.info.text = "Thinking..."
|
self.info.text = "Thinking..."
|
||||||
|
self.ai_thinking = True
|
||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
|
self.ai_thinking = False
|
||||||
# select move
|
# select move
|
||||||
current_move = self.board.current_move
|
current_move = self.board.current_move
|
||||||
pos_moves = [
|
pos_moves = [
|
||||||
@@ -233,6 +239,32 @@ class EngineControls(GridLayout):
|
|||||||
self.show_error(f"could not decode file contents of {file}")
|
self.show_error(f"could not decode file contents of {file}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def _do_analyze_extra(self, sweep):
|
||||||
|
stones = {s.coords for s in self.board.stones}
|
||||||
|
current_move = self.board.current_move
|
||||||
|
if not current_move.analysis:
|
||||||
|
self.info.text = "Wait for initial analysis to complete before doing a board-sweep or refinement"
|
||||||
|
return
|
||||||
|
played_moves = self.board.moves
|
||||||
|
if sweep:
|
||||||
|
analyze_moves = [Move(coords=(x, y)).gtp() for x in range(self.board_size) for y in range(self.board_size) if (x, y) not in stones]
|
||||||
|
visits = self.visits[self.ai_fast.active][2]
|
||||||
|
self.info.text = f"Refining analysis of entire board to {visits} visits"
|
||||||
|
else:
|
||||||
|
analyze_moves = [a["move"] for a in current_move.analysis]
|
||||||
|
visits = current_move.analysis[0]["visits"] + self.visits[1][2]
|
||||||
|
self.info.text = f"Refining analysis of candidate moves to {visits} visits"
|
||||||
|
|
||||||
|
for gtpcoords in analyze_moves:
|
||||||
|
self._send_analysis_query(
|
||||||
|
{
|
||||||
|
"id": f"AA:{current_move.id}:{gtpcoords}",
|
||||||
|
"moves": [[m.bw_player(), m.gtp()] for m in played_moves] + [[current_move.bw_player(True), gtpcoords]],
|
||||||
|
"includeOwnership": False,
|
||||||
|
"maxVisits": visits,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def _do_analyze_sgf(self, sgf, faster=False, rewind=False):
|
def _do_analyze_sgf(self, sgf, faster=False, rewind=False):
|
||||||
sgfprops = {k: v.strip("[]").split("][") if k in ["AB", "AW"] else v.strip("[]") for k, v in re.findall(r"\b(\w+)((?:\[.*?\])+)", sgf)}
|
sgfprops = {k: v.strip("[]").split("][") if k in ["AB", "AW"] else v.strip("[]") for k, v in re.findall(r"\b(\w+)((?:\[.*?\])+)", sgf)}
|
||||||
size = int(sgfprops.get("SZ", self.board_size))
|
size = int(sgfprops.get("SZ", self.board_size))
|
||||||
@@ -292,14 +324,16 @@ class EngineControls(GridLayout):
|
|||||||
if self.debug:
|
if self.debug:
|
||||||
print(f"[{time.time()-self.query_time.get(analysis['id'],0):.1f}] kata analysis received:", line[:80], "...")
|
print(f"[{time.time()-self.query_time.get(analysis['id'],0):.1f}] kata analysis received:", line[:80], "...")
|
||||||
if "error" in analysis:
|
if "error" in analysis:
|
||||||
print(analysis)
|
if "AA" not in analysis["id"]: # silently drop illegal moves from analysis all
|
||||||
self.show_error(f"ERROR IN KATA ANALYSIS: {analysis['error']}")
|
print(analysis)
|
||||||
|
self.show_error(f"ERROR IN KATA ANALYSIS: {analysis['error']}")
|
||||||
else:
|
else:
|
||||||
self.board.store_analysis(analysis)
|
self.board.store_analysis(analysis)
|
||||||
self.update_evaluation()
|
self.update_evaluation()
|
||||||
|
|
||||||
def _send_analysis_query(self, query):
|
def _send_analysis_query(self, query):
|
||||||
self.query_time[query["id"]] = time.time()
|
self.query_time[query["id"]] = time.time()
|
||||||
|
query = {"rules": "japanese", "komi": self.komi, "boardXSize": self.board_size, "boardYSize": self.board_size, "analyzeTurns": [len(query["moves"])], **query}
|
||||||
if self.kata:
|
if self.kata:
|
||||||
self.kata.stdin.write((json.dumps(query) + "\n").encode())
|
self.kata.stdin.write((json.dumps(query) + "\n").encode())
|
||||||
self.kata.stdin.flush()
|
self.kata.stdin.flush()
|
||||||
@@ -311,23 +345,12 @@ class EngineControls(GridLayout):
|
|||||||
move_id = move.id
|
move_id = move.id
|
||||||
moves = self.board.moves
|
moves = self.board.moves
|
||||||
fast = self.ai_fast.active
|
fast = self.ai_fast.active
|
||||||
query = {
|
query = {"id": str(move_id), "moves": [[m.bw_player(), m.gtp()] for m in moves], "includeOwnership": True, "maxVisits": self.visits[fast][1] // faster_fac}
|
||||||
"id": str(move_id),
|
|
||||||
"moves": [[m.bw_player(), m.gtp()] for m in moves],
|
|
||||||
"rules": "japanese",
|
|
||||||
"komi": self.komi,
|
|
||||||
"boardXSize": self.board_size,
|
|
||||||
"boardYSize": self.board_size,
|
|
||||||
"analyzeTurns": [len(moves)],
|
|
||||||
"includeOwnership": True,
|
|
||||||
"maxVisits": self.visits[fast][1] // faster_fac,
|
|
||||||
}
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(f"sending query for move {move_id}: {str(query)[:80]}")
|
print(f"sending query for move {move_id}: {str(query)[:80]}")
|
||||||
self._send_analysis_query(query)
|
self._send_analysis_query(query)
|
||||||
query.update({"id": f"PASS_{move_id}", "maxVisits": self.visits[fast][0] // faster_fac, "includeOwnership": False})
|
query.update({"id": f"PASS_{move_id}", "maxVisits": self.visits[fast][0] // faster_fac, "includeOwnership": False})
|
||||||
query["moves"] += [[move.bw_player(next_move=True), "pass"]]
|
query["moves"] += [[move.bw_player(next_move=True), "pass"]]
|
||||||
query["analyzeTurns"][0] += 1
|
|
||||||
self._send_analysis_query(query)
|
self._send_analysis_query(query)
|
||||||
|
|
||||||
def output_sgf(self):
|
def output_sgf(self):
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
<CheckBoxHint>
|
<CheckBoxHint>
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
checkbox: checkbox
|
checkbox: checkbox
|
||||||
|
label: label
|
||||||
text: ''
|
text: ''
|
||||||
default_active: False
|
default_active: False
|
||||||
position: (0,0)
|
position: (0,0)
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
font_size: root.height * 0.2 if root.orientation=='vertical' else root.height
|
font_size: root.height * 0.2 if root.orientation=='vertical' else root.height
|
||||||
text: root.text
|
text: root.text
|
||||||
on_press: if not checkbox.disabled: checkbox._do_press()
|
on_press: if not checkbox.disabled: checkbox._do_press()
|
||||||
|
id: label
|
||||||
CheckBox:
|
CheckBox:
|
||||||
size_hint: 1,0.55 if root.orientation=='vertical' else (0.2,1)
|
size_hint: 1,0.55 if root.orientation=='vertical' else (0.2,1)
|
||||||
id: checkbox
|
id: checkbox
|
||||||
@@ -55,11 +57,13 @@
|
|||||||
<BWCheckBoxHint>
|
<BWCheckBoxHint>
|
||||||
black: black
|
black: black
|
||||||
white: white
|
white: white
|
||||||
|
label: label
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
text: ''
|
text: ''
|
||||||
default_active: False
|
default_active: False
|
||||||
CheckBoxHintLabel:
|
CheckBoxHintLabel:
|
||||||
size_hint: 1,0.2
|
size_hint: 1,0.2
|
||||||
|
id: label
|
||||||
text: root.text
|
text: root.text
|
||||||
font_size: self.height
|
font_size: self.height
|
||||||
on_press: if not white.disabled: white._do_press(); black._do_press()
|
on_press: if not white.disabled: white._do_press(); black._do_press()
|
||||||
|
|||||||
+31
-3
@@ -169,11 +169,18 @@ class BadukPanWidget(Widget):
|
|||||||
|
|
||||||
# hints
|
# hints
|
||||||
if self.engine.hints.active(current_player):
|
if self.engine.hints.active(current_player):
|
||||||
for i, d in enumerate(last_move.ai_moves):
|
hint_moves = last_move.ai_moves
|
||||||
move = Move(gtpcoords=d["move"], player=0)
|
for i, d in enumerate(hint_moves):
|
||||||
|
move = Move(gtpcoords=d["move"])
|
||||||
c = [*self._eval_spectrum(d["evaluation"]), 0.5]
|
c = [*self._eval_spectrum(d["evaluation"]), 0.5]
|
||||||
if move.coords[0] is not None and move.coords not in undo_coords:
|
if move.coords[0] is not None and move.coords not in undo_coords:
|
||||||
self.draw_stone(move.coords[0], move.coords[1], c, scale=1.0 if i == 0 else 0.8)
|
if i == 0:
|
||||||
|
scale = 1.0
|
||||||
|
elif d["visits"] < 0.1 * hint_moves[0]["visits"]: # TODO: config?
|
||||||
|
scale = 0.6 # TODO: config?
|
||||||
|
else:
|
||||||
|
scale = 0.85
|
||||||
|
self.draw_stone(move.coords[0], move.coords[1], c, scale=scale)
|
||||||
|
|
||||||
# hover next move ghost stone
|
# hover next move ghost stone
|
||||||
if self.ghost_stone:
|
if self.ghost_stone:
|
||||||
@@ -208,6 +215,27 @@ class KaTrainGui(BoxLayout):
|
|||||||
self.controls.action("redo-branch", 1)
|
self.controls.action("redo-branch", 1)
|
||||||
elif keycode[1] == "left":
|
elif keycode[1] == "left":
|
||||||
self.controls.action("redo-branch", -1)
|
self.controls.action("redo-branch", -1)
|
||||||
|
elif keycode[1] == "s":
|
||||||
|
self.controls.action("analyze-extra", True)
|
||||||
|
elif keycode[1] == "r":
|
||||||
|
self.controls.action("analyze-extra", False)
|
||||||
|
elif keycode[1] == "a":
|
||||||
|
if not self.controls.ai_thinking:
|
||||||
|
self.controls.ai_move.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "p":# TODO: clean repetitive shortcuts
|
||||||
|
self.controls.play.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "f":
|
||||||
|
self.controls.ai_fast.label.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "h":
|
||||||
|
self.controls.hints.label.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "e":
|
||||||
|
self.controls.eval.label.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "u":
|
||||||
|
self.controls.auto_undo.label.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "b":
|
||||||
|
self.controls.ai_balance.label.trigger_action(duration=0)
|
||||||
|
elif keycode[1] == "o":
|
||||||
|
self.controls.ownership.label.trigger_action(duration=0)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
logs.append([{'lcb': 0.9866929576961049, 'move': 'Q13', 'order': 2, 'prior': 0.11910770833492279, 'pv': ['Q13', 'R13', 'S12', 'J1', 'M1', 'G16'], 'scoreLead': 124.47271696460673, 'scoreMean': 126.27482461531041, 'scoreSelfplay': 122.06720914951835, 'scoreStdev': 27.614507025114275, 'utility': 1.1346133945628056, 'utilityLcb': 1.098224634752818, 'visits': 68, 'winrate': 0.9996889433425291, 'outdatedScoreLead': 127.91250052175701, 'evaluation': 0.6566815927216013}])
|
||||||
|
logs.append([{'lcb': 0.23000714901044894, 'move': 'A7', 'order': 2, 'prior': 0.0939372107386589, 'pv': ['A7', 'B4', 'B3', 'B7', 'G12', 'G10', 'H10', 'G9'], 'scoreLead': -9.121776796888566, 'scoreMean': -4.895108362277802, 'scoreSelfplay': -5.2100667634473705, 'scoreStdev': 21.56650224292897, 'utility': -0.4353121358045132, 'utilityLcb': -0.6303358573690578, 'visits': 97, 'winrate': 0.2996584781406435, 'evaluation': 0.9730087446544682, 'outdatedScoreLead': -4.895108362277802}])
|
||||||
|
logs.append([{'lcb': 0.48324174996112224, 'move': 'F10', 'order': 2, 'prior': 0.12889033555984497, 'pv': ['F10', 'B9', 'A10', 'A9', 'B9', 'B7', 'H17'], 'scoreLead': 0.7020370412502724, 'scoreMean': 3.1918735507436278, 'scoreSelfplay': 3.8505667580252867, 'scoreStdev': 22.209495140940156, 'utility': 0.18945409233268506, 'utilityLcb': -0.12664315194471099, 'visits': 33, 'winrate': 0.5961336229173351, 'evaluation': 0.9857626433435042, 'outdatedScoreLead': 3.1918735507436278}])
|
||||||
|
logs.append([{'lcb': 1.2961580404924993, 'move': 'B8', 'order': 4, 'prior': 0.18784967064857483, 'pv': ['B8', 'D10', 'D11', 'G12', 'C14', 'B12'], 'scoreLead': 39.980447187304534, 'scoreMean': 16.300339300165696, 'scoreSelfplay': 16.75147660635949, 'scoreStdev': 27.816062826637406, 'utility': 0.6706339164931426, 'utilityLcb': 2.134771010104406, 'visits': 11, 'winrate': 0.7732519356313338, 'evaluation': 0.465537391117901, 'outdatedScoreLead': 16.300339300165696}])
|
||||||
|
logs.append([{'lcb': -0.9128409039094549, 'move': 'F6', 'order': 7, 'prior': 0.006048424169421196, 'pv': ['F6', 'E6'], 'scoreLead': -16.519556878825906, 'scoreMean': -14.270362377166748, 'scoreSelfplay': -14.119140625, 'scoreStdev': 19.22452345556336, 'utility': -0.8780453309766154, 'utilityLcb': -2.8000000000000003, 'visits': 2, 'winrate': 0.08715909609054506, 'evaluation': 1.0506796226282822, 'outdatedScoreLead': -14.270362377166748}])
|
||||||
|
logs.append([{'lcb': -0.11179767394897855, 'move': 'C8', 'order': 4, 'prior': 0.029647205024957657, 'pv': ['C8', 'A9', 'A10', 'A8', 'A7', 'B7', 'B9'], 'scoreLead': -27.91700043151085, 'scoreMean': -21.906844603223075, 'scoreSelfplay': -21.44171085687105, 'scoreStdev': 22.73403649360621, 'utility': -0.9781789774390067, 'utilityLcb': -1.4388028521708551, 'visits': 10, 'winrate': 0.05271085274096721, 'evaluation': 0.925279362535498, 'outdatedScoreLead': -21.906844603223075}])
|
||||||
|
logs.append([{'lcb': 0.004716111156360503, 'move': 'A8', 'order': 1, 'prior': 0.26070424914360046, 'pv': ['A8', 'A10', 'A6', 'B9', 'A9', 'C8', 'B9', 'C14'], 'scoreLead': -29.377870307329598, 'scoreMean': -25.069371462858335, 'scoreSelfplay': -24.13833752712488, 'scoreStdev': 19.46618456676441, 'utility': -1.0407429104348054, 'utilityLcb': -1.140719563219286, 'visits': 112, 'winrate': 0.0404220585793893, 'evaluation': 0.6556051615755801, 'outdatedScoreLead': -25.069371462858335}])
|
||||||
|
logs.append([{'lcb': 0.14960351964179275, 'move': 'C8', 'order': 2, 'prior': 0.29037389159202576, 'pv': ['C8', 'B9', 'A10', 'A3', 'A6', 'A4', 'A11', 'A9'], 'scoreLead': -13.234832497594427, 'scoreMean': -19.963710264718976, 'scoreSelfplay': -18.960616476623688, 'scoreStdev': 20.125619040929173, 'utility': -0.8869855532624162, 'utilityLcb': -0.710554899867088, 'visits': 64, 'winrate': 0.0865925720006041, 'evaluation': 0.7800065883824968, 'outdatedScoreLead': -19.963710264718976}])
|
||||||
|
logs.append([{'lcb': 0.2780396932369631, 'move': 'C14', 'order': 2, 'prior': 0.11985918134450912, 'pv': ['C14', 'A3', 'A6', 'A4', 'A10', 'G8', 'B12', 'F5', 'A11'], 'scoreLead': -6.718795563515677, 'scoreMean': -15.893474225710637, 'scoreSelfplay': -15.203650210809267, 'scoreStdev': 22.044457012561093, 'utility': -0.6851691288815772, 'utilityLcb': -0.422485576723899, 'visits': 122, 'winrate': 0.18422413889493516, 'evaluation': 1.0768651808168639, 'outdatedScoreLead': -15.893474225710637}])
|
||||||
|
logs.append([{'lcb': -0.04419652907096561, 'move': 'A6', 'order': 1, 'prior': 0.25112441182136536, 'pv': ['A6', 'B2', 'C2', 'A3', 'B1', 'A2', 'C1', 'D10'], 'scoreLead': -30.647512138007034, 'scoreMean': -22.862077390041346, 'scoreSelfplay': -21.523760459148246, 'scoreStdev': 22.10661200254798, 'utility': -0.8707647010387976, 'utilityLcb': -1.2786073140053726, 'visits': 35, 'winrate': 0.10146154698852561, 'evaluation': 0.5179365909169477, 'outdatedScoreLead': -22.862077390041346}])
|
||||||
|
logs.append([{'lcb': -0.04419652907096561, 'move': 'A6', 'order': 1, 'prior': 0.25112441182136536, 'pv': ['A6', 'B2', 'C2', 'A3', 'B1', 'A2', 'C1', 'D10'], 'scoreLead': -30.647512138007034, 'scoreMean': -22.862077390041346, 'scoreSelfplay': -21.523760459148246, 'scoreStdev': 22.10661200254798, 'utility': -0.8707647010387976, 'utilityLcb': -1.2786073140053726, 'visits': 35, 'winrate': 0.10146154698852561, 'evaluation': 0.2362162847661815, 'outdatedScoreLead': -22.862077390041346}])
|
||||||
|
logs.append([{'lcb': 1.054309982706412, 'move': 'A11', 'order': 7, 'prior': 0.2366078794002533, 'pv': ['A11', 'A4', 'R9', 'D5', 'Q10'], 'scoreLead': 6.910397638811527, 'scoreMean': 4.639930709907449, 'scoreSelfplay': 5.535607733520525, 'scoreStdev': 15.874905556161806, 'utility': 0.6591456525404961, 'utilityLcb': 1.379769560744805, 'visits': 12, 'winrate': 0.7969443012048731, 'evaluation': 0.28741264032782, 'outdatedScoreLead': 4.639930709907449}])
|
||||||
|
logs.append([{'lcb': 1.006487464714684, 'move': 'H11', 'order': 2, 'prior': 0.2041485607624054, 'pv': ['H11', 'G10', 'H7', 'H1', 'G2', 'K2'], 'scoreLead': 52.47195084132946, 'scoreMean': 46.81754482750254, 'scoreSelfplay': 46.92620595873263, 'scoreStdev': 27.67551678483527, 'utility': 1.067884055424014, 'utilityLcb': 1.1097375772381621, 'visits': 24, 'winrate': 0.9915397783524882, 'outdatedScoreLead': 45.208157412185365}])
|
||||||
Reference in new issue
Block a user