more bug fixes
This commit is contained in:
1 parent
99930f4a7c
commit
c1dc9c87fc
4 files changed
+44
-52
No files matched your search
@@ -54,12 +54,12 @@ class Move:
|
|||||||
def analysis_ready(self):
|
def analysis_ready(self):
|
||||||
return self.analysis and self.pass_analysis
|
return self.analysis and self.pass_analysis
|
||||||
|
|
||||||
def format_score(self,score=None):
|
def format_score(self, score=None):
|
||||||
score = score or self.score
|
score = score or self.score
|
||||||
return f"{'B' if score >= 0 else 'W'}+{abs(score):.1f}"
|
return f"{'B' if score >= 0 else 'W'}+{abs(score):.1f}"
|
||||||
|
|
||||||
def comment(self,sgf=False, eval=False, hints=False):
|
def comment(self, sgf=False, eval=False, hints=False):
|
||||||
if not self.parent: # root
|
if not self.parent: # root
|
||||||
return ""
|
return ""
|
||||||
text = f"Move {self.move_number}: {self.bw_player()} {self.gtp()} {'(AI Move)' if self.robot else ''}\n"
|
text = f"Move {self.move_number}: {self.bw_player()} {self.gtp()} {'(AI Move)' if self.robot else ''}\n"
|
||||||
text += self.x_comment
|
text += self.x_comment
|
||||||
@@ -89,8 +89,8 @@ class Move:
|
|||||||
if points_lost > 0.5:
|
if points_lost > 0.5:
|
||||||
text += f"Estimate point loss: {points_lost:.1f}\n"
|
text += f"Estimate point loss: {points_lost:.1f}\n"
|
||||||
|
|
||||||
if eval or sgf: # show undos on move itself in both sgf and while playing
|
if eval or sgf: # show undos on move itself in both sgf and while playing
|
||||||
undids = [m.gtp() + (f"({m.evaluation_info[0]*100:.1f}% efficient)" if m.evaluation_info[0] else "") for m in self.parent.children if m!=self]
|
undids = [m.gtp() + (f"({m.evaluation_info[0]*100:.1f}% efficient)" if m.evaluation_info[0] else "") for m in self.parent.children if m != self]
|
||||||
if undids:
|
if undids:
|
||||||
text += "Other attempted move(s): " + ", ".join(undids) + "\n"
|
text += "Other attempted move(s): " + ", ".join(undids) + "\n"
|
||||||
|
|
||||||
@@ -104,13 +104,13 @@ class Move:
|
|||||||
if self.parent and self.parent.analysis_ready and self.analysis_ready:
|
if self.parent and self.parent.analysis_ready and self.analysis_ready:
|
||||||
return self.evaluation, self.parent.temperature_stats[2]
|
return self.evaluation, self.parent.temperature_stats[2]
|
||||||
else:
|
else:
|
||||||
return None,None
|
return None, None
|
||||||
|
|
||||||
# needing own analysis ready
|
# needing own analysis ready
|
||||||
@property
|
@property
|
||||||
def temperature_stats(self):
|
def temperature_stats(self):
|
||||||
best = float(self.analysis[0]["scoreLead"])
|
best = float(self.analysis[0]["scoreLead"])
|
||||||
worst= float(self.pass_analysis[0]["scoreLead"])
|
worst = float(self.pass_analysis[0]["scoreLead"])
|
||||||
return best, worst, abs(best - worst)
|
return best, worst, abs(best - worst)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -178,7 +178,6 @@ class Move:
|
|||||||
|
|
||||||
|
|
||||||
class Board:
|
class Board:
|
||||||
|
|
||||||
def __init__(self, board_size=19):
|
def __init__(self, board_size=19):
|
||||||
self.board_size = board_size
|
self.board_size = board_size
|
||||||
self.root = Move(1, (None, None)) # root is 1=white so black is first
|
self.root = Move(1, (None, None)) # root is 1=white so black is first
|
||||||
@@ -219,9 +218,7 @@ class Board:
|
|||||||
nb_chains = list({c for c in neighbours([move]) if c >= 0 and self.chains[c][0].player == move.player})
|
nb_chains = list({c for c in neighbours([move]) if c >= 0 and self.chains[c][0].player == move.player})
|
||||||
if nb_chains:
|
if nb_chains:
|
||||||
this_chain = nb_chains[0]
|
this_chain = nb_chains[0]
|
||||||
self.board = [
|
self.board = [[nb_chains[0] if sq in nb_chains else sq for sq in line] for line in self.board] # merge chains connected by this move
|
||||||
[nb_chains[0] if sq in nb_chains else sq for sq in line] for line in self.board
|
|
||||||
] # merge chains connected by this move
|
|
||||||
for oc in nb_chains[1:]:
|
for oc in nb_chains[1:]:
|
||||||
self.chains[nb_chains[0]] += self.chains[oc]
|
self.chains[nb_chains[0]] += self.chains[oc]
|
||||||
self.chains[oc] = []
|
self.chains[oc] = []
|
||||||
@@ -299,10 +296,7 @@ class Board:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def prisoner_count(self):
|
def prisoner_count(self):
|
||||||
return [sum([m.player==player for m in self.prisoners]) for player in [0,1]]
|
return [sum([m.player == player for m in self.prisoners]) for player in [0, 1]]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return "\n".join("".join(Move.PLAYERS[self.chains[c][0].player] if c >= 0 else "-" for c in l) for l in self.board) + f"\ncaptures: {self.prisoner_count}"
|
||||||
"\n".join("".join(Move.PLAYERS[self.chains[c][0].player] if c >= 0 else "-" for c in l) for l in self.board)
|
|
||||||
+ f"\ncaptures: {self.prisoner_count}"
|
|
||||||
)
|
|
||||||
+3
-1
@@ -7,7 +7,9 @@
|
|||||||
},
|
},
|
||||||
"board": {
|
"board": {
|
||||||
"size": 19,
|
"size": 19,
|
||||||
"komi": 6.5
|
"komi_19": 6.5,
|
||||||
|
"komi_13": 6.5,
|
||||||
|
"komi_9": 6.5
|
||||||
},
|
},
|
||||||
"ui": {
|
"ui": {
|
||||||
"size_min": 1,
|
"size_min": 1,
|
||||||
|
|||||||
+23
-27
@@ -22,17 +22,14 @@ class EngineControls(GridLayout):
|
|||||||
self.command = shlex.split(Config.get("engine")["command"])
|
self.command = shlex.split(Config.get("engine")["command"])
|
||||||
|
|
||||||
analysis_settings = Config.get("analysis")
|
analysis_settings = Config.get("analysis")
|
||||||
self.visits = [
|
self.visits = [[analysis_settings["pass_visits"], analysis_settings["visits"]], [analysis_settings["pass_visits_fast"], analysis_settings["visits_fast"]]]
|
||||||
[analysis_settings["pass_visits"], analysis_settings["visits"]],
|
|
||||||
[analysis_settings["pass_visits_fast"], analysis_settings["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.komi = Config.get("board")["komi"]
|
|
||||||
self.ready = False
|
self.ready = 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.outstanding_analysis_queries = [] # allows faster interaction while kata is starting
|
self.outstanding_analysis_queries = [] # allows faster interaction while kata is starting
|
||||||
self.kata = None
|
self.kata = None
|
||||||
|
|
||||||
@@ -87,11 +84,11 @@ class EngineControls(GridLayout):
|
|||||||
# mr.waiting_for_analysis
|
# mr.waiting_for_analysis
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def update_evaluation(self,undo_triggered = False):
|
def update_evaluation(self, undo_triggered=False):
|
||||||
current_move = self.board.current_move
|
current_move = self.board.current_move
|
||||||
if self.eval.active(current_move.player):
|
if self.eval.active(current_move.player):
|
||||||
self.info.text = current_move.comment(eval=self.eval.active(current_move.player), hints=self.hints.active(current_move.player))
|
self.info.text = current_move.comment(eval=self.eval.active(current_move.player), hints=self.hints.active(current_move.player))
|
||||||
self.evaluation.text = ''
|
self.evaluation.text = ""
|
||||||
if current_move.analysis_ready and self.eval.active(current_move.player):
|
if current_move.analysis_ready and self.eval.active(current_move.player):
|
||||||
self.score.text = current_move.format_score().replace("-", "\u2013")
|
self.score.text = current_move.format_score().replace("-", "\u2013")
|
||||||
self.temperature.text = f"{current_move.temperature_stats[2]:.1f}"
|
self.temperature.text = f"{current_move.temperature_stats[2]:.1f}"
|
||||||
@@ -111,7 +108,7 @@ class EngineControls(GridLayout):
|
|||||||
self.board.undo()
|
self.board.undo()
|
||||||
undo_triggered = True
|
undo_triggered = True
|
||||||
if len(current_move.parent.children) >= ts["num_undo_prompts"] + 1:
|
if len(current_move.parent.children) >= ts["num_undo_prompts"] + 1:
|
||||||
best_move = sorted([m for m in current_move.parent.children], key=lambda m: -(m.evaluation_info[0] or 0) )[0]
|
best_move = sorted([m for m in current_move.parent.children], key=lambda m: -(m.evaluation_info[0] or 0))[0]
|
||||||
best_move.x_comment = f"Automatically played as best option after max. {ts['num_undo_prompts']} undo(s).\n"
|
best_move.x_comment = f"Automatically played as best option after max. {ts['num_undo_prompts']} undo(s).\n"
|
||||||
self.board.play(best_move)
|
self.board.play(best_move)
|
||||||
self.update_evaluation(undo_triggered=True)
|
self.update_evaluation(undo_triggered=True)
|
||||||
@@ -127,24 +124,21 @@ class EngineControls(GridLayout):
|
|||||||
|
|
||||||
# select move
|
# select move
|
||||||
current_move = self.board.current_move
|
current_move = self.board.current_move
|
||||||
pos_moves = [
|
pos_moves = [(d["move"], float(d["scoreMean"]), d["evaluation"]) for d in current_move.ai_moves if int(d["visits"]) >= ts["balance_play_min_visits"]]
|
||||||
(d["move"], float(d["scoreMean"]), d["evaluation"])
|
sel_moves = pos_moves[:1]
|
||||||
for d in current_move.ai_moves
|
|
||||||
if int(d["visits"]) >= ts["balance_play_min_visits"]
|
|
||||||
]
|
|
||||||
sel_moves = [pos_moves[0][0]]
|
|
||||||
# don't play suicidal to balance score - pass when it's best
|
# don't play suicidal to balance score - pass when it's best
|
||||||
if self.ai_balance.active and pos_moves[0][0] != "pass":
|
if self.ai_balance.active and pos_moves[0][0] != "pass":
|
||||||
sel_moves = [
|
sel_moves = [
|
||||||
move
|
(move, score, eval)
|
||||||
for move, score, eval in pos_moves
|
for move, score, eval in pos_moves
|
||||||
if eval > ts["balance_play_randomize_eval"]
|
if eval > ts["balance_play_randomize_eval"]
|
||||||
|
and -current_move.player_sign * score > 0
|
||||||
or eval > ts["balance_play_min_eval"]
|
or eval > ts["balance_play_min_eval"]
|
||||||
and -current_move.player_sign * score > ts["balance_play_target_score"]
|
and -current_move.player_sign * score > ts["balance_play_target_score"]
|
||||||
] or sel_moves
|
] or sel_moves
|
||||||
aimove = Move(player=self.board.current_player, gtpcoords=random.choice(sel_moves), robot=True)
|
aimove = Move(player=self.board.current_player, gtpcoords=random.choice(sel_moves)[0], robot=True)
|
||||||
if len(sel_moves) > 1:
|
if len(sel_moves) > 1:
|
||||||
aimove.x_comment = "{'AI Balance on, moves considered: " + ", ".join(f"{move} ({aimove.format_score(score)})" for move, score, eval in sel_moves) + "\n"
|
aimove.x_comment = "AI Balance on, moves considered: " + ", ".join(f"{move} ({aimove.format_score(score)})" for move, score, _ in sel_moves) + "\n"
|
||||||
self.play(aimove)
|
self.play(aimove)
|
||||||
|
|
||||||
def _do_undo(self):
|
def _do_undo(self):
|
||||||
@@ -159,22 +153,20 @@ class EngineControls(GridLayout):
|
|||||||
return
|
return
|
||||||
self.board.undo()
|
self.board.undo()
|
||||||
|
|
||||||
def _do_init(self, board_size, komi=None):
|
def _do_init(self, board_size):
|
||||||
self.board_size = board_size
|
self.board_size = board_size
|
||||||
|
self.komi = Config.get("board")[f"komi_{board_size}"]
|
||||||
self.board = Board(board_size)
|
self.board = Board(board_size)
|
||||||
self._request_analysis(self.board.root)
|
self._request_analysis(self.board.root)
|
||||||
self.redraw(include_board=True)
|
self.redraw(include_board=True)
|
||||||
self.ready = True
|
self.ready = True
|
||||||
|
|
||||||
def _do_analyze_sgf(self, sgf):
|
def _do_analyze_sgf(self, sgf):
|
||||||
self._do_init(self.board_size, self.komi)
|
self._do_init(self.board_size)
|
||||||
sgfmoves = re.findall(r"([BW])\[([a-z]{2})\]", sgf)
|
sgfmoves = re.findall(r"([BW])\[([a-z]{2})\]", sgf)
|
||||||
moves = [Move(player=Move.PLAYERS.index(p.upper()), sgfcoords=(mv, self.board_size)) for p, mv in sgfmoves]
|
moves = [Move(player=Move.PLAYERS.index(p.upper()), sgfcoords=(mv, self.board_size)) for p, mv in sgfmoves]
|
||||||
for move in moves:
|
for move in moves:
|
||||||
self.play(move)
|
self.play(move)
|
||||||
while not all(m.analysis for m in moves):
|
|
||||||
time.sleep(0.05)
|
|
||||||
self.info.text = f"{sum([1 if m.analysis else 0 for m in moves])}/{len(moves)} analyzed"
|
|
||||||
|
|
||||||
# analysis thread
|
# analysis thread
|
||||||
def _analysis_read_thread(self):
|
def _analysis_read_thread(self):
|
||||||
@@ -213,9 +205,7 @@ class EngineControls(GridLayout):
|
|||||||
if self.debug:
|
if self.debug:
|
||||||
print("query", query)
|
print("query", query)
|
||||||
self._send_analysis_query(query)
|
self._send_analysis_query(query)
|
||||||
query.update(
|
query.update({"id": f"PASS_{move_id}", "maxVisits": self.visits[fast][0], "includeOwnership": False})
|
||||||
{"id": f"PASS_{move_id}", "maxVisits": self.visits[fast][0], "includeOwnership": False}
|
|
||||||
)
|
|
||||||
query["moves"] += [[move.bw_player(next_move=True), "pass"]]
|
query["moves"] += [[move.bw_player(next_move=True), "pass"]]
|
||||||
query["analyzeTurns"][0] += 1
|
query["analyzeTurns"][0] += 1
|
||||||
self._send_analysis_query(query)
|
self._send_analysis_query(query)
|
||||||
@@ -225,13 +215,19 @@ class EngineControls(GridLayout):
|
|||||||
return f"(;GM[1]FF[4]SZ[{self.board_size}]KM[{self.komi}]RU[JP];" + ";".join(mvs) + ")"
|
return f"(;GM[1]FF[4]SZ[{self.board_size}]KM[{self.komi}]RU[JP];" + ";".join(mvs) + ")"
|
||||||
|
|
||||||
def format_move(move, prev_move):
|
def format_move(move, prev_move):
|
||||||
undos = [m for m in prev_move.children if m!=move]
|
undos = [m for m in prev_move.children if m != move]
|
||||||
undo_cr = "".join(f"MA[{u.sgfcoords(self.board_size)}]" for u in undos if u.coords[0])
|
undo_cr = "".join(f"MA[{u.sgfcoords(self.board_size)}]" for u in undos if u.coords[0])
|
||||||
if prev_move.analysis and prev_move.analysis[0]["move"] != "pass" and (move.evaluation_info[0] or 0.0) < self.train_settings['sgf_show_best_move_threshold']:
|
if (
|
||||||
|
prev_move.analysis
|
||||||
|
and prev_move.analysis[0]["move"] != "pass"
|
||||||
|
and (move.evaluation_info[0] or 0.0) < self.train_settings["sgf_show_best_move_threshold"]
|
||||||
|
and prev_move.analysis[0]["move"] != move.gtp()
|
||||||
|
):
|
||||||
best_sq = f"SQ[{Move(gtpcoords=prev_move.analysis[0]['move'], player=0).sgfcoords(self.board_size)}]"
|
best_sq = f"SQ[{Move(gtpcoords=prev_move.analysis[0]['move'], player=0).sgfcoords(self.board_size)}]"
|
||||||
else:
|
else:
|
||||||
best_sq = ""
|
best_sq = ""
|
||||||
return move.sgf(self.board_size) + f"C[{move.comment(sgf=True)}]{undo_cr}{best_sq}"
|
return move.sgf(self.board_size) + f"C[{move.comment(sgf=True)}]{undo_cr}{best_sq}"
|
||||||
|
|
||||||
moves = self.board.moves
|
moves = self.board.moves
|
||||||
sgfmoves_small = [mv.sgf(self.board_size) for mv in moves]
|
sgfmoves_small = [mv.sgf(self.board_size) for mv in moves]
|
||||||
sgfmoves = [format_move(mv, pmv) for mv, pmv in zip(moves, [self.board.root] + moves[:-1])]
|
sgfmoves = [format_move(mv, pmv) for mv, pmv in zip(moves, [self.board.root] + moves[:-1])]
|
||||||
|
|||||||
+8
-8
@@ -50,25 +50,25 @@ class BadukPanWidget(Widget):
|
|||||||
else:
|
else:
|
||||||
xd, xp = self._find_closest(touch.x)
|
xd, xp = self._find_closest(touch.x)
|
||||||
yd, yp = self._find_closest(touch.y)
|
yd, yp = self._find_closest(touch.y)
|
||||||
stones_here = [m for m in self.engine.board.stones if m.coords == (xp,yp)]
|
stones_here = [m for m in self.engine.board.stones if m.coords == (xp, yp)]
|
||||||
if stones_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
if stones_here and max(yd, xd) < self.grid_size / 2: # load old comment
|
||||||
self.engine.info.text = stones_here[-1].comment(sgf=True)
|
self.engine.info.text = stones_here[-1].comment(sgf=True)
|
||||||
self.ghost_stone = None
|
self.ghost_stone = None
|
||||||
self.redraw() # remove ghost
|
self.redraw() # remove ghost
|
||||||
|
|
||||||
# drawing functions
|
# drawing functions
|
||||||
def on_size(self, *args):
|
def on_size(self, *args):
|
||||||
self.draw_board()
|
self.draw_board()
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def draw_stone(self, x, y, col, innercol=None, evalcol=None, evalsize=10.0):
|
def draw_stone(self, x, y, col, innercol=None, evalcol=None, evalsize=10.0, scale=1.0):
|
||||||
draw_circle((self.gridpos[x], self.gridpos[y]), self.stone_size, col)
|
draw_circle((self.gridpos[x], self.gridpos[y]), self.stone_size * scale, col)
|
||||||
if evalcol:
|
if evalcol:
|
||||||
evalsize = min(self.EVAL_BOUNDS[1], max(evalsize, self.EVAL_BOUNDS[0])) / self.EVAL_BOUNDS[1]
|
evalsize = min(self.EVAL_BOUNDS[1], max(evalsize, self.EVAL_BOUNDS[0])) / self.EVAL_BOUNDS[1]
|
||||||
draw_circle((self.gridpos[x], self.gridpos[y]), math.sqrt(evalsize) * self.stone_size * 0.5, evalcol)
|
draw_circle((self.gridpos[x], self.gridpos[y]), math.sqrt(evalsize) * self.stone_size * scale * 0.5, evalcol)
|
||||||
if innercol:
|
if innercol:
|
||||||
Color(*innercol)
|
Color(*innercol)
|
||||||
Line(circle=(self.gridpos[x], self.gridpos[y], self.stone_size * 0.45 / 0.85), width=1.75)
|
Line(circle=(self.gridpos[x], self.gridpos[y], self.stone_size * scale * 0.45 / 0.85), width=1.75)
|
||||||
|
|
||||||
def _eval_spectrum(self, score):
|
def _eval_spectrum(self, score):
|
||||||
score = max(0, score)
|
score = max(0, score)
|
||||||
@@ -153,11 +153,11 @@ class BadukPanWidget(Widget):
|
|||||||
|
|
||||||
# hints
|
# hints
|
||||||
if self.engine.hints.active(current_player):
|
if self.engine.hints.active(current_player):
|
||||||
for d in last_move.ai_moves:
|
for i, d in enumerate(last_move.ai_moves):
|
||||||
move = Move(gtpcoords=d["move"], player=0)
|
move = Move(gtpcoords=d["move"], player=0)
|
||||||
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)
|
self.draw_stone(move.coords[0], move.coords[1], c, scale=1.0 if i == 0 else 0.8)
|
||||||
|
|
||||||
# hover next move ghost stone
|
# hover next move ghost stone
|
||||||
if self.ghost_stone:
|
if self.ghost_stone:
|
||||||
|
|||||||
Reference in new issue
Block a user