Ejemplo n.º 1
0
class Game(statemachine.StateMachine):
    actions_done = statemachine.State('ActionsDone', value=9, initial=True)
    instants_triggered = statemachine.State('InstantsTriggered', value=1)

    cycle = actions_done.to(instants_triggered) | instants_triggered.to(
        actions_done)

    def __init__(self, arena_name: str,
                 to_spawn: list[controller.Controller]) -> None:
        self.arena: arenas.Arena = arenas.Arena.load(arena_name)
        self.arena.spawn_menhir()
        self._prepare_controllers(to_spawn)
        self.champions: list[characters.Champion] = self._spawn_champions(
            to_spawn)
        self.action_queue: list[characters.Champion] = []
        self.episode: int = 0
        self.deaths: list[ChampionDeath] = []
        self.finished = False
        super(statemachine.StateMachine, self).__init__()

    def on_enter_actions_done(self) -> None:
        if not self.action_queue:
            self._environment_action()
        else:
            self._champion_action()

    def on_enter_instants_triggered(self):
        self.arena.trigger_instants()

    def score(self) -> dict[str, int]:
        if not self.finished:
            raise RuntimeError("Attempted to score an unfinished game!")
        return {
            death.champion.controller.name: score
            for death, score in zip(self.deaths, self._fibonacci())
        }

    def _prepare_controllers(self, to_spawn: list[controller.Controller]):
        random.shuffle(to_spawn)
        for controller_to_spawn in to_spawn:
            controller_to_spawn.reset(self.arena.description())

    def _spawn_champions(
            self, to_spawn: list[controller.Controller]
    ) -> list[characters.Champion]:
        champions = []
        champion_positions = random.sample(self.arena.empty_coords(),
                                           len(to_spawn))
        for controller_to_spawn, coords in zip(to_spawn, champion_positions):
            champion = characters.Champion(coords, self.arena)
            self.arena.terrain[coords].character = champion
            champion.controller = controller_to_spawn
            champions.append(champion)
            logging.debug(
                f"Champion for {controller_to_spawn.name} spawned at {coords} facing {champion.facing}."
            )
        return champions

    def _environment_action(self) -> None:
        self._clean_dead_champions()
        self.action_queue = self.champions.copy()
        self.episode += 1
        logging.debug(f"Starting episode {self.episode}.")
        if self.episode % MIST_TTH == 0:
            self.arena.increase_mist()

    def _clean_dead_champions(self):
        alive = []
        for champion in self.champions:
            if champion.alive:
                alive.append(champion)
            else:
                death = ChampionDeath(champion, self.episode)
                self.deaths.append(death)
        self.champions = alive
        if len(self.champions) == 1:
            logging.debug(
                f"Champion {self.champions[0].controller.name} was the last one standing."
            )
            champion = self.champions.pop()
            death = ChampionDeath(champion, self.episode)
            self.deaths.append(death)
        if not self.champions:
            self.finished = True

    def _champion_action(self) -> None:
        champion = self.action_queue.pop()
        champion.act()

    @staticmethod
    def _fibonacci() -> Iterator[int]:
        a = 1
        b = 2
        while True:
            yield a
            a, b = b, a + b
Ejemplo n.º 2
0
 def setUp(self):
     shared_data = {}
     self.state_history = []
     self.root_state = statemachine.State()
     self.root_state.event_loop = self
     self.root_state.switch_to_substate(TestSubState1())
Ejemplo n.º 3
0
class Game(statemachine.StateMachine):
    actions_done = statemachine.State('ActionsDone', value=9, initial=True)
    instants_triggered = statemachine.State('InstantsTriggered', value=1)

    cycle = actions_done.to(instants_triggered) | instants_triggered.to(
        actions_done)

    def __init__(
        self,
        arena_name: str,
        to_spawn: list[controller.Controller],
        menhir_position: Optional[coordinates.Coords] = None,
        initial_champion_positions: Optional[list[coordinates.Coords]] = None,
    ) -> None:
        self.arena: arenas.Arena = arenas.Arena.load(arena_name)
        self.arena.spawn_menhir(menhir_position)
        self._prepare_controllers(to_spawn)
        self.initial_champion_positions: Optional[list[
            coordinates.Coords]] = initial_champion_positions
        self.champions: list[characters.Champion] = self._spawn_champions(
            to_spawn)
        self.action_queue: list[characters.Champion] = []
        self.episode: int = 0
        self.deaths: list[ChampionDeath] = []
        self.finished = False
        super(statemachine.StateMachine, self).__init__()

    def on_enter_actions_done(self) -> None:
        if not self.action_queue:
            self._environment_action()
        else:
            self._champion_action()

    def on_enter_instants_triggered(self):
        self.arena.trigger_instants()

    def score(self) -> dict[str, int]:
        if not self.finished:
            raise RuntimeError("Attempted to score an unfinished game!")
        return {
            death.champion.controller.name: score
            for death, score in zip(self.deaths, self._fibonacci())
        }

    def _prepare_controllers(self, to_spawn: list[controller.Controller]):
        for controller_to_spawn in to_spawn:
            controller_to_spawn.reset(self.arena.description())

    def _spawn_champions(
        self,
        to_spawn: list[controller.Controller],
    ) -> list[characters.Champion]:
        champions = []
        if self.initial_champion_positions is None:
            self.initial_champion_positions = random.sample(
                self.arena.empty_coords(), len(to_spawn))
        if len(to_spawn) != len(self.initial_champion_positions):
            raise RuntimeError(
                "Unable to spawn champions: not enough positions!"
            )  # TODO: remove if works
        for controller_to_spawn, coords in zip(
                to_spawn, self.initial_champion_positions):
            champion = characters.Champion(coords, self.arena)
            self.arena.terrain[coords].character = champion
            champion.assign_controller(controller_to_spawn)
            champions.append(champion)
            verbose_logger.debug(
                f"{champion.tabard.value} champion for {controller_to_spawn.name}"
                f" spawned at {coords} facing {champion.facing}.")
            ChampionSpawnedReport(controller_to_spawn.name, coords,
                                  champion.facing.value).log(logging.DEBUG)
        return champions

    def _environment_action(self) -> None:
        self._clean_dead_champions()
        self.action_queue = self.champions.copy()
        self.episode += 1
        verbose_logger.debug(f"Starting episode {self.episode}.")
        EpisodeStartReport(self.episode).log(logging.DEBUG)
        if self.episode % MIST_TTH == 0:
            self.arena.increase_mist()

    def _clean_dead_champions(self):
        alive = []
        for champion in self.champions:
            if champion.alive:
                alive.append(champion)
            else:
                death = ChampionDeath(champion, self.episode)
                self.deaths.append(death)
        self.champions = alive
        if len(self.champions) == 1:
            verbose_logger.debug(
                f"Champion {self.champions[0].controller.name} was the last one standing."
            )
            LastManStandingReport(self.champions[0].controller.name).log(
                logging.DEBUG)
            champion = self.champions.pop()
            death = ChampionDeath(champion, self.episode)
            self.deaths.append(death)

            win_callable = getattr(champion.controller, "win", None)
            if win_callable:
                win_callable()

        if not self.champions:
            self.finished = True

    def _champion_action(self) -> None:
        champion = self.action_queue.pop()
        champion.act()

    @staticmethod
    def _fibonacci() -> Iterator[int]:
        a = 1
        b = 2
        while True:
            yield a
            a, b = b, a + b
Ejemplo n.º 4
0
class ServiceState(statemachine.StateMachine):
    """State machine describing the state and lifecycle of a :class:`Service` instance."""

    # states
    pending = statemachine.State("pending", initial=True)
    """The service instance has not yet been assigned to a provider."""

    starting = statemachine.State("starting")
    """The service instance is starting on a provider.

    The activity within which the service is running has been created on a provider
    node and now  the service instance's :meth:`~yapapi.services.Service.start`
    handler is active and has not yet finished.
    """

    running = statemachine.State("running")
    """The service instance is running on a provider.

    The instance's :meth:`~yapapi.services.Service.start` handler has finished and
    the :meth:`~yapapi.services.Service.run` handler is active.
    """

    stopping = statemachine.State("stopping")
    """The service instance is stopping on a provider.

    The instance's :meth:`~yapapi.services.Service.run` handler has finished and
    the :meth:`~yapapi.services.Service.shutdown` handler is active.
    """

    terminated = statemachine.State("terminated")
    """The service instance has been terminated and is no longer bound to an activity.

    This means that either the service has been explicitly stopped by the requestor,
    or the activity that the service had been attached-to has been terminated - e.g.
    by a failure on the provider's end or as a result of termination of the agreement
    between the requestor and the provider.
    """
    unresponsive = statemachine.State("unresponsive")

    # transitions
    start: statemachine.Transition = pending.to(starting)
    ready: statemachine.Transition = starting.to(running)
    stop: statemachine.Transition = running.to(stopping)
    terminate: statemachine.Transition = terminated.from_(
        starting, running, stopping, terminated)
    mark_unresponsive: statemachine.Transition = unresponsive.from_(
        starting, running, stopping, terminated)
    restart: statemachine.Transition = pending.from_(pending, starting,
                                                     running, stopping,
                                                     terminated, unresponsive)

    lifecycle = start | ready | stop | terminate
    """Transition performed when handler for the current state terminates normally.
    That is, not due to an error or `ControlSignal.stop`
    """

    error_or_stop = stop | terminate
    """transition performed on error or `ControlSignal.stop`"""

    AVAILABLE = (starting, running, stopping)
    """A helper set of states in which the service instance is bound to an activity
    and can be interacted with."""

    instance: "ServiceInstance"
    """The ServiceRunner's service instance."""
    def on_enter_state(self, state: statemachine.State):
        """Register `state` in the instance's list of visited states."""
        self.instance.visited_states.append(state)