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()