optimization, bot fixes
This commit is contained in:
1 parent
de0d99e11a
commit
b9aec4b6dd
12 files changed
+69325
-37
No files matched your search
+21
-3
@@ -2,6 +2,7 @@
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import random
|
||||
|
||||
from core.ai import ai_move
|
||||
from core.common import OUTPUT_ERROR, OUTPUT_INFO
|
||||
@@ -103,8 +104,14 @@ while True:
|
||||
logger.log(f"Setting komi {game.root.properties}", OUTPUT_ERROR)
|
||||
elif "place_free_handicap" in line:
|
||||
_, n = line.split(" ")
|
||||
game.place_handicap_stones(int(n))
|
||||
gtp = [Move.from_sgf(m, game.board_size, "B").gtp() for m in game.root.get_list_property("AB")]
|
||||
n = int(n)
|
||||
game.place_handicap_stones(n)
|
||||
handicaps = set(game.root.get_list_property("AB"))
|
||||
bx, by = game.board_size
|
||||
while len(handicaps) < min(n, bx * by): # really obscure cases
|
||||
handicaps.add(Move((random.randint(0, bx - 1), random.randint(0, by - 1)), player="B").sgf(board_size=game.board_size))
|
||||
game.root.set_property("AB", list(handicaps))
|
||||
gtp = [Move.from_sgf(m, game.board_size, "B").gtp() for m in handicaps]
|
||||
logger.log(f"Chose handicap placements as {gtp}", OUTPUT_ERROR)
|
||||
print(f"= {' '.join(gtp)}\n")
|
||||
sys.stdout.flush()
|
||||
@@ -115,6 +122,12 @@ while True:
|
||||
game.root.set_property("AB", [Move.from_gtp(move.upper()).sgf(game.board_size) for move in stones])
|
||||
logger.log(f"Set handicap placements to {game.root.get_list_property('AB')}", OUTPUT_ERROR)
|
||||
elif "genmove" in line:
|
||||
_, player = line.strip().split(" ")
|
||||
if player[0].upper() != game.next_player:
|
||||
logger.log(f"ERROR generating move: UNEXPECTED PLAYER {player} != {game.next_player}.", OUTPUT_ERROR)
|
||||
print(f"= ??\n")
|
||||
sys.stdout.flush()
|
||||
continue
|
||||
logger.log(f"{ai_strategy} generating move", OUTPUT_ERROR)
|
||||
game.current_node.analyze(engine)
|
||||
malkovich_analysis(game.current_node)
|
||||
@@ -130,7 +143,12 @@ while True:
|
||||
move = game.play(Move(None, player=game.next_player)).single_move
|
||||
else:
|
||||
move, node = ai_move(game, ai_strategy, ai_settings)
|
||||
logger.log(f"Generated move {move}", OUTPUT_ERROR)
|
||||
if node is None:
|
||||
while node is None:
|
||||
logger.log(f"ERROR generating move, backing up with weighted.", OUTPUT_ERROR)
|
||||
move, node = ai_move(game, "p:weighted", {"pick_override": 1.0, "lower_bound": 0.001, "weaken_fac": 1})
|
||||
else:
|
||||
logger.log(f"Generated move {move}", OUTPUT_ERROR)
|
||||
print(f"= {move.gtp()}\n")
|
||||
sys.stdout.flush()
|
||||
malkovich_analysis(game.current_node)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+26
-24
@@ -34,8 +34,7 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
|
||||
raise EngineDiedException(f"Engine for {cn.next_player} ({engine.config}) died")
|
||||
ai_mode = ai_mode.lower()
|
||||
ai_thoughts = ""
|
||||
candidate_ai_moves = cn.candidate_moves
|
||||
if ("policy" in ai_mode or "p:" in ai_mode) and cn.policy:
|
||||
if ("policy" in ai_mode or "p:" in ai_mode) and cn.policy: # pure policy based move
|
||||
policy_moves = cn.policy_ranking
|
||||
pass_policy = cn.policy[-1]
|
||||
top_5_pass = any([polmove[1].is_pass for polmove in policy_moves[:5]]) # dont make it jump around for the last few sensible non pass moves
|
||||
@@ -131,28 +130,30 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
|
||||
ai_thoughts += f"Pick policy strategy {ai_mode} failed to find legal moves, so is playing top policy move {aimove.gtp()}."
|
||||
else:
|
||||
raise ValueError(f"Unknown AI mode {ai_mode}")
|
||||
elif "balance" in ai_mode and candidate_ai_moves[0]["move"] != "pass": # don't play suicidal to balance score - pass when it's best
|
||||
sign = cn.player_sign(cn.next_player)
|
||||
sel_moves = [ # top move, or anything not too bad, or anything that makes you still ahead
|
||||
move
|
||||
for i, move in enumerate(candidate_ai_moves)
|
||||
if i == 0
|
||||
or move["visits"] >= ai_settings["min_visits"]
|
||||
and (move["pointsLost"] < ai_settings["random_loss"] or move["pointsLost"] < ai_settings["max_loss"] and sign * move["scoreLead"] > ai_settings["target_score"])
|
||||
]
|
||||
aimove = Move.from_gtp(random.choice(sel_moves)["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Balance strategy selected moves {sel_moves} based on target score and max points lost, and randomly chose {aimove.gtp()}."
|
||||
elif "jigo" in ai_mode and candidate_ai_moves[0]["move"] != "pass":
|
||||
sign = cn.player_sign(cn.next_player)
|
||||
jigo_move = min(candidate_ai_moves, key=lambda move: abs(sign * move["scoreLead"] - ai_settings["target_score"]))
|
||||
aimove = Move.from_gtp(jigo_move["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Jigo strategy found candidate moves {candidate_ai_moves} moves and chose {aimove.gtp()} as closest to 0.5 point win"
|
||||
else:
|
||||
if "default" not in ai_mode and "katago" not in ai_mode:
|
||||
game.katrain.log(f"Unknown AI mode {ai_mode} or policy missing, using default.", OUTPUT_INFO)
|
||||
ai_thoughts += f"Strategy {ai_mode} not found or unexpected fallback."
|
||||
aimove = Move.from_gtp(candidate_ai_moves[0]["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Default strategy found {len(candidate_ai_moves)} moves returned from the engine and chose {aimove.gtp()} as top move"
|
||||
else: # Engine based move
|
||||
candidate_ai_moves = cn.candidate_moves
|
||||
if "balance" in ai_mode and candidate_ai_moves[0]["move"] != "pass": # don't play suicidal to balance score - pass when it's best
|
||||
sign = cn.player_sign(cn.next_player)
|
||||
sel_moves = [ # top move, or anything not too bad, or anything that makes you still ahead
|
||||
move
|
||||
for i, move in enumerate(candidate_ai_moves)
|
||||
if i == 0
|
||||
or move["visits"] >= ai_settings["min_visits"]
|
||||
and (move["pointsLost"] < ai_settings["random_loss"] or move["pointsLost"] < ai_settings["max_loss"] and sign * move["scoreLead"] > ai_settings["target_score"])
|
||||
]
|
||||
aimove = Move.from_gtp(random.choice(sel_moves)["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Balance strategy selected moves {sel_moves} based on target score and max points lost, and randomly chose {aimove.gtp()}."
|
||||
elif "jigo" in ai_mode and candidate_ai_moves[0]["move"] != "pass":
|
||||
sign = cn.player_sign(cn.next_player)
|
||||
jigo_move = min(candidate_ai_moves, key=lambda move: abs(sign * move["scoreLead"] - ai_settings["target_score"]))
|
||||
aimove = Move.from_gtp(jigo_move["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Jigo strategy found candidate moves {candidate_ai_moves} moves and chose {aimove.gtp()} as closest to 0.5 point win"
|
||||
else:
|
||||
if "default" not in ai_mode and "katago" not in ai_mode:
|
||||
game.katrain.log(f"Unknown AI mode {ai_mode} or policy missing, using default.", OUTPUT_INFO)
|
||||
ai_thoughts += f"Strategy {ai_mode} not found or unexpected fallback."
|
||||
aimove = Move.from_gtp(candidate_ai_moves[0]["move"], player=cn.next_player)
|
||||
ai_thoughts += f"Default strategy found {len(candidate_ai_moves)} moves returned from the engine and chose {aimove.gtp()} as top move"
|
||||
game.katrain.log(f"AI thoughts: {ai_thoughts}", OUTPUT_DEBUG)
|
||||
try:
|
||||
played_node = game.play(aimove)
|
||||
@@ -160,3 +161,4 @@ def ai_move(game: Game, ai_mode: str, ai_settings: Dict) -> Tuple[Move, GameNode
|
||||
return aimove, played_node
|
||||
except IllegalMoveException as e:
|
||||
game.katrain.log(f"AI Strategy {ai_mode} generated illegal move {aimove.gtp()}: {e}", OUTPUT_ERROR)
|
||||
return None, None
|
||||
+3
-5
@@ -154,10 +154,8 @@ class Game:
|
||||
|
||||
def place_handicap_stones(self, n_handicaps):
|
||||
board_size_x, board_size_y = self.board_size
|
||||
near_x = 3 if board_size_x >= 13 else 2
|
||||
near_y = 3 if board_size_y >= 13 else 2
|
||||
if board_size_x < 3 or board_size_y < 3:
|
||||
return
|
||||
near_x = 3 if board_size_x >= 13 else min(2, board_size_x - 1)
|
||||
near_y = 3 if board_size_y >= 13 else min(2, board_size_y - 1)
|
||||
far_x = board_size_x - 1 - near_x
|
||||
far_y = board_size_y - 1 - near_y
|
||||
middle_x = board_size_x // 2 # what for even sizes?
|
||||
@@ -176,7 +174,7 @@ class Game:
|
||||
if n_handicaps % 2 == 1:
|
||||
stones.append((middle_x, middle_y))
|
||||
stones += [(near_x, middle_y), (far_x, middle_y), (middle_x, near_y), (middle_x, far_y)]
|
||||
self.root.set_property("AB", [Move(stone).sgf(board_size=(board_size_x, board_size_y)) for stone in stones[:n_handicaps]])
|
||||
self.root.set_property("AB", list({Move(stone).sgf(board_size=(board_size_x, board_size_y)) for stone in stones[:n_handicaps]}))
|
||||
|
||||
@property
|
||||
def board_size(self):
|
||||
|
||||
+4
-3
@@ -79,10 +79,11 @@ class SGFNode:
|
||||
|
||||
def sgf(self, **xargs) -> str:
|
||||
"""Generates an SGF, calling sgf_properties on each node with the given xargs, so it can filter relevant properties if needed."""
|
||||
import sys
|
||||
if self.is_root:
|
||||
import sys
|
||||
|
||||
bszx, bszy = self.board_size
|
||||
sys.setrecursionlimit(max(sys.getrecursionlimit(), 3 * bszx * bszy)) # thanks to lightvector for causing stack overflows ;)
|
||||
bszx, bszy = self.board_size
|
||||
sys.setrecursionlimit(max(sys.getrecursionlimit(), 4 * bszx * bszy))
|
||||
sgf_str = "".join([prop + "".join(f"[{v}]" for v in values) for prop, values in self.sgf_properties(**xargs).items() if values])
|
||||
if self.children:
|
||||
children = [c.sgf(**xargs) for c in self.order_children(self.children)]
|
||||
|
||||
+2
-2
@@ -133,7 +133,7 @@ class ConfigPopup(QuickConfigGui):
|
||||
col_container.add_widget(cols[0])
|
||||
col_container.add_widget(cols[1])
|
||||
self.add_widget(col_container)
|
||||
self.info_label = Label(halign='center')
|
||||
self.info_label = Label(halign="center")
|
||||
self.apply_button = StyledButton(text="Apply", on_press=lambda _: self.update_config())
|
||||
self.save_button = StyledButton(text="Apply and Save", on_press=lambda _: self.update_config(save_to_file=True))
|
||||
btn_container = BoxLayout(orientation="horizontal", size_hint=(1, 0.1), spacing=1, padding=1)
|
||||
@@ -170,7 +170,7 @@ class ConfigPopup(QuickConfigGui):
|
||||
|
||||
def restart_engine(_dt):
|
||||
old_engine = self.katrain.engine # type: KataGoEngine
|
||||
old_proc =old_engine.katago_process
|
||||
old_proc = old_engine.katago_process
|
||||
if old_proc:
|
||||
old_engine.shutdown(finish=True)
|
||||
|
||||
|
||||
Reference in new issue
Block a user