Source code for miniosl.player
"""player"""
import json
import logging
import re
import miniosl
class MyRandomPlayer(miniosl.SingleCPUPlayer):
"""sample of implementing virtual methods in python"""
def __init__(self):
super().__init__()
def think(self, usi: str):
record = miniosl.usi_record(usi)
state = record.replay(-1)
moves = state.genmove()
move = moves[0]
return move
def name(self):
return 'py-random'
[docs]
class UsiPlayer(miniosl.SingleCPUPlayer):
"""bridge between usi engine and :py:class:`CPUPlayer`
for self-play with :py:class:`GameArray`.
"""
def __init__(self, engine: miniosl.UsiProcess):
super().__init__()
self.engine = engine
[docs]
def think(self, usi: str):
record = miniosl.usi_record(usi)
state = record.replay(-1)
go = 'byoyomi 1000'
ret = self.engine.search(usi, go)
move = ret['move']
return state.to_move(move)
[docs]
def name(self):
id = self.engine.name
return id.replace(' ', '_') if id else 'usi'
global_cache = {'players': []}
def make_usi_player(cfg_path: str) -> miniosl.PlayerArray:
with open(cfg_path, 'r') as f:
cfg = json.load(f)
if 'type' not in cfg or cfg['type'] != 'usi':
raise ValueError(f'unsupported cfg {cfg_path}')
path_and_args = cfg['path_and_args']
setoptions = cfg['setoptions']
cwd = cfg.get('cwd', None)
engine = miniosl.UsiProcess(path_and_args, setoptions, cwd)
pl = UsiPlayer(engine)
global_cache['players'].append(pl)
return miniosl.CPUPlayer(pl, False)
def clear_usi_players():
global_cache['players'] = []
def make_player(name: str, *, noise_scale=1.0, book_path='') -> miniosl.PlayerArray:
"""factory method"""
gumbel_pattern = r'^gumbel([1-9][0-9]*)$'
gumbel_d2_pattern = r'^gumbel([1-9][0-9]*)-([1-9][0-9]*)$'
soft_pattern = r'^soft([1-9][0-9]*)$'
soft_d2_pattern = r'^soft([1-9][0-9]*)-([1-9][0-9]*)$'
book_cfg = miniosl.BookConfig()
book_cfg.book_path = book_path
book_cfg.exploration = 0.0
config = miniosl.GumbelPlayerConfig()
config.noise_scale = noise_scale
if book_path:
config.book = book_cfg
if match := re.match(gumbel_d2_pattern, name):
config.root_width = int(match.group(1))
config.second_width = int(match.group(2))
if config.root_width < config.second_width:
raise RuntimeError(
f'width mismatch {config.root_width} < {config.second_width}'
)
return miniosl.FlatGumbelPlayer(config)
elif match := re.match(gumbel_pattern, name):
config.root_width = int(match.group(1))
return miniosl.FlatGumbelPlayer(config)
elif match := re.match(soft_d2_pattern, name):
config.root_width = int(match.group(1))
config.second_width = int(match.group(2))
if config.root_width < config.second_width:
raise RuntimeError(
f'width mismatch {config.root_width} < {config.second_width}'
)
return miniosl.FlatGumbelPlayer(config)
elif match := re.match(soft_pattern, name):
config.root_width = int(match.group(1))
return miniosl.FlatGumbelPlayer(config)
elif name == 'greedy-policy':
return miniosl.PolicyPlayer(True)
elif name == 'random':
""" ... warning:: this depends on std::shared_ptr is used as holder
for :py:class:`RandomPlayer`, otherwise results in dangling pointer.
"""
return miniosl.CPUPlayer(miniosl.RandomPlayer(), False)
elif name == 'myrandom':
"""save before return to keep its lifetime
"""
player = MyRandomPlayer()
global_cache['players'].append(player)
return miniosl.CPUPlayer(player, False)
elif name.endswith('.json'):
return make_usi_player(name)
else:
if name != 'policy':
logging.getLogger(__name__).warning(f'unknown player name {name}')
return miniosl.PolicyPlayer()