Run loop that gets observations, renders them, and sends back actions.

def run(self, run_config, controller, max_game_steps=0, max_episodes=0,
          game_steps_per_episode=0, save_replay=False):
    """Run loop that gets observations, renders them, and sends back actions."""
    is_replay = (controller.status == remote_controller.Status.in_replay)
    total_game_steps = 0
    start_time = time.time()
    num_episodes = 0

    try:
      while True:
        self.init(controller.game_info(), controller.data())
        episode_steps = 0
        num_episodes += 1

        controller.step()

        while True:
          total_game_steps += self._step_mul
          episode_steps += self._step_mul
          frame_start_time = time.time()

          obs = controller.observe()
          self.render(obs)

          if obs.player_result:
            break

          cmd = self.get_actions(run_config, controller)
          if cmd == ActionCmd.STEP:
            pass
          elif cmd == ActionCmd.QUIT:
            if not is_replay and save_replay:
              self.save_replay(run_config, controller)
            return
          elif cmd == ActionCmd.RESTART:
            break
          else:
            raise Exception("Unexpected command: %s" % cmd)

          controller.step(self._step_mul)

          if max_game_steps and total_game_steps >= max_game_steps:
            return

          if game_steps_per_episode and episode_steps >= game_steps_per_episode:
            break

          with sw("sleep"):
            elapsed_time = time.time() - frame_start_time
            time.sleep(max(0, 1 / self._fps - elapsed_time))

        if is_replay:
          break

        if save_replay:
          self.save_replay(run_config, controller)

        if max_episodes and num_episodes >= max_episodes:
          break

        print("Restarting")
        controller.restart()
    except KeyboardInterrupt:
      pass
    finally:
      self.close()
      elapsed_time = time.time() - start_time
      print("took %.3f seconds for %s steps: %.3f fps" %
            (elapsed_time, total_game_steps, total_game_steps / elapsed_time))