docs: 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))