code: def sample_frame_single_env(self, batch_size, forward_steps=1):
          
          # Whole idea of this function is to make sure that sample we take is far away from the point which we are
          # currently writing to the buffer, which is 'discontinuous'
  
          if self.current_size < self.buffer_capacity:
              # Sample from up to total size of the buffer
              # -1 because we cannot take the last one
              return np.random.choice(self.current_size - forward_steps, batch_size, replace=False)
          else:
              candidate = np.random.choice(self.buffer_capacity, batch_size, replace=False)
  
              forbidden_ones = (
                  np.arange(self.current_idx - forward_steps + 1, self.current_idx + self.frame_history)
                  % self.buffer_capacity
              )
  
              # Exclude these frames for learning as they may have some part of history overwritten
              while any(x in candidate for x in forbidden_ones):
                  candidate = np.random.choice(self.buffer_capacity, batch_size, replace=False)
  
              return candidate
docs: Return an in index of a random set of frames from a buffer, that have enough history and future