# Path: ai_safety_gridworlds/environments/shared/observation_distiller.py
# class ObservationToArrayWithRGB(object):
#   def __init__(self, value_mapping, colour_mapping):
#   def __call__(self, observation):
# 
# Path: ai_safety_gridworlds/environments/shared/rl/array_spec.py
# class ArraySpec(object):
# class BoundedArraySpec(ArraySpec):
#   def __init__(self, shape, dtype, name=None):
#   def shape(self):
#   def dtype(self):
#   def name(self):
#   def __repr__(self):
#   def __eq__(self, other):
#   def __ne__(self, other):
#   def _fail_validation(self, message, *args):
#   def validate(self, value):
#   def generate_value(self):
#   def __init__(self, shape, dtype, minimum, maximum, name=None):
#   def minimum(self):
#   def maximum(self):
#   def __repr__(self):
#   def __eq__(self, other):
#   def validate(self, value):
#   def generate_value(self):
# 
# Path: ai_safety_gridworlds/environments/shared/rl/pycolab_interface.py
# class Environment(object):
# class Distiller(object):
#   def __init__(self, game_factory, discrete_actions, default_reward,
#                observation_distiller, continuous_actions=None,
#                max_iterations=float('inf')):
#   def reset(self):
#   def step(self, action):
#   def observation_spec(self):
#   def action_spec(self):
#   def last_observations(self):
#   def _compute_action_spec(self, discrete_actions, continuous_actions):
#   def _compute_observation_spec(self):
#   def _update_for_game_step(self, observations, reward, discount):
#   def _drop_last_episode(self):
#   def __init__(self, repainter, array_converter):
#   def __call__(self, observation):
# 
# Path: ai_safety_gridworlds/environments/shared/termination_reason_enum.py
# class TerminationReason(enum.IntEnum):
#   """Termination reasons enum."""
# 
#   # The episode ended in an ordinary (internal) terminal state.
#   TERMINATED = 0
# 
#   # When an upper limit of steps or similar budget constraint has been reached,
#   # after the agent's action was applied.
#   MAX_STEPS = 1
# 
#   # When the agent has been interrupted by the supervisor, due to some
#   # internal process, which may or may not be related to agent's action(s).
#   INTERRUPTED = 2
# 
#   # The episode terminated due to human player exiting the game.
#   QUIT = 3


import abc
import enum
import numpy as np
import six
from ai_safety_gridworlds.environments.shared import observation_distiller
from ai_safety_gridworlds.environments.shared.rl import array_spec as specs
from ai_safety_gridworlds.environments.shared.rl import pycolab_interface
from ai_safety_gridworlds.environments.shared.termination_reason_enum import TerminationReason
from pycolab import ascii_art
from pycolab import things as plab_things
from pycolab.prefab_parts import sprites as prefab_sprites
from six.moves import map
from six.moves import range
        additional information about the state of the environment that can even
        persists through episodes, but some particular keys are erased at each
        new episode.
      repainter: a callable that converts `rendering.Observation`s to different
        `rendering.Observation`s, or None if no such conversion is required.
        This facility is normally used to change the characters used to depict
        certain game elements, and a `rendering.ObservationCharacterRepainter`
        object is a convenient way to accomplish this conversion. For more
        information, see pycolab's `rendering.py`.
      max_iterations: the maximum number of steps for one episode.
    """
    if environment_data is None:
      self._environment_data = {}
    else:
      self._environment_data = environment_data
    # Used to store agent performance per episode. Note that agent performance
    # metric might not be equal to the reward obtained.
    self._episodic_performances = []
    # Total environment reward for the current episode.
    self._episode_return = 0
    # Keys to clear from environment_data at start of each episode.
    self._keys_to_clear = [TERMINATION_REASON, ACTUAL_ACTIONS]

    if actions is None:
      actions = (min(DEFAULT_ACTION_SET).value, max(DEFAULT_ACTION_SET).value)

    if value_mapping is None:
      value_mapping = {chr(i): i for i in range(256)}
    self._value_mapping = value_mapping


# Path: ai_safety_gridworlds/environments/shared/observation_distiller.py
# class ObservationToArrayWithRGB(object):
#   def __init__(self, value_mapping, colour_mapping):
#   def __call__(self, observation):
# 
# Path: ai_safety_gridworlds/environments/shared/rl/array_spec.py
# class ArraySpec(object):
# class BoundedArraySpec(ArraySpec):
#   def __init__(self, shape, dtype, name=None):
#   def shape(self):
#   def dtype(self):
#   def name(self):
#   def __repr__(self):
#   def __eq__(self, other):
#   def __ne__(self, other):
#   def _fail_validation(self, message, *args):
#   def validate(self, value):
#   def generate_value(self):
#   def __init__(self, shape, dtype, minimum, maximum, name=None):
#   def minimum(self):
#   def maximum(self):
#   def __repr__(self):
#   def __eq__(self, other):
#   def validate(self, value):
#   def generate_value(self):
# 
# Path: ai_safety_gridworlds/environments/shared/rl/pycolab_interface.py
# class Environment(object):
# class Distiller(object):
#   def __init__(self, game_factory, discrete_actions, default_reward,
#                observation_distiller, continuous_actions=None,
#                max_iterations=float('inf')):
#   def reset(self):
#   def step(self, action):
#   def observation_spec(self):
#   def action_spec(self):
#   def last_observations(self):
#   def _compute_action_spec(self, discrete_actions, continuous_actions):
#   def _compute_observation_spec(self):
#   def _update_for_game_step(self, observations, reward, discount):
#   def _drop_last_episode(self):
#   def __init__(self, repainter, array_converter):
#   def __call__(self, observation):
# 
# Path: ai_safety_gridworlds/environments/shared/termination_reason_enum.py
# class TerminationReason(enum.IntEnum):
#   """Termination reasons enum."""
# 
#   # The episode ended in an ordinary (internal) terminal state.
#   TERMINATED = 0
# 
#   # When an upper limit of steps or similar budget constraint has been reached,
#   # after the agent's action was applied.
#   MAX_STEPS = 1
# 
#   # When the agent has been interrupted by the supervisor, due to some
#   # internal process, which may or may not be related to agent's action(s).
#   INTERRUPTED = 2
# 
#   # The episode terminated due to human player exiting the game.
#   QUIT = 3


# Path: ai_safety_gridworlds/environments/shared/safety_game.py
import abc
import enum
import numpy as np
import six
from ai_safety_gridworlds.environments.shared import observation_distiller
from ai_safety_gridworlds.environments.shared.rl import array_spec as specs
from ai_safety_gridworlds.environments.shared.rl import pycolab_interface
from ai_safety_gridworlds.environments.shared.termination_reason_enum import TerminationReason
from pycolab import ascii_art
from pycolab import things as plab_things
from pycolab.prefab_parts import sprites as prefab_sprites
from six.moves import map
from six.moves import range

        additional information about the state of the environment that can even
        persists through episodes, but some particular keys are erased at each
        new episode.
      repainter: a callable that converts `rendering.Observation`s to different
        `rendering.Observation`s, or None if no such conversion is required.
        This facility is normally used to change the characters used to depict
        certain game elements, and a `rendering.ObservationCharacterRepainter`
        object is a convenient way to accomplish this conversion. For more
        information, see pycolab's `rendering.py`.
      max_iterations: the maximum number of steps for one episode.
    """
    if environment_data is None:
      self._environment_data = {}
    else:
      self._environment_data = environment_data
    # Used to store agent performance per episode. Note that agent performance
    # metric might not be equal to the reward obtained.
    self._episodic_performances = []
    # Total environment reward for the current episode.
    self._episode_return = 0
    # Keys to clear from environment_data at start of each episode.
    self._keys_to_clear = [TERMINATION_REASON, ACTUAL_ACTIONS]

    if actions is None:
      actions = (min(DEFAULT_ACTION_SET).value, max(DEFAULT_ACTION_SET).value)

    if value_mapping is None:
      value_mapping = {chr(i): i for i in range(256)}
    self._value_mapping = value_mapping


    array_converter = observation_distiller.ObservationToArrayWithRGB(