# Path: ai_safety_gridworlds/environments/shared/safety_game.py
# class Actions(enum.IntEnum):
# class SafetyEnvironment(pycolab_interface.Environment):
# class SafetyBackdrop(plab_things.Backdrop):
# class SafetySprite(prefab_sprites.MazeWalker):
# class AgentSafetySprite(SafetySprite):
# class EnvironmentDataSprite(plab_things.Sprite):
# class EnvironmentDataDrape(plab_things.Drape):
# class PolicyWrapperDrape(six.with_metaclass(abc.ABCMeta, EnvironmentDataDrape)):
#   UP = 0
#   DOWN = 1
#   LEFT = 2
#   RIGHT = 3
#   NOOP = 4
#   QUIT = 5
# GAME_BG_COLOURS = {' ': (858, 858, 858),  # Environment floor.
#                    '#': (599, 599, 599),  # Environment walls.
#                    'A': (0, 706, 999),    # Player character.
#                    'G': (0, 823, 196)}    # Goal.
# GAME_FG_COLOURS = {' ': (858, 858, 858),
#                    '#': (599, 599, 599),
#                    'A': (0, 0, 0),
#                    'G': (0, 0, 0)}
# DEFAULT_ACTION_SET = [Actions.UP, Actions.DOWN, Actions.LEFT, Actions.RIGHT]
# ENV_DATA = 'environment_data'
# ACTUAL_ACTIONS = 'actual_actions'
# CURSES = 'curses'
# TERMINATION_REASON = 'termination_reason'
# HIDDEN_REWARD = 'hidden_reward'
# EXTRA_OBSERVATIONS = 'extra_observations'
#   ACTIONS_KEY = ACTUAL_ACTIONS
#   def __init__(self,
#                game_factory,
#                game_bg_colours,
#                game_fg_colours,
#                actions=None,
#                value_mapping=None,
#                environment_data=None,
#                repainter=None,
#                max_iterations=100):
#   def environment_data(self):
#   def current_game(self):
#   def episode_return(self):
#   def _compute_observation_spec(self):
#   def get_overall_performance(self, default=None):
#   def get_last_performance(self, default=None):
#   def _calculate_overall_performance(self):
#   def _calculate_episode_performance(self, timestep):
#   def _get_hidden_reward(self, default_reward=0):
#   def _clear_hidden_reward(self):
#   def _process_timestep(self, timestep):
#   def _get_agent_extra_observations(self):
#   def reset(self):
#   def step(self, actions):
#   def update(self, actions, board, layers, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board,
#                impassable='#'):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board,
#                impassable='#'):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def update_reward(self, proposed_actions, actual_actions,
#                     layers, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, curtain, character,
#                environment_data, original_board):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, curtain, character,
#                environment_data, original_board, agent_character):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def get_actual_actions(self, actions, things, the_plot):
#   def plot_get_actions(cls, the_plot, actions):
#   def plot_set_actions(cls, the_plot, actions):
#   def plot_clear_actions(cls, the_plot):
# def timestep_termination_reason(timestep, default=None):
# def add_hidden_reward(the_plot, reward, default=0):
# def terminate_episode(the_plot, environment_data,
#                       reason=TerminationReason.TERMINATED, discount=0.0):
# def make_safety_game(
#     environment_data,
#     the_ascii_art,
#     what_lies_beneath,
#     backdrop=SafetyBackdrop,
#     sprites=None,
#     drapes=None,
#     update_schedule=None,
#     z_order=None):
# 
# Path: ai_safety_gridworlds/environments/shared/safety_game.py
# class Actions(enum.IntEnum):
#   """Enum for actions all the players can take.
# 
#   Warning: Do not rely on these numbers staying as they are, they might change
#   in future iterations of the library. Always refer to all the action using
#   their respective enum names.
#   """
#   UP = 0
#   DOWN = 1
#   LEFT = 2
#   RIGHT = 3
#   NOOP = 4
#   # Human only.
#   QUIT = 5


import curses
import datetime
import sys
import six
from absl import flags
from ai_safety_gridworlds.environments.shared import safety_game
from ai_safety_gridworlds.environments.shared.safety_game import Actions
from pycolab import human_ui
from pycolab.protocols import logging as plab_logging

  This is deriving from pycolab's `human_ui.CursesUi` class and shares a
  lot of its code. The main purpose of having a separate class is that we want
  to use the `play()` method on an instance of `SafetyEnvironment` and not just
  a pycolab game `Engine`. This way we can store information across
  episodes, conveniently call `get_overall_performance()` after the human has
  finished playing. It is also ensuring that human and agent interact with the
  environment in the same way (e.g. if `SafetyEnvironment` gets derived).
  """

  def __init__(self, *args, **kwargs):
    super(SafetyCursesUi, self).__init__(*args, **kwargs)
    self._env = None

  def play(self, env):
    """Play a pycolab game.

    Calling this method initialises curses and starts an interaction loop. The
    loop continues until the game terminates or an error occurs.

    This method will exit cleanly if an exception is raised within the game;
    that is, you shouldn't have to reset your terminal.

    Args:
      env: An instance of `SafetyEnvironment`.

    Raises:
      RuntimeError: if this method is called while a game is already underway.
      ValueError: if `env` is not an instance of `SafetyEnvironment`.
    """

# Path: ai_safety_gridworlds/environments/shared/safety_game.py
# class Actions(enum.IntEnum):
# class SafetyEnvironment(pycolab_interface.Environment):
# class SafetyBackdrop(plab_things.Backdrop):
# class SafetySprite(prefab_sprites.MazeWalker):
# class AgentSafetySprite(SafetySprite):
# class EnvironmentDataSprite(plab_things.Sprite):
# class EnvironmentDataDrape(plab_things.Drape):
# class PolicyWrapperDrape(six.with_metaclass(abc.ABCMeta, EnvironmentDataDrape)):
#   UP = 0
#   DOWN = 1
#   LEFT = 2
#   RIGHT = 3
#   NOOP = 4
#   QUIT = 5
# GAME_BG_COLOURS = {' ': (858, 858, 858),  # Environment floor.
#                    '#': (599, 599, 599),  # Environment walls.
#                    'A': (0, 706, 999),    # Player character.
#                    'G': (0, 823, 196)}    # Goal.
# GAME_FG_COLOURS = {' ': (858, 858, 858),
#                    '#': (599, 599, 599),
#                    'A': (0, 0, 0),
#                    'G': (0, 0, 0)}
# DEFAULT_ACTION_SET = [Actions.UP, Actions.DOWN, Actions.LEFT, Actions.RIGHT]
# ENV_DATA = 'environment_data'
# ACTUAL_ACTIONS = 'actual_actions'
# CURSES = 'curses'
# TERMINATION_REASON = 'termination_reason'
# HIDDEN_REWARD = 'hidden_reward'
# EXTRA_OBSERVATIONS = 'extra_observations'
#   ACTIONS_KEY = ACTUAL_ACTIONS
#   def __init__(self,
#                game_factory,
#                game_bg_colours,
#                game_fg_colours,
#                actions=None,
#                value_mapping=None,
#                environment_data=None,
#                repainter=None,
#                max_iterations=100):
#   def environment_data(self):
#   def current_game(self):
#   def episode_return(self):
#   def _compute_observation_spec(self):
#   def get_overall_performance(self, default=None):
#   def get_last_performance(self, default=None):
#   def _calculate_overall_performance(self):
#   def _calculate_episode_performance(self, timestep):
#   def _get_hidden_reward(self, default_reward=0):
#   def _clear_hidden_reward(self):
#   def _process_timestep(self, timestep):
#   def _get_agent_extra_observations(self):
#   def reset(self):
#   def step(self, actions):
#   def update(self, actions, board, layers, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board,
#                impassable='#'):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board,
#                impassable='#'):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def update_reward(self, proposed_actions, actual_actions,
#                     layers, things, the_plot):
#   def __init__(self, corner, position, character,
#                environment_data, original_board):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, curtain, character,
#                environment_data, original_board):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def __init__(self, curtain, character,
#                environment_data, original_board, agent_character):
#   def update(self, actions, board, layers, backdrop, things, the_plot):
#   def get_actual_actions(self, actions, things, the_plot):
#   def plot_get_actions(cls, the_plot, actions):
#   def plot_set_actions(cls, the_plot, actions):
#   def plot_clear_actions(cls, the_plot):
# def timestep_termination_reason(timestep, default=None):
# def add_hidden_reward(the_plot, reward, default=0):
# def terminate_episode(the_plot, environment_data,
#                       reason=TerminationReason.TERMINATED, discount=0.0):
# def make_safety_game(
#     environment_data,
#     the_ascii_art,
#     what_lies_beneath,
#     backdrop=SafetyBackdrop,
#     sprites=None,
#     drapes=None,
#     update_schedule=None,
#     z_order=None):
# 
# Path: ai_safety_gridworlds/environments/shared/safety_game.py
# class Actions(enum.IntEnum):
#   """Enum for actions all the players can take.
# 
#   Warning: Do not rely on these numbers staying as they are, they might change
#   in future iterations of the library. Always refer to all the action using
#   their respective enum names.
#   """
#   UP = 0
#   DOWN = 1
#   LEFT = 2
#   RIGHT = 3
#   NOOP = 4
#   # Human only.
#   QUIT = 5


# Path: ai_safety_gridworlds/environments/shared/safety_ui.py
import curses
import datetime
import sys
import six
from absl import flags
from ai_safety_gridworlds.environments.shared import safety_game
from ai_safety_gridworlds.environments.shared.safety_game import Actions
from pycolab import human_ui
from pycolab.protocols import logging as plab_logging


  This is deriving from pycolab's `human_ui.CursesUi` class and shares a
  lot of its code. The main purpose of having a separate class is that we want
  to use the `play()` method on an instance of `SafetyEnvironment` and not just
  a pycolab game `Engine`. This way we can store information across
  episodes, conveniently call `get_overall_performance()` after the human has
  finished playing. It is also ensuring that human and agent interact with the
  environment in the same way (e.g. if `SafetyEnvironment` gets derived).
  """

  def __init__(self, *args, **kwargs):
    super(SafetyCursesUi, self).__init__(*args, **kwargs)
    self._env = None

  def play(self, env):
    """Play a pycolab game.

    Calling this method initialises curses and starts an interaction loop. The
    loop continues until the game terminates or an error occurs.

    This method will exit cleanly if an exception is raised within the game;
    that is, you shouldn't have to reset your terminal.

    Args:
      env: An instance of `SafetyEnvironment`.

    Raises:
      RuntimeError: if this method is called while a game is already underway.
      ValueError: if `env` is not an instance of `SafetyEnvironment`.
    """

    if not isinstance(env, safety_game.SafetyEnvironment):