Source code for CYLGame.Player

from typing import List, Optional

import sys
from abc import ABC, abstractmethod
from random import Random, randint

from littlepython.error import LittlePythonBaseExcetion
from littlepython.interpreter import LPProg

# A template class for the Prog for the Player.
from CYLGame.structures.const_mapping import ConstMapping
from CYLGame.Utils import int2base


[docs]class Prog(ABC): def __init__( self, options: dict, token: Optional[str] = None, name: Optional[str] = None, code_hash: Optional[str] = None ): # The `options`, `token` and `name` attributes are reserved for the GameRunner self.options = options self.token = token self.name = name self.code_hash = code_hash
[docs] @abstractmethod def run(self, state: dict, max_op_count: int = -1, random=None): pass
[docs]class LittlePythonProg(Prog): def __init__( self, prog: LPProg, options: dict, token: Optional[str] = None, name: Optional[str] = None, code_hash: Optional[str] = None, ): super().__init__(options=options, token=token, name=name, code_hash=code_hash) self.prog = prog
[docs] def run(self, *args, **kargs): return self.prog.run(*args, **kargs)
[docs]class UserProg(Prog): def __init__(self): super().__init__(name="You", options={}) self.key = None
[docs] def run(self, *args, **kwargs): return {"move": ord(self.key)}
[docs]class Player(ABC): def __init__(self, prog: Prog): self.prog = prog self.prev_vars: dict = {} self.debugging = prog.options.get("debug", False) self.debug_vars: list = [] # TODO: Maybe make this into a class. self.running = True
[docs] def run_turn(self, random: Random, max_ops: int = 1000000): if self.running: try: nxt_state = self.prog.run(self.get_state(), max_op_count=max_ops, random=random) self.update_state(dict(nxt_state)) self.prev_vars = nxt_state except LittlePythonBaseExcetion as e: print("Player class raised: {}!".format(e.__class__.__name__)) self.running = False self.prev_vars = {}
[docs] @abstractmethod def get_state(self) -> dict: pass
[docs] @abstractmethod def update_state(self, new_state: dict): pass
[docs]class DefaultGridPlayer(Player): """Make sure that all bot_vars are updated in game.do_turn""" def __init__(self, prog: Prog, bot_consts: ConstMapping): super(DefaultGridPlayer, self).__init__(prog) self.bot_consts = bot_consts self.bot_vars: dict = {} self.move: Optional[str] = None
[docs] def get_state(self) -> dict: state = dict(self.prev_vars) state.update(self.bot_consts) state.update(self.bot_vars) return state
[docs] def update_state(self, state: dict): # remove consts for key in self.bot_consts.names: state.pop(key, None) self.move = chr(state.get("move", ord("Q"))) if self.debugging: human_vars = {} for name, val in state.items(): if isinstance(val, int) and val in self.bot_consts: human_vars[name] = self.bot_consts[val] + " (" + str(val) + ")" elif str(val) == str(True): human_vars[name] = 1 elif str(val) == str(False): human_vars[name] = 0 else: human_vars[name] = val self.debug_vars += [human_vars]
[docs]class Room(object): def __init__(self, bots: List[Prog] = None, seed=None): self.bots = bots if bots is None: self.bots = [] self.seed = seed if seed is None: self.seed = randint(0, sys.maxsize) self.debug_vars: dict = {} self.screen_cap = None
[docs] def save(self, gamedb): """The method saves the game data to a new game. Note: this room must be run before calling this function. Args: gamedb (GameDB): The current game database. Returns: The gtoken of the newly created game. """ if self.screen_cap is None: raise Exception("You must run this room before trying to save it.") game_data = {"screen": self.screen_cap, "seed": int2base(self.seed, 36)} player_data = {} for player in self.bots: if hasattr(player, "token") and player.token is not None: player_data[player.token] = {"debug_vars": self.debug_vars[player], "code_hash": player.code_hash} return gamedb.add_new_game(game_data, per_player_data=player_data)
@property def rand_seeded(self): """A randomly seeded room with the same bots.""" return Room(self.bots) def __str__(self): return "<Room with '{}'>".format("', '".join(map(lambda x: x.name, self.bots)))