Source code for amaze.simu.controllers.base

from abc import ABC, abstractmethod
from pathlib import Path
from typing import List
from zipfile import ZipFile

from ..pos import Vec
from ..robot import Robot
from ..types import InputType, OutputType, State, Action, classproperty


[docs] class BaseController(ABC): _simple = True _cheats = False _savable = True infos: dict = {} """ Generic storage for additional information. For instance the class of mazes this agent should solve. """ _discrete_actions = [ Action(1, 0), Action(0, 1), Action(-1, 0), Action(0, -1), ] def __init__(self, robot_data: Robot.BuildData): self._robot_data = robot_data if not isinstance(robot_data, Robot.BuildData): raise ValueError( f"Wrong argument type. Robot.BuildData expected, got" f"{type(robot_data)}" ) def test(name, field_type, field_types): if field_type not in field_types: raise ValueError( f"{name} type not supported." f" {field_type} not in {field_types}: either" f" you passed a wrong argument or you wrongly" f" specified the valid {name.lower()} types" f" for this controller" ) test("Input", self.input_type, self.inputs_types()) test("Output", self.output_type, self.outputs_types()) @classproperty def is_simple(cls) -> bool: """Whether this controller has no internal state (table, ANN, ...) or solely used for demonstration and testing""" return cls._simple @classproperty def cheats(cls) -> bool: """Whether this controller uses simulation-level information. Only meant for test controller *not* for trained agents .. seealso:: `~amaze.simu.controllers.CheaterController` """ return cls._cheats @classproperty def savable(cls) -> bool: """Whether this controller contains a savable state. If True, implies that `save_to_archive` and `load_from_archive` are implemented """ return cls._savable @property def input_type(self) -> InputType: return self._robot_data.inputs @property def output_type(self) -> OutputType: return self._robot_data.outputs @property def vision(self) -> int: return self._robot_data.vision @property def robot_data(self) -> Robot.BuildData: return Robot.BuildData( inputs=self.input_type, outputs=self.output_type, vision=self.vision ) @abstractmethod def __call__(self, inputs: State) -> Vec: """ Generate next move :param inputs: Current local information :return: (dx,dy) in [-1,1]x[-1,1], the requested movement """ # noinspection PyMethodMayBeStatic def details(self) -> dict: return {} @classproperty def name(cls) -> str: return cls.__name__ @classproperty def short_name(cls) -> str: return cls.name.replace("Controller", "").lower() @abstractmethod def reset(self): pass # pragma no cover
[docs] @staticmethod @abstractmethod def inputs_types() -> List[InputType]: # pragma: no cover """Specify what kind of inputs this controller can handle. Abstract method that should be implemented and documented. """ raise NotImplementedError
[docs] @staticmethod @abstractmethod def outputs_types() -> List[OutputType]: # pragma: no cover """Specify what kind of outputs this controller can handle. Abstract method that should be implemented and documented. """ raise NotImplementedError
@classproperty def discrete_actions(cls) -> List[Action]: """Specifies the set of discrete actions that can be taken by an agent""" return cls._discrete_actions
[docs] def _save_to_archive( self, archive: ZipFile, *args, **kwargs ) -> bool: # pragma: no cover """Re-implement to save derived-specific content to the archive :meta public: """ raise NotImplementedError
[docs] @classmethod def _load_from_archive( cls, archive: ZipFile, robot: Robot.BuildData, *args, **kwargs ) -> "BaseController": # pragma: no cover """Re-implement to load derived-specific content from the archive. :meta public: """ raise NotImplementedError
[docs] @staticmethod def assert_equal(lhs: "BaseController", rhs: "BaseController") -> bool: """Re-implement for savable controllers to test for successful roundtrip""" raise NotImplementedError
[docs] def save(self, *args, **kwargs) -> Path: """Easy access to global save function .. seealso:: `~amaze.simu.controllers.control.save` """ from .control import save return save(self, *args, **kwargs)
[docs] @classmethod def load(cls, *args, **kwargs): """Easy access to global load function .. seealso:: `~amaze.simu.controllers.control.load` """ from .control import load return load(*args, **kwargs)