6 files changed
+58
-38
No files matched your search
@@ -13,6 +13,8 @@ sgf_ogs
|
||||
log*
|
||||
tmp.pickle
|
||||
my
|
||||
logs
|
||||
callgrind.*
|
||||
|
||||
# debug
|
||||
outdated_log.txt
|
||||
|
||||
+21
-4
@@ -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
|
||||
@@ -85,7 +86,6 @@ def malkovich_analysis(cn):
|
||||
|
||||
|
||||
while True:
|
||||
p = game.current_node.next_player
|
||||
line = input()
|
||||
logger.log(f"GOT INPUT {line}", OUTPUT_ERROR)
|
||||
if "boardsize" in line:
|
||||
@@ -103,8 +103,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 +121,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 +142,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)
|
||||
|
||||
+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