* distributed option * i18n, pause, etc * fixes galore * max buffer etc * test override config * maxgame * visit * contribute menu * restore vars * i18n * actually start * retry distr and errors * pw eye / move speed * cfg/no log * shutdown fix * shutdown fix * download fix * wut * stats and desc * esc fix * Omit terminate queries from KataGoEngine.queries. (#353) * press key h to clear current node analysis. (#352) * clear current node all analysis * add reset key binding * reset all analysis off. * code refactor * code change according to review. * remove useless variable * code review changes * clean up reset node * oops * Setup position feature (#354) * go for zebras * setup working! * uhh * tweak * img * fix i18n * AEEEEEEEEEE and stop * link in readme * new game options for edit/new/setup (#357) * new game options for edit/new/setup * feedback * fix * ai thoughts * no tristate cb * branch fixing (#358) * new game options for edit/new/setup * feedback * fix * ai thoughts * no tristate cb * fix comma etc * normal katago * kata * dll * save window pos/size * BAD comma * new linux binary + allow default engine * fix * unused icon, build mac * exe * player new game fix * fix i18n * test test * just print * 한국어 * 활성화 * Add new Traditional Chinese translation (#362) Improve some translations as well. * cn (#363) * cn * rm old * rm old * informal you * mo * jp (#364) * config and readme * mo * kgtraining * fix score * lower stddev a bit * tweak weights * 1.8 French Po (#365) * fr and getattr fix * -DBUILD_DISTRIBUTED=1 * openssl * openssl * openssl * openssl * config * jp (num undos) (#366) * clarify undo in en, po->mo * fix player name * new kata * new kata * Load game option save config (#367) * in the load dialog, "load fast analysis" and "rewind to the start" option ,save to config file * in the load dialog, "load fast analysis" and "rewind to the start" option ,save to config file * default option * remove useless override * save check state when file dialog's submit event , * save config in callback * readme * active games * de * log games as json always * black * Russian localization for 1.8.0 (#375) * ru Co-authored-by: pdeblanc <peter@spaceandgames.com> Co-authored-by: xiaoyifang <105986+xiaoyifang@users.noreply.github.com> Co-authored-by: Liou, Guan-Cheng <Tony-Liou@users.noreply.github.com> Co-authored-by: kaorahi <38910552+kaorahi@users.noreply.github.com> Co-authored-by: Dontbtme <66470440+Dontbtme@users.noreply.github.com> Co-authored-by: Alexander Kiselev <satoshi.yoda.register.264@gmail.com>
101 lines
2.9 KiB
Python
101 lines
2.9 KiB
Python
import heapq
|
|
import math
|
|
import os
|
|
import random
|
|
import struct
|
|
import sys
|
|
from typing import List, Tuple, TypeVar
|
|
|
|
try:
|
|
import importlib.resources as pkg_resources
|
|
except ImportError:
|
|
import importlib_resources as pkg_resources
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
def var_to_grid(array_var: List[T], size: Tuple[int, int]) -> List[List[T]]:
|
|
"""convert ownership/policy to grid format such that grid[y][x] is for move with coords x,y"""
|
|
ix = 0
|
|
grid = [[]] * size[1]
|
|
for y in range(size[1] - 1, -1, -1):
|
|
grid[y] = array_var[ix : ix + size[0]]
|
|
ix += size[0]
|
|
return grid
|
|
|
|
|
|
def evaluation_class(points_lost: float, eval_thresholds: List[float]):
|
|
i = 0
|
|
while i < len(eval_thresholds) - 1 and points_lost < eval_thresholds[i]:
|
|
i += 1
|
|
return i
|
|
|
|
|
|
def check_thread(tb=False): # for checking if draws occur in correct thread
|
|
import threading
|
|
|
|
print("build in ", threading.current_thread().ident)
|
|
if tb:
|
|
import traceback
|
|
|
|
traceback.print_stack()
|
|
|
|
|
|
PATHS = {}
|
|
|
|
|
|
def find_package_resource(path, silent_errors=False):
|
|
global PATHS
|
|
if path.startswith("katrain"):
|
|
if not PATHS.get("PACKAGE"):
|
|
try:
|
|
with pkg_resources.path("katrain", "gui.kv") as p:
|
|
PATHS["PACKAGE"] = os.path.split(str(p))[0]
|
|
except (ModuleNotFoundError, FileNotFoundError, ValueError) as e:
|
|
print(f"Package path not found, installation possibly broken. Error: {e}", file=sys.stderr)
|
|
return f"FILENOTFOUND/{path}"
|
|
return os.path.join(PATHS["PACKAGE"], path.replace("katrain\\", "katrain/").replace("katrain/", ""))
|
|
else:
|
|
return os.path.abspath(os.path.expanduser(path)) # absolute path
|
|
|
|
|
|
def pack_floats(float_list):
|
|
if float_list is None:
|
|
return b""
|
|
return struct.pack(f"{len(float_list)}e", *float_list)
|
|
|
|
|
|
def unpack_floats(str, num):
|
|
if not str:
|
|
return None
|
|
return struct.unpack(f"{num}e", str)
|
|
|
|
|
|
def format_visits(n):
|
|
if n < 1000:
|
|
return str(n)
|
|
if n < 1e5:
|
|
return f"{n/1000:.1f}k"
|
|
if n < 1e6:
|
|
return f"{n/1000:.0f}k"
|
|
return f"{n/1e6:.0f}k"
|
|
|
|
|
|
def json_truncate_arrays(data, lim=20):
|
|
if isinstance(data, list):
|
|
if data and isinstance(data[0], dict):
|
|
return [json_truncate_arrays(d) for d in data]
|
|
if len(data) > lim:
|
|
data = [f"{len(data)} x {type(data[0]).__name__}"]
|
|
return data
|
|
elif isinstance(data, dict):
|
|
return {k: json_truncate_arrays(v) for k, v in data.items()}
|
|
else:
|
|
return data
|
|
|
|
|
|
def weighted_selection_without_replacement(items: List[Tuple], pick_n: int) -> List[Tuple]:
|
|
"""For a list of tuples where the second element is a weight, returns random items with those weights, without replacement."""
|
|
elt = [(math.log(random.random()) / (item[1] + 1e-18), item) for item in items] # magic
|
|
return [e[1] for e in heapq.nlargest(pick_n, elt)] # NB fine if too small
|