def generate_distract_objects(self,
                                distinct_objects,
                                obligatory_objects,
                                target_object,
                                target_ref_object,
                                target_position,
                                ref_position,
                                ref_predicate,
                                max_distract_objects,
                                is_target_distinct_from_ref,
                                max_trials=3):
    """Generate and place distract objects based on target and its reference."""
    distract_positions = []
    num_distract_objects = random.sample(
        range(1, max_distract_objects + 1), k=1).pop()
    trail = 0
    # Sample positions for distract objects. Avoid target being distractor's
    # reference object when target is not distinct from its reference.
    # e.g. when target object is red square and reference object is square.
    for _ in range(num_distract_objects):
      if self._vocabulary.translate_word(
          ref_predicate["location"]) == "next to":
        # The distractor cannot be next to the reference object.
        position = self._world.sample_non_nearby_position(ref_position)
        while (not is_target_distinct_from_ref and
               position in self._world.get_nearby_positions(target_position)):
          position = self._world.sample_non_nearby_position(ref_position)
          trail += 1
          if trail > max_trials:
            return False
      else:
        position = self._world.sample_position()
        while (not is_target_distinct_from_ref and
               target_position == self._world.get_relative_position(
                   position, ref_predicate["location"])):
          position = self._world.sample_position()
          trail += 1
          if trail > max_trials:
            return False
      if not position:
        return False
      self._world.place_object(target_object, position=position)
      distract_positions.append(position)

    # Sample some reference objects for distractors.
    reference_objects = random.sample(
        distinct_objects, k=num_distract_objects - len(obligatory_objects))
    objects_to_place = obligatory_objects + reference_objects
    assert len(objects_to_place) == len(
        distract_positions) == num_distract_objects

    # Place distractors' reference objects.
    for ref_object, position in zip(objects_to_place, distract_positions):
      size, color, shape = ref_object
      ref_location = self._vocabulary.translate_word(ref_predicate["location"])
      p = random.uniform(0, 1)
      if ref_location == "next to":
        # With 1/2 probability we don't place any reference object.
        if p < 0.5 and ref_object not in obligatory_objects:
          continue
        # With 1/2 probability, we place a random reference object.
        other_position = self._world.sample_nearby_position(position)
      else:
        # With 1/3 probability we don't place any reference object.
        if p < 1 / 3 and ref_object not in obligatory_objects:
          continue
        # With 1/3 probability, we place a reference object that is the same
        # as target's reference but with a different relative position.
        if 1 / 3 <= p < 2 / 3 and ref_object not in obligatory_objects:
          other_position = self._world.sample_nearby_position(
              position, exclude_locations=[ref_location])
          size, color, shape = target_ref_object
        # With 1/3 probability, we place a random reference object.
        else:
          other_position = self._world.sample_nearby_position(position)
      if other_position:
        self._world.place_object(
            world_lib.Object(size=size, color=color, shape=shape),
            position=other_position)
    return True
Generate and place distract objects based on target and its reference.
language/gscan/data/dataset.py