def __init__(self, addr, *users, seed=None, full_log=False, god_mode=False): self.addr = addr self.full_log = full_log self.god_mode = god_mode self.rng = RandomGenerator() if seed is None: seed = random.getrandbits(64) self.rng.seed(seed) self.seed = seed self.in_progress = False self.msg = None self.log = None self.key = None self.actions = None self.users = tdeque(users) self.user2players = tdict() self.players = tdict() self.specs = tset()
def __init__(self): super().__init__() self.obj_types = tdict() self.ID_counter_shadow = None self.table = tdict() self.ID_counter = 0 self.players = None
def __init__(self, status=None): super().__init__() self._current = None self._options = tdict() self._name = None self._desc = None self.set_status(status) self.info = tdict() # should be accessed directly by dev
def __init__(self, name=None, debug=False, manager=None, stack=None, table=None, log=None, **settings): if name is None: # TODO: add suggestion about game name name = self.__class__.__name__ super().__init__(name) if manager is None: manager = self.choose_manager()() if stack is None: stack = self.choose_stack()() if table is None: table = self.choose_table()() if log is None: log = GameLogger() game_info = self._view_info() # Registries and managers self.stack = stack self.stack.populate(game_info['phases']) self.table = table self.table.populate(game_info['objects']) self.manager = manager # manager gets populated in reset() self.config_files = tdict() # GameState self._in_progress = False # flag for registration to end self._in_transaction = False # flag for transactionable self.DEBUG = debug # flag for dev to use as needed self.keys = tdict( ) # a one time permission to call step() (with a valid action) self.RNG = RandomGenerator() self._images = tdict() self._advice = tdict() self._advisor_images = tdict() self._spec_image = None self.state = None self.active_players = None self.settings = containerify(settings) self.config = self.load_configs() self.end_info = None # Game components self.log = log
def __init__( self, force_include_type=False, hide_name=False, ): super().__init__() self.force_player_type = force_include_type self.hide_name = hide_name self.players = tdict() self.players_list = tlist() self.meta_info = tdict() self._in_transaction = False
def reset(self, ctrl): game_info = ctrl._view_info() types = game_info['player_types'] default = None for name, info in types.items(): self.meta_info[name] = tdict(info) if 'open' not in self.meta_info[ name] or self.meta_info[name].open is None: self.meta_info[name].open = tset() if not self.hide_name: self.meta_info[name].open.add('name') if 'default' in info and info['default']: default = name if default is None: if len(self.meta_info) == 1: default = next(iter(self.meta_info)) else: raise Exception('no default player type provided') self.default_player = default # by default only show player type if there is more than one type registered self.show_player_type = len( self.meta_info) > 1 or self.force_player_type
def _reset(self, player, seed=None): # reset all components if seed is None: seed = random.getrandbits(64) self.seed = seed self._key_rng = RandomGenerator(self.seed) self.RNG = RandomGenerator(self.seed) self.end_info = None self.active_players = tdict() # init components self.state = GameState() self.manager.reset(self) self._add_players(self.config, self.settings) self.log.reset(self) # TODO: maybe this shouldnt just be the names self.table.reset(self) self.stack.reset(self) # init game data = self._get_data() data.lock() self._init_game(data, self.config, self.settings) # builds maps/objects self._in_progress = True # create starting phase self._create_start_phase(data, self.config, self.settings) # execute first player return self._step(player)
def load_configs(cls): config = tdict() for name, path in cls.config_files.items(): config[name] = containerify(yaml.load(open(path, 'r'))) return config
def unjsonify(obj, tfm=None): ''' Convert from a json readable python data structure (containing dict, list, tuples, humpack objects etc.) to a json conpatible object (only dicts, lists, and primitives). :param obj: Input data structure to be unjsonified :param tfm: Custom transform function to unjsonify certain data structures (use with caution) ''' if tfm is not None: try: return tfm(obj, unjsonify) except UnknownElementError: pass if isinstance(obj, primitive): return obj if isinstance(obj, list): return tlist([unjsonify(o, tfm=tfm) for o in obj]) if isinstance(obj, dict): if len(obj) == 1 and '_tuple' in obj: return tuple(unjsonify(o, tfm=tfm) for o in obj['_tuple']) if len(obj) == 1 and '_set' in obj: return tset(unjsonify(o, tfm=tfm) for o in obj['_set']) if len(obj) == 2 and '_ndarray' in obj and '_dtype' in obj: return np.array(unjsonify(obj['_ndarray'], tfm=tfm), dtype=obj['_dtype']) return tdict({k: unjsonify(v, tfm=tfm) for k, v in obj.items()}) raise UnknownElementError(obj)
def __init__(self, ): super().__init__() self._in_transaction = False self._stack = tstack() self._phases = tdict() self._start_phase = None
def register_obj_type(self, obj_cls=None, name=None, open=[], req=[]): if obj_cls is None: assert name is not None, 'Must provide either a name or class' obj_cls = GameObject elif name is None: name = obj_cls.__name__ self.obj_types[name] = tdict(obj_cls=obj_cls, open=tset(open), req=tset(req))
def begin(self): if self.in_transaction(): return self.log.begin() self.update.begin() self._shadow = tdict() self._shadow.debug = self.debug self._shadow.indent_level = self.indent_level self._shadow.end = self.end self._shadow.players = self.players self._shadow.targets = self.targets
def test_init(): ''' Test creating some standard humpack objects ''' x = tdict() assert len(x) == 0 x = tlist() assert len(x) == 0 x = tset() assert len(x) == 0
def commit(self): if not self.in_transaction(): return if len(self._current): opt = tdict(actions=process_actions(self._current)) if self._desc is not None: opt.desc = self._desc self._options[self._name] = opt self._name = None self._desc = None self._current = None
def populate(self, phases): start_phase = None for name, info in phases.items(): self._phases[name] = tdict(info) if 'start' in info and info['start']: start_phase = name if self._start_phase is None: assert start_phase is not None, 'no start phase found in: {}'.format( phases) self._start_phase = start_phase
def get_tdict(): x = tdict() x.a = 1 x.x = x x.l = [tlist(), tset()] x[100] = '100' x[None] = 1.2 x.m = None x[True] = tlist x[list] = complex x['<>)dksfl_ ds: gkal'] = '<>1234543224' x['d = ds=a _+ sd;'] = bytes(range(256)) x[12.2344 + .023j] = range(123, 456, 7) # np.random.seed(1) # x.b = np.random.randn(3).tobytes() x[b'\xaa'] = 'running' return x
def test_tdict(): ''' Test basic operations with tdict ''' x = tdict() assert str(x) == 't{}' x.a = 'a' assert str(x) == 't{a}' x.b = 10 assert str(x) == 't{a, b}' assert len(x) == 2 l = list(iter(x)) assert str(l) == "['a', 'b']" assert x.a == 'a' assert x['a'] == 'a'
def __init_subclass__(cls, register=True, name=None, info_path=None, **kwargs): super().__init_subclass__(**kwargs) cls.__home__ = os.path.dirname(inspect.getfile(cls)) cls.config_files = tdict() config_dir = os.path.join(cls.__home__, 'config') if os.path.isdir(config_dir): prt.info(f'Config dir found for {cls.__name__} at {config_dir}') for fname in os.listdir(config_dir): name = fname.split('.')[0] path = os.path.join(config_dir, fname) cls.register_config(name, path) if register: Game(name=name, info_path=info_path)(cls)
def reset(self, ctrl): self.players = tlist(ctrl.manager.names()) # TODO maybe change to full player objects self.clear() self.update = tdict({player:tlist() for player in self.players})
def hexgrid(rows, cols): global idCounters dhelp = {} idCounters = {'field': 0, 'corner': 0, 'edge': 0, 'other': 0} h = tdict() h.objects = tdict() h.obj_type = 'hexgrid' h.id = getId(h) rows = rows if rows % 2 != 0 else rows + 1 # bei hex muss das ungerade sein: was wenn nicht? h.topcols = cols # cols in top row h.colarr = calc_hex_col_array(rows, h.topcols) h.maxcols = max(h.colarr) h.rows = rows h.cols = cols h.fields = [] h.corners = [] h.edges = [] imiddleRow = (rows - 1) / 2 indexRow = [-1, -1, 0, 0, 0, -1] indexCol = [0, 1, 1, 0, -1, -1] for irow in range(len(h.colarr)): colstart = h.maxcols - h.colarr[irow] for j in range(h.colarr[irow]): #field________________ icol = colstart + 2 * j field = tdict() field.obj_type = 'field' field.id = getId(field) field.row = irow + 1 field.col = icol + 1 field.edges = [None] * 6 field.fields = [None] * 6 field.corners = [None] * 6 h.objects[field.id] = field h.fields.append(field.id) #nodes________________ for fid in h.fields: field = h.objects[fid] #nodes field is irow+1,icol+1 for inode in range(6): #make node idByRC nrow = field.row + indexRow[inode] ncol = field.col + indexCol[inode] irc = 'n' + '-' + str(nrow) + '_' + str(ncol) node = None if irc in dhelp: node = dhelp[irc] else: node = tdict() node.obj_type = 'corner' node.id = getId(node) node.row = nrow node.col = ncol node.edges = [None, None, None] node.fields = [None, None, None] h.corners.append(node.id) dhelp[irc] = node h.objects[node.id] = node #fields of nodes ok if inode == 0: node.fields[1] = field.id elif inode == 1: node.fields[2] = field.id elif inode == 2: node.fields[2] = field.id elif inode == 3: node.fields[0] = field.id elif inode == 4: node.fields[0] = field.id elif inode == 5: node.fields[1] = field.id field.corners[inode] = node.id #edges________________ for fid in h.fields: field = h.objects[fid] #field indices is irow+1,icol+1 for inode in range(6): in1 = inode in2 = (inode + 1) % 6 n1 = h.objects[field.corners[in1]] n2 = h.objects[field.corners[in2]] startNode = n1 if n1.row > n2.row: startNode = n2 if n1.row == n2.row and n1.col > n2.col: startNode = n2 endNode = n2 if startNode == n1 else n1 irc = 'e' + str(startNode.id) + '_' + str(endNode.id) edge = None if irc in dhelp: edge = dhelp[irc] else: edge = tdict() edge.obj_type = 'edge' edge.id = getId(edge) edge.row = startNode.row edge.col = startNode.col edge.fields = [None, None] edge.leftField = None edge.rightField = None edge.corners = [startNode.id, endNode.id] edge.startNode = startNode.id edge.endNode = endNode.id #add this edge id to each node's edges list ok if inode == 0: n1.edges[1] = edge.id n2.edges[2] = edge.id elif inode == 1: n1.edges[1] = edge.id n2.edges[0] = edge.id elif inode == 2: n1.edges[2] = edge.id n2.edges[0] = edge.id elif inode == 3: n1.edges[2] = edge.id n2.edges[1] = edge.id elif inode == 4: n1.edges[0] = edge.id n2.edges[1] = edge.id elif inode == 5: n1.edges[0] = edge.id n2.edges[2] = edge.id #add edge to board, dhelp h.edges.append(edge.id) dhelp[irc] = edge h.objects[edge.id] = edge if inode < 3: edge.fields[1] = field.id edge.leftField = field.id else: edge.fields[0] = field.id edge.rightField = field.id field.edges[inode] = edge.id #add fields of fields ok for fid in h.fields: f = h.objects[fid] for i in range(6): e = h.objects[f.edges[i]] for f1 in e.fields: if f1 and f1 != fid: f.fields[i] = f1 return h
def quadgrid(rows, cols): global idCounters dhelp = {} idCounters = {'field': 0, 'corner': 0, 'edge': 0, 'other': 0} h = tdict() h.objects = tdict() h.obj_type = 'quadgrid' h.id = getId(h) h.topcols = cols # cols in top row h.colarr = [cols] * rows h.maxcols = cols h.rows = rows h.cols = cols h.fields = [] h.corners = [] h.edges = [] imiddleRow = (rows - 1) / 2 indexRow = [-1, 0, 0, -1] #NE node is f.corners[0] indexCol = [0, 0, -1, -1] #fields for irow in range(len(h.colarr)): for icol in range(h.colarr[irow]): #field________________ field = tdict() field.obj_type = 'field' field.id = getId(field) field.row = irow + 1 field.col = icol + 1 field.edges = [None] * 4 field.fields = [None] * 4 field.corners = [None] * 4 h.objects[field.id] = field h.fields.append(field.id) #nodes________________ for fid in h.fields: field = h.objects[fid] #nodes field is irow+1,icol+1 for inode in range(4): #make node idByRC nrow = field.row + indexRow[inode] ncol = field.col + indexCol[inode] irc = 'n' + '-' + str(nrow) + '_' + str(ncol) node = None if irc in dhelp: node = dhelp[irc] else: node = tdict() node.obj_type = 'corner' node.id = getId(node) node.row = nrow node.col = ncol node.edges = [None, None, None, None] node.fields = [None, None, None, None] h.corners.append(node.id) dhelp[irc] = node h.objects[node.id] = node #fields of nodes if inode == 0: node.fields[2] = field.id elif inode == 1: node.fields[3] = field.id elif inode == 2: node.fields[0] = field.id elif inode == 3: node.fields[1] = field.id field.corners[inode] = node.id #edges________________ for fid in h.fields: field = h.objects[fid] #field indices is irow+1,icol+1 for i in range(4): inode = (i + 3) % 4 in1 = inode in2 = (inode + 1) % 4 n1 = h.objects[field.corners[in1]] n2 = h.objects[field.corners[in2]] startNode = n1 if n1.row > n2.row: startNode = n2 if n1.row == n2.row and n1.col > n2.col: startNode = n2 endNode = n2 if startNode == n1 else n1 irc = 'e' + str(startNode.id) + '_' + str(endNode.id) edge = None if irc in dhelp: edge = dhelp[irc] else: edge = tdict() edge.obj_type = 'edge' edge.id = getId(edge) edge.row = startNode.row edge.col = startNode.col edge.fields = [None, None] edge.leftField = None edge.rightField = None edge.topField = None edge.bottomField = None edge.crossField = None edge.corners = [startNode.id, endNode.id] edge.startNode = startNode.id edge.endNode = endNode.id #add this edge id to each node's edges list ok if inode == 0: n1.edges[2] = edge.id n2.edges[0] = edge.id elif inode == 1: n1.edges[3] = edge.id n2.edges[1] = edge.id elif inode == 2: n1.edges[0] = edge.id n2.edges[2] = edge.id elif inode == 3: n1.edges[1] = edge.id n2.edges[3] = edge.id #add edge to board, dhelp h.edges.append(edge.id) dhelp[irc] = edge h.objects[edge.id] = edge if inode == 0: edge.fields[1] = field.id edge.leftField = field.id elif inode == 1: edge.fields[0] = field.id edge.topField = field.id elif inode == 2: edge.fields[0] = field.id edge.rightField = field.id elif inode == 3: edge.fields[1] = field.id edge.bottomField = field.id field.edges[(inode + 1) % 4] = edge.id #add fields of fields ok for fid in h.fields: f = h.objects[fid] for i in range(4): if not f.edges[i]: continue e = h.objects[f.edges[i]] for f1 in e.fields: if f1 and f1 != fid: f.fields[i] = f1 return h
def _step(self, player, group=None, action=None, key=None): # returns python objs (but json readable) try: if player in self.manager: player = self.manager[player] else: raise InvalidPlayerError(player) if not len(self.stack): raise GameOver if self.active_players is None: raise NoActiveGameError('Call reset() first') if action is not None: if player not in self.active_players: return self._compose_msg(player) if key is None or key != self.keys[player]: raise InvalidKeyError action = self.active_players[player].verify( group, action ) # action is a tuple with (action-group, (action-tuple)) # start transaction self.begin() # prepare executing actions - collect game data data = self._get_data() data.lock() # execute action while len(self.stack): phase = self.stack.pop() try: phase.execute(data, player=player, action=action) # get next action out = phase.encode(data) except PhaseComplete as intr: if not intr.transfer_action(): action = None except _PhaseControl as intr: if intr.stacks(): self.stack.push(phase) # keep current phase around new = intr.get_phase() self.stack.push(new, **intr.get_phase_kwargs()) if not intr.transfer_action(): action = None else: # successfully took a step and generated current action sets self.stack.push(phase) break if not len( self.stack ): # ran out of phases, so game must be over. This probably shouldn't happen, instead raise a GameOver signal manually in the phase raise GameOver except GameOver: self.commit() if self.end_info is None: self._clear_images() data = self._get_data() data.lock() self.end_info = self._end_game(data) self._in_progress = False msg = self._compose_msg(player) except Exception as e: self.abort() # error handling msg = { 'error': { 'type': e.__class__.__name__, 'msg': ''.join(traceback.format_exception(*sys.exc_info())), }, } else: self.commit() # format output message self.active_players = tdict( {p.name: opts for p, opts in out.items()}) self._clear_images() msg = self._compose_msg(player) return msg
def reset(self, players): self.writers = tdict({p: LogWriter(indent_level=self.indent_level, debug=self.debug) for p in players}) super().reset()