player info
This commit is contained in:
1 parent
97dc12df10
commit
671a764c6a
25 files changed
+457
-213
No files matched your search
+5
-1
@@ -4,6 +4,10 @@ import yappi
|
||||
|
||||
from katrain.__main__ import run_app
|
||||
|
||||
yappi.set_clock_type("cpu")
|
||||
yappi.start()
|
||||
run_app()
|
||||
try:
|
||||
run_app()
|
||||
except:
|
||||
pass
|
||||
yappi.get_func_stats().save("callgrind.out." + datetime.now().isoformat(), "CALLGRIND")
|
||||
+18
-19
@@ -23,23 +23,16 @@ from kivy.storage.jsonstore import JsonStore
|
||||
from kivy.uix.popup import Popup
|
||||
from kivy.uix.screenmanager import Screen
|
||||
from kivymd.app import MDApp
|
||||
from katrain.core.constants import *
|
||||
from katrain.core.ai import ai_move
|
||||
from katrain.core.utils import (
|
||||
DEFAULT_LANGUAGE,
|
||||
OUTPUT_DEBUG,
|
||||
OUTPUT_ERROR,
|
||||
OUTPUT_EXTRA_DEBUG,
|
||||
OUTPUT_INFO,
|
||||
OUTPUT_KATAGO_STDERR,
|
||||
find_package_resource,
|
||||
i18n,
|
||||
MODE_PLAY,
|
||||
switch_lang,
|
||||
)
|
||||
from katrain.core.constants import OUTPUT_ERROR, OUTPUT_KATAGO_STDERR, OUTPUT_INFO, OUTPUT_DEBUG, OUTPUT_EXTRA_DEBUG, MODE_PLAY
|
||||
from katrain.gui.popups import ConfigTeacherPopup, ConfigTimerPopup, I18NPopup
|
||||
from katrain.gui.ai_settings import ConfigAIPopupContents
|
||||
from katrain.core.settings_and_logging import KaTrainSettings
|
||||
from katrain.core.base_katrain import KaTrainBase
|
||||
from katrain.core.engine import KataGoEngine
|
||||
from katrain.core.game import Game, IllegalMoveException, KaTrainSGF
|
||||
from katrain.core.sgf_parser import Move, ParseError
|
||||
@@ -53,15 +46,15 @@ from katrain.gui.style import ENGINE_BUSY_COL, ENGINE_DOWN_COL, ENGINE_READY_COL
|
||||
__version__ = "1.1.0"
|
||||
|
||||
|
||||
class KaTrainGui(Screen, KaTrainSettings):
|
||||
class KaTrainGui(Screen, KaTrainBase):
|
||||
"""Top level class responsible for tying everything together"""
|
||||
|
||||
zen = BooleanProperty(False)
|
||||
controls = ObjectProperty(None)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.engine = None
|
||||
self.game = None
|
||||
|
||||
self.new_game_popup = None
|
||||
self.fileselect_popup = None
|
||||
@@ -109,7 +102,7 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
def update_state(self, redraw_board=False): # is called after every message and on receiving analyses and config changes
|
||||
# AI and Trainer/auto-undo handlers
|
||||
cn = self.game.current_node
|
||||
last_player, next_player = self.game.players[cn.player], self.game.players[cn.next_player]
|
||||
last_player, next_player = self.players_info[cn.player], self.players_info[cn.next_player]
|
||||
if self.play_analyze_mode == MODE_PLAY:
|
||||
teaching_undo = cn.player and last_player.being_taught
|
||||
if teaching_undo and cn.analysis_ready and cn.parent and cn.parent.analysis_ready and not cn.children and not self.game.ended:
|
||||
@@ -120,7 +113,7 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
# Handle prisoners and next player display
|
||||
prisoners = self.game.prisoner_count
|
||||
top, bot = [w.__self__ for w in self.board_controls.circles] # no weakref
|
||||
if self.game.next_player.player == "W":
|
||||
if self.next_player_info.player == "W":
|
||||
top, bot = bot, top
|
||||
self.controls.players["W"].active = True
|
||||
self.controls.players["B"].active = False
|
||||
@@ -148,6 +141,14 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
self.controls.update_evaluation()
|
||||
self.controls.update_timer(1)
|
||||
|
||||
def update_player(self, bw, **kwargs):
|
||||
super().update_player(bw, **kwargs)
|
||||
if self.controls:
|
||||
self.controls.update_players()
|
||||
self.update_state()
|
||||
for player_setup_block in PlayerSetupBlock.INSTANCES:
|
||||
player_setup_block.update_players(bw,self.players_info[bw])
|
||||
|
||||
def set_note(self, note):
|
||||
self.game.current_node.note = note
|
||||
|
||||
@@ -173,14 +174,12 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
self.board_gui.animating_pv = None
|
||||
self.engine.on_new_game() # clear queries
|
||||
self.game = Game(self, self.engine, move_tree=move_tree, analyze_fast=analyze_fast)
|
||||
for bw, player_widget in self.nav_drawer_contents.player_setup.players.items():
|
||||
self.game.players[bw].update(**player_widget.player_def)
|
||||
self.controls.graph.initialize_from_game(self.game.root)
|
||||
self.update_state(redraw_board=True)
|
||||
|
||||
def _do_ai_move(self, node=None):
|
||||
if node is None or self.game.current_node == node:
|
||||
mode = self.game.next_player.strategy
|
||||
mode = self.next_player_info.strategy
|
||||
settings = self.config(f"ai/{mode}")
|
||||
if settings:
|
||||
ai_move(self.game, mode, settings)
|
||||
@@ -190,7 +189,7 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
def _do_undo(self, n_times=1):
|
||||
if n_times == "smart":
|
||||
n_times = 1
|
||||
if self.play_analyze_mode == "play" and self.game.last_player.ai and self.game.next_player.human:
|
||||
if self.play_analyze_mode == "play" and self.last_player_info.ai and self.next_player_info.human:
|
||||
n_times = 2
|
||||
self.board_gui.animating_pv = None
|
||||
self.game.undo(n_times)
|
||||
@@ -206,7 +205,7 @@ class KaTrainGui(Screen, KaTrainSettings):
|
||||
def _do_play(self, coords):
|
||||
self.board_gui.animating_pv = None
|
||||
try:
|
||||
self.game.play(Move(coords, player=self.game.next_player.player))
|
||||
self.game.play(Move(coords, player=self.next_player_info.player))
|
||||
except IllegalMoveException as e:
|
||||
self.controls.set_status(f"Illegal Move: {str(e)}")
|
||||
|
||||
@@ -377,7 +376,7 @@ class KaTrainApp(MDApp):
|
||||
|
||||
def on_language(self, _instance, language):
|
||||
self.gui.log(f"Switching language to {language}", OUTPUT_INFO)
|
||||
switch_lang(language)
|
||||
i18n.switch_lang(language)
|
||||
|
||||
def on_start(self):
|
||||
self.gui.start()
|
||||
|
||||
+15
-27
@@ -60,71 +60,59 @@
|
||||
"lock_ai": false
|
||||
},
|
||||
"ai": {
|
||||
"default": {
|
||||
"ai:default": {
|
||||
"_help_right": "No settings available for Default KataGo AI, strength is mainly affected by `max_visits` and `model` in the main settings `engine` section.",
|
||||
"_help_left": ""
|
||||
},
|
||||
"jigo": {
|
||||
"ai:jigo": {
|
||||
"target_score": 0.5,
|
||||
"_help_left": "Will try to win by `target_score`, without further restrictions.",
|
||||
"_help_right": "Also affected by engine settings such as `max_visits`."
|
||||
},
|
||||
"scoreloss": {
|
||||
"ai:scoreloss": {
|
||||
"strength": 0.5
|
||||
},
|
||||
"Policy": {
|
||||
"ai:policy": {
|
||||
"opening_moves": 20
|
||||
},
|
||||
"P:Weighted": {
|
||||
"_help_right": "pick_override` determines when top move is chosen without randomness, and `lower_bound` determines the lower bound policy value that is allowed.",
|
||||
"_help_left": "Plays move with probability=policy^(1/weaken_fac),i.e. `weaken_fac` influences how much more likely weaker moves are picked.",
|
||||
"ai:p:weighted": {
|
||||
"pick_override": 1.0,
|
||||
"lower_bound": 0.001,
|
||||
"weaken_fac": 1.25
|
||||
},
|
||||
"P:Pick": {
|
||||
"ai:p:pick": {
|
||||
"pick_override": 0.95,
|
||||
"pick_n": 5,
|
||||
"pick_frac": 0.33,
|
||||
"_help_left": "Picks `pick_n + pick_frac * <number of legal moves>` at random and plays the best one. Change `pick_frac` to make it see more moves.",
|
||||
"_help_right": "Plays top move if policy value is above `pick_override` to avoid obvious mistakes."
|
||||
"pick_frac": 0.33
|
||||
},
|
||||
"P:Local": {
|
||||
"ai:p:local": {
|
||||
"pick_override": 0.95,
|
||||
"stddev": 1.5,
|
||||
"pick_n": 15,
|
||||
"pick_frac": 0.0,
|
||||
"_help_left": "Samples `pick_n + pick_frac * <number of legal moves>` near the last move and plays the best one.",
|
||||
"_help_right": "Lower `stddev` makes it prefer closer moves."
|
||||
"pick_frac": 0.0
|
||||
},
|
||||
"P:Tenuki": {
|
||||
"ai:p:tenuki": {
|
||||
"pick_override": 0.85,
|
||||
"stddev": 7.5,
|
||||
"pick_n": 5,
|
||||
"pick_frac": 0.5,
|
||||
"endgame": 0.45,
|
||||
"_help_left": "Samples `pick_n + pick_frac * <number of legal moves>` away from the last move and plays the best one.",
|
||||
"_help_right": "Increase `stddev` makes it prefer moves further away. Stops tenukiing after the 'endgame' fraction of the board is filled."
|
||||
"endgame": 0.45
|
||||
},
|
||||
"P:Influence": {
|
||||
"ai:p:influence": {
|
||||
"pick_override": 0.95,
|
||||
"pick_n": 5,
|
||||
"pick_frac": 0.4,
|
||||
"threshold": 3.5,
|
||||
"line_weight": 10,
|
||||
"endgame": 0.4,
|
||||
"_help_left": "Samples `pick_n + pick_frac * <number of legal moves>` and plays the best one, biased to above the `threshold` line.",
|
||||
"_help_right": "Increase `line_weight` to penalize moves near the edge more. Stops strategy after the 'endgame' fraction of the board is filled."
|
||||
"endgame": 0.4
|
||||
},
|
||||
"P:Territory": {
|
||||
"ai:p:territory": {
|
||||
"pick_override": 0.95,
|
||||
"pick_n": 5,
|
||||
"pick_frac": 0.4,
|
||||
"threshold": 3.5,
|
||||
"line_weight": 2,
|
||||
"endgame": 0.4,
|
||||
"_help_left": "Samples `pick_n + pick_frac * <number of legal moves>` and plays the best one, biased to below the `threshold` line.",
|
||||
"_help_right": "Increase `line_weight` to penalize moves closer to the center more. Stops strategy after the 'endgame' fraction of the board is filled."
|
||||
"endgame": 0.4
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -4,7 +4,8 @@ import random
|
||||
import time
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from katrain.core.utils import OUTPUT_DEBUG, OUTPUT_INFO, var_to_grid
|
||||
from katrain.core.utils import var_to_grid
|
||||
from katrain.core.constants import OUTPUT_INFO, OUTPUT_DEBUG
|
||||
from katrain.core.engine import EngineDiedException
|
||||
from katrain.core.game import Game, GameNode, Move
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
from kivy import Config
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivy.storage.jsonstore import JsonStore
|
||||
import os, sys
|
||||
from katrain.core.constants import *
|
||||
|
||||
from katrain.core.utils import find_package_resource
|
||||
|
||||
|
||||
class Player:
|
||||
def __init__(self, player="B", player_type=PLAYER_HUMAN, player_subtype=PLAYING_NORMAL, periods_used=0):
|
||||
self.player = player
|
||||
self.update(player_type, player_subtype)
|
||||
self.periods_used = periods_used
|
||||
|
||||
def update(self, player_type=PLAYER_HUMAN, player_subtype=PLAYING_NORMAL):
|
||||
self.player_type = player_type
|
||||
self.player_subtype = player_subtype
|
||||
|
||||
@property
|
||||
def ai(self):
|
||||
return self.player_type == PLAYER_AI
|
||||
|
||||
@property
|
||||
def human(self):
|
||||
return self.player_type == PLAYER_HUMAN
|
||||
|
||||
@property
|
||||
def being_taught(self):
|
||||
return self.player_type == PLAYER_HUMAN and self.player_subtype == PLAYING_TEACHING
|
||||
|
||||
@property
|
||||
def strategy(self):
|
||||
return self.player_subtype if self.ai else AI_DEFAULT
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.player_type} ({self.player_subtype})"
|
||||
|
||||
|
||||
class KaTrainBase:
|
||||
CONFIG_FILE = "katrain/config.json"
|
||||
|
||||
"""Settings, logging, and players functionality, so other classes like bots who need a katrain instance can be used without a GUI"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.debug_level = 0
|
||||
self.game = None
|
||||
|
||||
self.logger = lambda message, level=OUTPUT_INFO: self.log(message, level)
|
||||
self.config_file = self._load_config()
|
||||
self.debug_level = self.config("general/debug_level", OUTPUT_INFO)
|
||||
|
||||
Config.set("kivy", "log_level", "error")
|
||||
if self.debug_level >= OUTPUT_DEBUG:
|
||||
Config.set("kivy", "log_enable", 1)
|
||||
Config.set("kivy", "log_level", "warning")
|
||||
if self.debug_level >= OUTPUT_EXTRA_DEBUG:
|
||||
Config.set("kivy", "log_level", "trace")
|
||||
self.players_info = {"B": Player("B"), "W": Player("W")}
|
||||
self.reset_players()
|
||||
|
||||
def log(self, message, level=OUTPUT_INFO):
|
||||
if level == OUTPUT_ERROR:
|
||||
print(f"ERROR: {message}", file=sys.stderr)
|
||||
elif self.debug_level >= level:
|
||||
print(message)
|
||||
|
||||
def _load_config(self):
|
||||
config_file = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else find_package_resource(self.CONFIG_FILE))
|
||||
try:
|
||||
self.log(f"Using config file {config_file}", OUTPUT_INFO)
|
||||
self._config_store = JsonStore(config_file, indent=4)
|
||||
self._config = dict(self._config_store)
|
||||
return config_file
|
||||
except Exception as e:
|
||||
self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR)
|
||||
sys.exit(1)
|
||||
|
||||
def save_config(self):
|
||||
for k, v in self._config.items():
|
||||
self._config_store.put(k, **v)
|
||||
|
||||
def config(self, setting, default=None):
|
||||
try:
|
||||
if "/" in setting:
|
||||
cat, key = setting.split("/")
|
||||
return self._config[cat].get(key, default)
|
||||
else:
|
||||
return self._config[setting]
|
||||
except KeyError:
|
||||
self.log(f"Missing configuration option {setting}", OUTPUT_ERROR)
|
||||
|
||||
|
||||
def update_player(self, bw, **kwargs):
|
||||
self.players_info[bw].update(**kwargs)
|
||||
|
||||
def reset_players(self):
|
||||
self.update_player("B")
|
||||
self.update_player("W")
|
||||
for v in self.players_info.values():
|
||||
v.periods_used = 0
|
||||
|
||||
|
||||
@property
|
||||
def last_player_info(self) -> Player:
|
||||
return self.players_info[self.game.current_node.player]
|
||||
|
||||
@property
|
||||
def next_player_info(self) -> Player:
|
||||
return self.players_info[self.game.current_node.next_player]
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
HOMEPAGE = "https://github.com/sanderland/katrain"
|
||||
|
||||
PLAYER_HUMAN, PLAYER_AI = "player:human", "player:ai"
|
||||
PLAYER_TYPES = [PLAYER_HUMAN, PLAYER_AI]
|
||||
|
||||
PLAYING_NORMAL, PLAYING_TEACHING = "game:normal", "game:teach"
|
||||
GAME_TYPES = [PLAYING_NORMAL, PLAYING_TEACHING]
|
||||
|
||||
MODE_PLAY, MODE_ANALYZE = "play", "analyze"
|
||||
|
||||
AI_DEFAULT = "default"
|
||||
AI_STRATEGIES = [AI_DEFAULT]
|
||||
OUTPUT_ERROR = -1
|
||||
OUTPUT_KATAGO_STDERR = -0.5
|
||||
OUTPUT_INFO = 0
|
||||
OUTPUT_DEBUG = 1
|
||||
OUTPUT_EXTRA_DEBUG = 2
|
||||
@@ -6,7 +6,8 @@ import threading
|
||||
import time
|
||||
from typing import Callable, Optional
|
||||
|
||||
from katrain.core.utils import OUTPUT_DEBUG, OUTPUT_ERROR, OUTPUT_EXTRA_DEBUG, OUTPUT_KATAGO_STDERR, find_package_resource, i18n
|
||||
from katrain.core.utils import find_package_resource, i18n
|
||||
from katrain.core.constants import OUTPUT_ERROR, OUTPUT_KATAGO_STDERR, OUTPUT_DEBUG, OUTPUT_EXTRA_DEBUG
|
||||
from katrain.core.game_node import GameNode
|
||||
|
||||
|
||||
|
||||
+6
-49
@@ -5,11 +5,11 @@ import threading
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Union, Optional
|
||||
|
||||
from katrain.core.utils import var_to_grid, OUTPUT_INFO, OUTPUT_DEBUG, i18n
|
||||
from katrain.core.utils import var_to_grid, i18n
|
||||
from katrain.core.constants import OUTPUT_INFO, OUTPUT_DEBUG, HOMEPAGE
|
||||
from katrain.core.engine import KataGoEngine
|
||||
from katrain.core.game_node import GameNode
|
||||
from katrain.core.sgf_parser import SGF, Move
|
||||
from katrain.core.constants import *
|
||||
|
||||
|
||||
class IllegalMoveException(Exception):
|
||||
@@ -20,46 +20,15 @@ class KaTrainSGF(SGF):
|
||||
_NODE_CLASS = GameNode
|
||||
|
||||
|
||||
class Player:
|
||||
def __init__(self, player="B", player_type=PLAYER_HUMAN, player_subtype=PLAYING_NORMAL, periods_used=0):
|
||||
self.player = player
|
||||
self.update(player_type, player_subtype)
|
||||
self.periods_used = periods_used
|
||||
|
||||
def update(self, player_type, player_subtype):
|
||||
self.player_type = player_type
|
||||
self.player_subtype = player_subtype
|
||||
|
||||
@property
|
||||
def ai(self):
|
||||
return self.player_type == PLAYER_AI
|
||||
|
||||
@property
|
||||
def human(self):
|
||||
return self.player_type == PLAYER_HUMAN
|
||||
|
||||
@property
|
||||
def being_taught(self):
|
||||
return self.player_type == PLAYER_HUMAN and self.player_subtype == PLAYING_TEACHING
|
||||
|
||||
@property
|
||||
def strategy(self):
|
||||
return self.player_subtype if self.ai else AI_DEFAULT
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.player_type} ({self.player_subtype})"
|
||||
|
||||
|
||||
class Game:
|
||||
"""Represents a game of go, including an implementation of capture rules."""
|
||||
|
||||
DEFAULT_PROPERTIES = {"GM": 1, "FF": 4, "AP": "KaTrain:https://github.com/sanderland/katrain"}
|
||||
DEFAULT_PROPERTIES = {"GM": 1, "FF": 4, "AP": f"KaTrain:{HOMEPAGE}"}
|
||||
|
||||
def __init__(self, katrain, engine: Union[Dict, KataGoEngine], move_tree: GameNode = None, players: Dict = None, analyze_fast=False):
|
||||
def __init__(self, katrain, engine: Union[Dict, KataGoEngine], move_tree: GameNode = None, analyze_fast=False):
|
||||
self.katrain = katrain
|
||||
if not isinstance(engine, Dict):
|
||||
engine = {"B": engine, "W": engine}
|
||||
self.players = players or {"B": Player("B"), "W": Player("W")}
|
||||
self.engines = engine
|
||||
self.game_id = datetime.strftime(datetime.now(), "%Y-%m-%d %H %M %S")
|
||||
|
||||
@@ -76,8 +45,6 @@ class Game:
|
||||
handicap = katrain.config("game/handicap")
|
||||
if handicap:
|
||||
self.place_handicap_stones(handicap)
|
||||
self.root.set_property("PW", str(self.players["W"]))
|
||||
self.root.set_property("PB", str(self.players["B"]))
|
||||
|
||||
if not self.root.get_property("RU"):
|
||||
self.root.set_property("RU", katrain.config("game/rules"))
|
||||
@@ -85,14 +52,6 @@ class Game:
|
||||
self.set_current_node(self.root)
|
||||
threading.Thread(target=lambda: self.analyze_all_nodes(-1_000_000, analyze_fast=analyze_fast), daemon=True).start() # return faster, but bypass Kivy Clock
|
||||
|
||||
@property
|
||||
def last_player(self) -> Player:
|
||||
return self.players[self.current_node.player]
|
||||
|
||||
@property
|
||||
def next_player(self) -> Player:
|
||||
return self.players[self.current_node.next_player]
|
||||
|
||||
def analyze_all_nodes(self, priority=0, analyze_fast=False):
|
||||
for node in self.root.nodes_in_tree:
|
||||
node.analyze(self.engines[node.next_player], priority=priority, analyze_fast=analyze_fast)
|
||||
@@ -287,10 +246,8 @@ class Game:
|
||||
if eval_thresholds is None:
|
||||
eval_thresholds = self.katrain.config("trainer/eval_thresholds")
|
||||
|
||||
black, white = self.root.get_property("PB"), self.root.get_property("PW")
|
||||
black = re.sub(r"['<>:\"/\\|?*]", "", black or "Black")
|
||||
white = re.sub(r"['<>:\"/\\|?*]", "", white or "White")
|
||||
game_name = f"katrain_{black} vs {white} {self.game_id}"
|
||||
player_names = {bw: re.sub(r"['<>:\"/\\|?*]", "", self.root.get_property("P"+bw) or str(self.katrain.players_info[bw])) for bw in "BW" }
|
||||
game_name = f"katrain_{player_names['B']} vs {player_names['W']} {self.game_id}"
|
||||
file_name = os.path.abspath(os.path.join(path, f"{game_name}.sgf"))
|
||||
os.makedirs(os.path.dirname(file_name), exist_ok=True)
|
||||
|
||||
|
||||
@@ -142,7 +142,6 @@ class GameNode(SGFNode):
|
||||
else:
|
||||
text += i18n._("Info:best move") + "\n"
|
||||
if previous_top_move.get("pv") and (sgf or hints):
|
||||
print("PREV", previous_top_move)
|
||||
text += i18n._("Info:PV").format(pv=self.make_pv(single_move.player, previous_top_move["pv"], interactive)) + "\n"
|
||||
|
||||
if sgf or hints or teach:
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
from kivy import Config
|
||||
from kivy.storage.jsonstore import JsonStore
|
||||
import os, sys
|
||||
from katrain.core.utils import (
|
||||
OUTPUT_ERROR,
|
||||
OUTPUT_INFO,
|
||||
OUTPUT_KATAGO_STDERR,
|
||||
find_package_resource,
|
||||
OUTPUT_DEBUG,
|
||||
OUTPUT_EXTRA_DEBUG,
|
||||
)
|
||||
|
||||
|
||||
class KaTrainSettings:
|
||||
CONFIG_FILE = "katrain/config.json"
|
||||
|
||||
"""Settings and logging functionality, so other classes who need a katrain instance can be used without a GUI"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.debug_level = 0
|
||||
self.logger = lambda message, level=OUTPUT_INFO: self.log(message, level)
|
||||
self.config_file = self._load_config()
|
||||
self.debug_level = self.config("general/debug_level", OUTPUT_INFO)
|
||||
|
||||
Config.set("kivy", "log_level", "error")
|
||||
if self.debug_level >= OUTPUT_DEBUG:
|
||||
Config.set("kivy", "log_enable", 1)
|
||||
Config.set("kivy", "log_level", "warning")
|
||||
|
||||
# if self.debug_level >= OUTPUT_EXTRA_DEBUG:
|
||||
# Config.set("kivy", "log_level", "trace")
|
||||
|
||||
def log(self, message, level=OUTPUT_INFO):
|
||||
if level == OUTPUT_ERROR:
|
||||
print(f"ERROR: {message}", file=sys.stderr)
|
||||
elif self.debug_level >= level:
|
||||
print(message)
|
||||
|
||||
def _load_config(self):
|
||||
config_file = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else find_package_resource(self.CONFIG_FILE))
|
||||
try:
|
||||
self.log(f"Using config file {config_file}", OUTPUT_INFO)
|
||||
self._config_store = JsonStore(config_file, indent=4)
|
||||
self._config = dict(self._config_store)
|
||||
return config_file
|
||||
except Exception as e:
|
||||
self.log(f"Failed to load config {config_file}: {e}", OUTPUT_ERROR)
|
||||
sys.exit(1)
|
||||
|
||||
def save_config(self):
|
||||
for k, v in self._config.items():
|
||||
self._config_store.put(k, **v)
|
||||
|
||||
def config(self, setting, default=None):
|
||||
try:
|
||||
if "/" in setting:
|
||||
cat, key = setting.split("/")
|
||||
return self._config[cat].get(key, default)
|
||||
else:
|
||||
return self._config[setting]
|
||||
except KeyError:
|
||||
self.log(f"Missing configuration option {setting}", OUTPUT_ERROR)
|
||||
@@ -5,8 +5,6 @@ from typing import List, Tuple, Callable
|
||||
from kivy.lang import Observable
|
||||
import gettext
|
||||
|
||||
from kivymd.uix.textfield import MDTextField
|
||||
|
||||
from katrain.gui.style import DEFAULT_FONT
|
||||
|
||||
try:
|
||||
@@ -14,14 +12,6 @@ try:
|
||||
except:
|
||||
import importlib_resources as pkg_resources
|
||||
|
||||
OUTPUT_ERROR = -1
|
||||
OUTPUT_KATAGO_STDERR = -0.5
|
||||
OUTPUT_INFO = 0
|
||||
OUTPUT_DEBUG = 1
|
||||
OUTPUT_EXTRA_DEBUG = 2
|
||||
|
||||
MODE_PLAY, MODE_ANALYZE = "play", "analyze"
|
||||
|
||||
|
||||
def var_to_grid(array_var: List[Number], size: Tuple[int, int]) -> List[List[Number]]:
|
||||
"""convert ownership/policy to grid format such that grid[y][x] is for move with coords x,y"""
|
||||
@@ -113,7 +103,3 @@ class Lang(Observable):
|
||||
|
||||
DEFAULT_LANGUAGE = "en"
|
||||
i18n = Lang(DEFAULT_LANGUAGE)
|
||||
|
||||
|
||||
def switch_lang(lang):
|
||||
i18n.switch_lang(lang)
|
||||
Binary file not shown.
+5
-5
@@ -119,7 +119,7 @@
|
||||
<AutoSizedRoundedRectangleButton@AutoSizedRectangleButton>:
|
||||
background_radius: self.height/3.5
|
||||
|
||||
<BGMDBoxLayout>:
|
||||
<BGBoxLayout>:
|
||||
background_color: BOX_BACKGROUND_COLOR
|
||||
|
||||
<TransparentIconButton>:
|
||||
@@ -695,7 +695,7 @@
|
||||
notebox.size_hint_y = int(args[1]['notes'])*0.66+1e-9
|
||||
notebox.opacity = int(args[1]['notes'])
|
||||
options_height: root.tab_option_height
|
||||
BGMDBoxLayout:
|
||||
BGBoxLayout:
|
||||
background_color: BOX_BACKGROUND_COLOR
|
||||
orientation: 'vertical'
|
||||
ScrollableLabel:
|
||||
@@ -895,9 +895,9 @@
|
||||
StyledSpinner:
|
||||
id: player_subtype
|
||||
value_refs: []
|
||||
on_text: root.set_player()
|
||||
on_text: root.update_global_player_info()
|
||||
|
||||
<PlayerSetupBlock@MDBoxLayout>:
|
||||
<PlayerSetupBlock>:
|
||||
orientation: 'vertical'
|
||||
size_hint_y: None
|
||||
spacing: 3*CP_SPACING
|
||||
@@ -1023,7 +1023,7 @@
|
||||
ScreenManager:
|
||||
Screen:
|
||||
name: 'gui'
|
||||
BGMDBoxLayout:
|
||||
BGBoxLayout:
|
||||
background_color: BACKGROUND_COLOR
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
|
||||
@@ -4,7 +4,7 @@ from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.gridlayout import MDGridLayout
|
||||
from kivymd.uix.label import MDLabel
|
||||
|
||||
from katrain.core.utils import OUTPUT_DEBUG, OUTPUT_ERROR
|
||||
from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG
|
||||
from katrain.gui.kivyutils import SizedButton, LightHelpLabel, ScaledLightLabel, StyledSpinner
|
||||
from katrain.gui.popups import QuickConfigGui, ConfigPopup, InputParseError
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.floatlayout import MDFloatLayout
|
||||
from kivymd.uix.menu import MDDropdownMenu, RightContent
|
||||
|
||||
from katrain.core.utils import OUTPUT_DEBUG, evaluation_class, i18n, MODE_PLAY
|
||||
from katrain.core.utils import evaluation_class, i18n
|
||||
from katrain.core.constants import OUTPUT_DEBUG, MODE_PLAY
|
||||
from katrain.core.game import Move
|
||||
from katrain.gui.kivyutils import draw_circle, draw_text
|
||||
from katrain.core.utils import var_to_grid
|
||||
@@ -50,9 +51,12 @@ class BadukPanWidget(Widget):
|
||||
self.stone_size = 0
|
||||
self.active_pv_moves = []
|
||||
self.animating_pv = None
|
||||
self.redraw_board_contents_trigger = Clock.create_trigger(self.draw_board_contents)
|
||||
self.last_mouse_pos = (0, 0)
|
||||
Window.bind(mouse_pos=self.on_mouse_pos)
|
||||
|
||||
self.redraw_board_contents_trigger = Clock.create_trigger(self.draw_board_contents)
|
||||
self.redraw_trigger = Clock.create_trigger(self.redraw)
|
||||
self.bind(size=self.redraw_trigger)
|
||||
Clock.schedule_interval(self.animate_pv, 0.1)
|
||||
|
||||
# stone placement functions
|
||||
@@ -132,7 +136,7 @@ class BadukPanWidget(Widget):
|
||||
self.draw_hover_contents() # remove ghost
|
||||
|
||||
# drawing functions
|
||||
def on_size(self, *_args):
|
||||
def redraw(self,*_args):
|
||||
self.draw_board()
|
||||
self.draw_board_contents()
|
||||
|
||||
@@ -276,7 +280,7 @@ class BadukPanWidget(Widget):
|
||||
Rectangle(pos=(self.gridpos_x[x] - rsz / 2, self.gridpos_y[y] - rsz / 2), size=(rsz, rsz))
|
||||
|
||||
policy = current_node.policy
|
||||
if not policy and current_node.parent and current_node.parent.policy and katrain.game.last_player.ai and katrain.game.next_player.ai:
|
||||
if not policy and current_node.parent and current_node.parent.policy and katrain.last_player_info.ai and katrain.next_player_info.ai:
|
||||
policy = current_node.parent.policy # in the case of AI self-play we allow the policy to be one step out of date
|
||||
|
||||
pass_btn = katrain.board_controls.pass_btn
|
||||
|
||||
@@ -7,7 +7,8 @@ from kivy.uix.popup import Popup
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.floatlayout import MDFloatLayout
|
||||
|
||||
from katrain.core.utils import MODE_PLAY, MODE_ANALYZE, i18n
|
||||
from katrain.core.utils import i18n
|
||||
from katrain.core.constants import MODE_PLAY, MODE_ANALYZE
|
||||
|
||||
|
||||
class PlayAnalyzeSelect(MDFloatLayout):
|
||||
@@ -38,9 +39,9 @@ class ControlsPanel(BoxLayout):
|
||||
Clock.schedule_interval(self.update_timer, 0.07)
|
||||
|
||||
def update_players(self, *_args):
|
||||
for player, info in self.katrain.game.players.items():
|
||||
self.players[player].player_type = i18n._(info.player_type)
|
||||
self.players[player].player_subtype = i18n._(info.player_subtype)
|
||||
for bw, player_info in self.katrain.players_info.items():
|
||||
self.players[bw].player_type = i18n._(player_info.player_type)
|
||||
self.players[bw].player_subtype = i18n._(player_info.player_subtype)
|
||||
|
||||
def set_status(self, msg, at_node=None):
|
||||
self.status_msg = msg
|
||||
@@ -59,11 +60,11 @@ class ControlsPanel(BoxLayout):
|
||||
self.status.text = ""
|
||||
self.status_node = None
|
||||
|
||||
last_player_was_ai_playing_human = game.last_player.ai and game.next_player.human
|
||||
last_player_was_ai_playing_human = katrain.last_player_info.ai and katrain.next_player_info.human
|
||||
|
||||
self.active_comment_node = current_node
|
||||
if katrain.play_analyze_mode == MODE_PLAY and last_player_was_ai_playing_human:
|
||||
if game.next_player.being_taught and current_node.children and current_node.children.auto_undo:
|
||||
if katrain.next_player_info.being_taught and current_node.children and current_node.children.auto_undo:
|
||||
self.active_comment_node = current_node.children[-1]
|
||||
elif current_node.parent:
|
||||
self.active_comment_node = current_node.parent
|
||||
@@ -71,7 +72,7 @@ class ControlsPanel(BoxLayout):
|
||||
hints = katrain.analysis_controls.hints.active
|
||||
info = ""
|
||||
if current_node.move and not current_node.is_root:
|
||||
info = self.active_comment_node.comment(teach=game.players[self.active_comment_node.player].being_taught, hints=hints)
|
||||
info = self.active_comment_node.comment(teach=katrain.players_info[self.active_comment_node.player].being_taught, hints=hints)
|
||||
|
||||
if self.active_comment_node.analysis_ready:
|
||||
self.stats.score = self.active_comment_node.format_score() or ""
|
||||
@@ -96,7 +97,7 @@ class ControlsPanel(BoxLayout):
|
||||
self.last_timer_update = (current_node, now)
|
||||
byo_len = max(1, self.katrain.config("timer/byo_length"))
|
||||
byo_num = max(1, self.katrain.config("timer/byo_periods"))
|
||||
player = self.katrain.game.next_player
|
||||
player = self.katrain.next_player_info
|
||||
ai = player.ai
|
||||
if not self.timer.paused and not ai:
|
||||
if last_update_node == current_node and not current_node.children:
|
||||
|
||||
+31
-11
@@ -14,6 +14,7 @@ from kivy.properties import (
|
||||
ObjectProperty,
|
||||
)
|
||||
from kivy.uix.behaviors import ToggleButtonBehavior, ButtonBehavior
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
from kivy.uix.button import Button
|
||||
from kivy.uix.checkbox import CheckBox
|
||||
from kivy.uix.filechooser import FileChooserLayout, FileChooserListLayout
|
||||
@@ -170,7 +171,7 @@ class CircleWithText(Widget):
|
||||
min_size = NumericProperty(50)
|
||||
|
||||
|
||||
class BGMDBoxLayout(MDBoxLayout, BackgroundMixin):
|
||||
class BGBoxLayout(BoxLayout, BackgroundMixin):
|
||||
pass
|
||||
|
||||
|
||||
@@ -195,11 +196,17 @@ class StyledSpinner(Spinner):
|
||||
except (ValueError, IndexError):
|
||||
return 0, "", ""
|
||||
|
||||
def select_key(self, key):
|
||||
try:
|
||||
ix = self.value_refs.index(key)
|
||||
self.text = self.values[ix]
|
||||
except:
|
||||
pass
|
||||
|
||||
def i18n_values(self, *_args):
|
||||
if self.value_refs:
|
||||
selected = self.selected[0]
|
||||
self.values = [i18n._(ref) for ref in self.value_refs]
|
||||
print(self.selected, self.values, self.value_refs)
|
||||
self.text = self.values[selected]
|
||||
self.font_name = i18n.font_name
|
||||
self.update_dropdown_props()
|
||||
@@ -221,6 +228,18 @@ class StyledSpinner(Spinner):
|
||||
item.font_name = self.font_name
|
||||
|
||||
|
||||
class PlayerSetupBlock(MDBoxLayout):
|
||||
players = ObjectProperty(None)
|
||||
INSTANCES = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
PlayerSetupBlock.INSTANCES.append(self)
|
||||
|
||||
def update_players(self, bw, player_info): # update sub widget based on gui state change
|
||||
self.players[bw].update_widget(player_type=player_info.player_type, player_subtype=player_info.player_subtype)
|
||||
|
||||
|
||||
class PlayerSetup(MDBoxLayout):
|
||||
player = OptionProperty("B", options=["B", "W"])
|
||||
|
||||
@@ -237,19 +256,20 @@ class PlayerSetup(MDBoxLayout):
|
||||
self.player_subtype_label.text = i18n._("aistrategy")
|
||||
self.player_subtype.value_refs = MDApp.get_running_app().gui.ai_strategies # TODO:
|
||||
self.player_subtype.text = self.player_subtype.values[0]
|
||||
self.set_player()
|
||||
self.update_global_player_info()
|
||||
|
||||
@property
|
||||
def player_def(self):
|
||||
def player_type_dump(self):
|
||||
return {"player_type": self.player_type.selected[1], "player_subtype": self.player_subtype.selected[1]}
|
||||
|
||||
def set_player(self):
|
||||
def update_widget(self, player_type, player_subtype):
|
||||
self.player_type.select_key(player_type) # should trigger setup options
|
||||
self.player_subtype.select_key(player_subtype) # should trigger setup options
|
||||
|
||||
def update_global_player_info(self):
|
||||
katrain = MDApp.get_running_app().gui
|
||||
game = katrain and katrain.game
|
||||
if game:
|
||||
game.players[self.player].update(**self.player_def)
|
||||
katrain.controls.update_players()
|
||||
katrain.update_state()
|
||||
if katrain.game and katrain.game.current_node:
|
||||
katrain.update_player(self.player, **self.player_type_dump)
|
||||
|
||||
|
||||
class PlayerInfo(MDBoxLayout, BackgroundMixin):
|
||||
@@ -260,7 +280,7 @@ class PlayerInfo(MDBoxLayout, BackgroundMixin):
|
||||
active = BooleanProperty(True)
|
||||
|
||||
|
||||
class Timer(BGMDBoxLayout):
|
||||
class Timer(BGBoxLayout):
|
||||
state = ListProperty([30, 5, 1])
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.selectioncontrol import MDCheckbox
|
||||
from kivymd.uix.textfield import MDTextField
|
||||
|
||||
from katrain.core.utils import OUTPUT_DEBUG, OUTPUT_ERROR
|
||||
from katrain.core.constants import OUTPUT_ERROR, OUTPUT_DEBUG
|
||||
from katrain.core.engine import KataGoEngine
|
||||
from katrain.core.game import Game, GameNode
|
||||
from katrain.gui.kivyutils import StyledSpinner
|
||||
@@ -163,7 +163,7 @@ class ConfigTimerPopup(QuickConfigGui):
|
||||
|
||||
def update_config(self, save_to_file=True):
|
||||
super().update_config(save_to_file=save_to_file)
|
||||
for p in self.katrain.game.players.values():
|
||||
for p in self.katrain.players_info.values():
|
||||
p.periods_used = 0
|
||||
self.katrain.controls.timer.paused = True
|
||||
self.katrain.game.current_node.time_used = 0
|
||||
@@ -183,6 +183,9 @@ class NewGamePopup(QuickConfigGui):
|
||||
self.katrain.engine.restart()
|
||||
self.katrain("new-game")
|
||||
|
||||
# for bw, player_widget in self.nav_drawer_contents.player_setup.players.items():
|
||||
# self.players[bw].update(**player_widget.player_def)
|
||||
|
||||
|
||||
class ConfigPopup(QuickConfigGui):
|
||||
def __init__(self, katrain, popup: Popup, config: Dict, ignore_cats: Tuple = (), **kwargs):
|
||||
|
||||
Binary file not shown.
@@ -311,7 +311,7 @@ msgstr ""
|
||||
msgid "Engine died unexpectedly"
|
||||
msgstr ""
|
||||
"Engine died unexpectedly without sending output, possibly due to out of "
|
||||
"memory: {e}"
|
||||
"memory: {error}"
|
||||
|
||||
#. AI names, help etc
|
||||
msgid "strength:kyu"
|
||||
@@ -320,7 +320,7 @@ msgstr "k"
|
||||
msgid "strength:dan"
|
||||
msgstr "d"
|
||||
|
||||
msgid "ainame:default"
|
||||
msgid "ai:default"
|
||||
msgstr "KataGo"
|
||||
|
||||
msgid "aihelp:default"
|
||||
@@ -328,7 +328,7 @@ msgstr ""
|
||||
"Full strength KataGo AI. Strength is mainly affected by `max_visits` and "
|
||||
"`model` in the general settings `engine` section."
|
||||
|
||||
msgid "ainame:jigo"
|
||||
msgid "ai:jigo"
|
||||
msgstr "KataJigo"
|
||||
|
||||
msgid "aihelp:jigo"
|
||||
@@ -336,7 +336,7 @@ msgstr ""
|
||||
"Will try to win by a set amount of points (default 0.5), without further "
|
||||
"restrictions."
|
||||
|
||||
msgid "ainame:jigo"
|
||||
msgid "ai:jigo"
|
||||
msgstr "KataJigo"
|
||||
|
||||
msgid "aihelp:jigo"
|
||||
@@ -344,7 +344,7 @@ msgstr ""
|
||||
"Will try to win by a set amount of points (default 0.5), without further "
|
||||
"restrictions."
|
||||
|
||||
msgid "ainame:scoreloss"
|
||||
msgid "ai:scoreloss"
|
||||
msgstr "Score Loss"
|
||||
|
||||
msgid "aihelp:scoreloss"
|
||||
@@ -352,7 +352,7 @@ msgstr ""
|
||||
"Plays moves that lead to more points lost with lower probability. Likely to "
|
||||
"play more varied/weaker with higher visits settings."
|
||||
|
||||
msgid "ainame:policy"
|
||||
msgid "ai:policy"
|
||||
msgstr "Policy"
|
||||
|
||||
msgid "aihelp:policy"
|
||||
@@ -360,3 +360,59 @@ msgstr ""
|
||||
"Plays the top move from the policy network, without any reading. Strength is"
|
||||
" mainly affected by `model` in engine settings. The opening moves setting "
|
||||
"affects how many moves in the opening are more random."
|
||||
|
||||
msgid "ai:p:weighted"
|
||||
msgstr "Policy Weighted"
|
||||
|
||||
msgid "aihelp:p:weighted"
|
||||
msgstr ""
|
||||
"Plays moves according to policy probability, with `weaken_fac` influencing "
|
||||
"how much more likely weaker moves are played. A high negative value plays "
|
||||
"like the `Policy` AI.`pick_override` determines when top move is chosen "
|
||||
"without randomness, and `lower_bound` determines the lower bound policy "
|
||||
"value that is allowed."
|
||||
|
||||
msgid "ai:p:pick"
|
||||
msgstr "Blinded Policy"
|
||||
|
||||
msgid "aihelp:p:pick"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` at random and plays the"
|
||||
" best one. For `pick_frac=1` plays like the `Policy` AI. Plays top move if "
|
||||
"policy value is above `pick_override` to avoid obvious mistakes."
|
||||
|
||||
msgid "ai:p:local"
|
||||
msgstr "Local Response Style"
|
||||
|
||||
msgid "aihelp:p:local"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` weighted towards the "
|
||||
"last move and plays the best one. Plays top move if policy value is above "
|
||||
"`pick_override` to avoid obvious mistakes."
|
||||
|
||||
msgid "ai:p:tenuki"
|
||||
msgstr "Tenuki Style"
|
||||
|
||||
msgid "aihelp:p:tenuki"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` weighted away from the "
|
||||
"last move and plays the best one. Plays top move if policy value is above "
|
||||
"`pick_override` to avoid obvious mistakes."
|
||||
|
||||
msgid "ai:p:influence"
|
||||
msgstr "Influential Style"
|
||||
|
||||
msgid "aihelp:p:influence"
|
||||
msgstr ""
|
||||
"Picks moves biased above the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the edge more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
msgid "ai:p:territory"
|
||||
msgstr "Respond Locally"
|
||||
|
||||
msgid "aihelp:p:territory"
|
||||
msgstr ""
|
||||
"Picks moves biased below the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the center more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
Binary file not shown.
@@ -398,3 +398,87 @@ msgstr "k"
|
||||
#. TODO
|
||||
msgid "strength:dan"
|
||||
msgstr "d"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:weighted"
|
||||
msgstr ""
|
||||
"Plays moves according to policy probability, with `weaken_fac` influencing "
|
||||
"how much more likely weaker moves are played. A high negative value plays "
|
||||
"like the `Policy` AI.`pick_override` determines when top move is chosen "
|
||||
"without randomness, and `lower_bound` determines the lower bound policy "
|
||||
"value that is allowed."
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:pick"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` at random and plays the"
|
||||
" best one. For `pick_frac=1` plays like the `Policy` AI. Plays top move if "
|
||||
"policy value is above `pick_override` to avoid obvious mistakes."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:influence"
|
||||
msgstr "Influential Style"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:local"
|
||||
msgstr "Respond Locally"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:tenuki"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` weighted away from the "
|
||||
"last move and plays the best one. Plays top move if policy value is above "
|
||||
"`pick_override` to avoid obvious mistakes."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:scoreloss"
|
||||
msgstr "Score Loss"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:influence"
|
||||
msgstr ""
|
||||
"Picks moves biased above the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the edge more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:default"
|
||||
msgstr "KataGo"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:tenuki"
|
||||
msgstr "Tenuki Style"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:pick"
|
||||
msgstr "Blinded Policy"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:weighted"
|
||||
msgstr "Policy Weighted"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:policy"
|
||||
msgstr "Policy"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:jigo"
|
||||
msgstr "KataJigo"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:local"
|
||||
msgstr ""
|
||||
"Picks moves biased below the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the center more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:territory"
|
||||
msgstr ""
|
||||
"Picks moves biased below the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the center more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:territory"
|
||||
msgstr "Respond Locally"
|
||||
Binary file not shown.
@@ -430,3 +430,87 @@ msgstr "k"
|
||||
#. TODO
|
||||
msgid "strength:dan"
|
||||
msgstr "d"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:weighted"
|
||||
msgstr ""
|
||||
"Plays moves according to policy probability, with `weaken_fac` influencing "
|
||||
"how much more likely weaker moves are played. A high negative value plays "
|
||||
"like the `Policy` AI.`pick_override` determines when top move is chosen "
|
||||
"without randomness, and `lower_bound` determines the lower bound policy "
|
||||
"value that is allowed."
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:pick"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` at random and plays the"
|
||||
" best one. For `pick_frac=1` plays like the `Policy` AI. Plays top move if "
|
||||
"policy value is above `pick_override` to avoid obvious mistakes."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:influence"
|
||||
msgstr "Influential Style"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:local"
|
||||
msgstr "Respond Locally"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:tenuki"
|
||||
msgstr ""
|
||||
"Picks `pick_n + pick_frac * <number of legal moves>` weighted away from the "
|
||||
"last move and plays the best one. Plays top move if policy value is above "
|
||||
"`pick_override` to avoid obvious mistakes."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:scoreloss"
|
||||
msgstr "Score Loss"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:influence"
|
||||
msgstr ""
|
||||
"Picks moves biased above the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the edge more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:default"
|
||||
msgstr "KataGo"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:tenuki"
|
||||
msgstr "Tenuki Style"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:pick"
|
||||
msgstr "Blinded Policy"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:weighted"
|
||||
msgstr "Policy Weighted"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:policy"
|
||||
msgstr "Policy"
|
||||
|
||||
#. TODO
|
||||
msgid "ai:jigo"
|
||||
msgstr "KataJigo"
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:local"
|
||||
msgstr ""
|
||||
"Picks moves biased below the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the center more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "aihelp:p:territory"
|
||||
msgstr ""
|
||||
"Picks moves biased below the `threshold` line and plays the best "
|
||||
"one.Increase `line_weight` to penalize moves near the center more. Stops "
|
||||
"strategy after the 'endgame' fraction of the board is filled."
|
||||
|
||||
#. TODO
|
||||
msgid "ai:p:territory"
|
||||
msgstr "Respond Locally"
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
<LabelledFloatInput>:
|
||||
font_size: INPUT_FONT_SIZE
|
||||
on_text: print(self.size,self.font_size)
|
||||
|
||||
<LabelledCheckBox>:
|
||||
color: WHITE
|
||||
|
||||
Reference in new issue
Block a user