示例#1
0
 def _place_walls(self, relative_wall_margin=0.05):
     """Returns blocks with walls at the edges of the scene, with some margin."""
     wall_width = self.height / 2
     margin = self.scene_width * relative_wall_margin
     scene_height = self.scene_width * 2 / 3
     right_wall = block_utils.Block(x=self.scene_width + margin +
                                    wall_width / 2.,
                                    y=scene_height / 2,
                                    height=scene_height,
                                    width=wall_width)
     left_wall = block_utils.Block(x=-margin - wall_width / 2.,
                                   y=scene_height / 2,
                                   height=scene_height,
                                   width=wall_width)
     return [right_wall, left_wall]
示例#2
0
 def _place_floor(self):
     floor_height = self.height / 2
     floor = block_utils.Block(x=self.scene_width / 2.,
                               y=-floor_height / 2.,
                               height=floor_height,
                               width=self.scene_width * 2)
     return floor
示例#3
0
 def add_block(width):
     block = block_utils.Block(x=current_position["x"] + width / 2,
                               y=current_position["y"],
                               width=width,
                               height=self.height)
     current_position["x"] += width + margin
     return block
示例#4
0
 def create_block(width, height, shape):
     """Returns a block with the specified properties."""
     block = block_utils.Block(width=width,
                               height=height,
                               angle=0.,
                               shape=shape,
                               x=0,
                               y=0)  # x and y will be set later.
     return block
示例#5
0
    def _try_to_generate_one(self):
        """Generates a single marble_run scene.

    Returns:
      observation: a block_utils.BlocksObservation object
      solution: a list of Block objects in their final locations. This generator
        in particular always returns an empty list here. Unused
    """

        # Generate ball and target.
        # Make sure that there is enough horizontal separation.
        min_horiz_dist = self._rel_horizontal_distance_range[
            0] * self.scene_width
        max_horiz_dist = self._rel_horizontal_distance_range[
            1] * self.scene_width

        # Start by assuming that the ball will go left to right.
        # Sample the position of the ball to make sure that is it at least
        # min_horiz_dist away from the right.
        ball_x = self.random_state.uniform(0,
                                           self.scene_width - min_horiz_dist)

        min_target_x = ball_x + min_horiz_dist
        # The minimum target separation is the size of the target and the ball,
        # so the ball cannot drop directly on the target.
        min_target_x = max(self._targets_height + self.height, min_target_x)

        max_target_x = ball_x + max_horiz_dist
        max_target_x = min(self.scene_width, max_target_x)

        target_x = self.random_state.uniform(min_target_x, max_target_x)

        assert target_x - ball_x < max_horiz_dist
        assert target_x - ball_x > min_horiz_dist

        # We flip a coin to exchage the positions of target and ball
        if self.random_state.randint(2):
            target_x, ball_x = ball_x, target_x

        # Make sure that the ball is at least two levels above the target.
        target_level = np.random.choice(self._target_levels)
        ball_level = np.random.choice(self._ball_levels)
        ball_level = max(ball_level,
                         target_level + self._min_ball_target_level_diff)
        targets = [
            block_utils.Block(x=target_x,
                              y=target_level,
                              shape=unity_constants.BALL_SHAPE,
                              width=self._targets_height,
                              height=self._targets_height)
        ]
        balls = [
            block_utils.Block(x=ball_x,
                              y=ball_level,
                              shape=unity_constants.BALL_SHAPE,
                              width=self.height,
                              height=self.height)
        ]

        # Generating obstacles.
        obstacles = []
        # Tesselate space and remove blocks too close to balls and targets.
        tessellation_blocks_xyw = self._build_tessellation(
            num_levels=ball_level + 1)
        for ball in balls:
            tessellation_blocks_xyw = self._remove_nearby_blocks(
                ball, tessellation_blocks_xyw)
        for target in targets:
            tessellation_blocks_xyw = self._remove_nearby_blocks(
                target, tessellation_blocks_xyw)

        # Add obstacles sequentially.
        num_obstacles = np.random.randint(*self._num_obstacles_range)
        for _ in range(num_obstacles):
            if tessellation_blocks_xyw.shape[0] == 0:
                raise stacking.GenerationError(
                    "Not possible to generate all obstacles.")
            block = self._sample_block_from_tessellation(
                tessellation_blocks_xyw, balls, targets)
            obstacles.append(
                block_utils.Block(x=block[0],
                                  y=block[1],
                                  width=block[2],
                                  height=self.obstacles_height))
            tessellation_blocks_xyw = self._remove_nearby_blocks(
                obstacles[-1], tessellation_blocks_xyw)

        floor = self._place_floor()
        observation_blocks = self._place_available_objects()
        fixed_blocks = [floor] + observation_blocks

        # Convert discrete vertical positions into continuous values.
        obstacles = self._scale_vertical_positions(obstacles)
        targets = self._scale_vertical_positions(targets)
        balls = self._scale_vertical_positions(balls)

        walls = self._place_walls()

        observation = block_utils.BlocksObservation(balls=balls,
                                                    blocks=fixed_blocks,
                                                    obstacles=walls +
                                                    obstacles,
                                                    targets=targets)

        return observation
示例#6
0
    def generate_one(self):
        """Generate a single scene.

    Returns:
      observation: a block_utils.BlocksObservation object
      solution: a list of Block objects in their final locations
    """

        # Tessellate space, fractions of the blocks lengths, with a small margin.
        # And with the standard block height.

        discrete_heights = (self._corrected_height, )
        discrete_widths = (self.small_width + self.margin,
                           self.medium_width + self.margin,
                           self.large_width + self.margin)

        # Sample a maximum height for the scene.
        num_levels = self.random_state.randint(*self._num_levels_range)
        this_scene_height = self.height * (num_levels + 0.5)

        # Set the targets.
        num_targets = self.random_state.randint(*self._num_targets_range)
        max_attempts = 10
        min_overlap = 0.9 * self.small_width
        for _ in range(max_attempts):
            # Tessellate space. This returns a list of blocks in the tesselation
            # with shape [num_blocks, 4], where the last axis, indicats, center_x,
            # center_y, width, height.
            tessellation_blocks = (
                _tessellate_discrete_rectangles_by_row_from_options(
                    scene_width=self.scene_width,
                    scene_height=this_scene_height,
                    discrete_widths=discrete_widths,
                    discrete_heights=discrete_heights,
                    random_state=self.random_state,
                    do_x_offset=True,
                    return_as="cxy_dxy"))

            # Pick num_targets blocks from possible options.
            existing_blocks = []
            for _ in range(num_targets):
                candidates = self._get_supported_blocks(
                    tessellation_blocks,
                    existing_blocks,
                    min_overlap=min_overlap)
                if not candidates:
                    break
                block_i, block = self._sample_candidates(candidates,
                                                         num_samples=1)[0]
                tessellation_blocks = np.delete(tessellation_blocks,
                                                block_i,
                                                axis=0)
                existing_blocks.append(block)
            else:
                # If we successfully added as many targets as we needed, we do not need
                # to keep attempting by breaking the loop.
                break
        else:
            # If we got here, is because we did not break out of the loop, and
            # we have exhausted all attempts.
            raise ValueError(
                "Maximum number of attempts reached to generate silhouette.")

        targets = [
            block_utils.Block(x=b[0],
                              y=b[1] + _VERTICAL_CORRECTION / 2,
                              width=b[2] - self.margin,
                              height=b[3] - _VERTICAL_CORRECTION)
            for b in existing_blocks
        ]

        # Set the obstacles.
        num_obstacles = self.random_state.randint(*self._num_obstacles_range)
        # We only require negative overlap for obstacles.
        candidates = self._get_supported_blocks(tessellation_blocks,
                                                existing_blocks,
                                                min_overlap=-2.)
        sampled_candidates = self._sample_candidates(candidates,
                                                     num_samples=min(
                                                         num_obstacles,
                                                         len(candidates)))
        obstacles = [
            block_utils.Block(x=block[0],
                              y=block[1],
                              width=block[2] - self.margin,
                              height=self.obstacles_height)
            for _, block in sampled_candidates
        ]
        tessellation_blocks = np.delete(
            tessellation_blocks,
            [block_i for block_i, _ in sampled_candidates],
            axis=0)
        observation_blocks = self._place_available_objects()
        floor = self._place_floor()

        observation = block_utils.BlocksObservation(blocks=[floor] +
                                                    observation_blocks,
                                                    obstacles=obstacles,
                                                    targets=targets,
                                                    balls=[])

        return observation
示例#7
0
    def generate_one(self):
        """Generate a single scene.

    Returns:
      observation: a block_utils.BlocksObservation object
      solution: a list of Block objects in their final locations
    """
        # Pick the set of y-positions we want for our obstacles
        idx = np.arange(len(self._obstacles_ys_range))
        obstacles_ys_range = self._obstacles_ys_range[self.random_state.choice(
            idx)]
        # Place the obstacles at each level, going from bottom to top
        obstacles = []
        for y in obstacles_ys_range:
            available_widths = np.arange(*self._obstacles_width_range)
            obstacles_begins, obstacles_ends = self._generate_line_of_blocks(
                available_widths=available_widths,
                num_blocks=self.random_state.randint(
                    *self._num_obstacles_range),
                min_available_width=self.small_width + 1,
                min_interdistance=self._min_obstacles_interdistance)
            # Now actually create the obstacles
            for obstacle_begin, obstacle_end in zip(obstacles_begins,
                                                    obstacles_ends):
                center = (obstacle_begin + obstacle_end) // 2
                width = obstacle_end - obstacle_begin
                obstacle = block_utils.Block(x=center,
                                             y=y,
                                             width=width,
                                             height=self.obstacles_height)
                obstacles.append(obstacle)

        # Pick y positions for the targets
        idx = np.arange(len(self._targets_ys_range))
        targets_ys_range = self._targets_ys_range[self.random_state.choice(
            idx)]
        targets = []
        for y in targets_ys_range:
            available_widths = [self.small_width, self.medium_width]
            if not self._use_legacy_obstacles_heights:
                available_widths = [self._targets_side]
            num_targets = self.random_state.randint(*self._num_targets_range)
            targets_begins, targets_ends = self._generate_line_of_blocks(
                available_widths=available_widths,
                num_blocks=num_targets,
                min_interdistance=self._min_targets_interdistance)
            for target_begin, target_end in zip(targets_begins, targets_ends):
                center = (target_begin + target_end) // 2
                width = target_end - target_begin
                target = block_utils.Block(x=center,
                                           y=y,
                                           width=width,
                                           height=self._targets_height)
                targets.append(target)

        observation_blocks = self._place_available_objects()
        floor = self._place_floor()

        observation = block_utils.BlocksObservation(blocks=[floor] +
                                                    observation_blocks,
                                                    obstacles=obstacles,
                                                    targets=targets,
                                                    balls=[])

        return observation
示例#8
0
  def generate_one(self):
    """Generate a single scene.

    Returns:
      observation: a BlocksObservation object
      solution: a list of Block objects in their final locations
    """
    # pick the set of y-positions we want for our obstacles
    idx = np.arange(len(self._obstacles_ys_range))
    obstacles_ys = self._obstacles_ys_range[self.random_state.choice(idx)]

    # place the obstacles at each level, going from bottom to top
    obstacles = []
    for y in obstacles_ys:

      # get the number of obstacles at this layer
      num_obstacles = self.random_state.randint(*self.num_blocks_range)

      # pick a set of obstacle widths, and check that the sum of the widths is
      # not greater than the scene width plus some buffer room. keep regenerting
      # obstacles until this is the case.
      available_width = 0
      while available_width < self.small_width + 1:
        available_widths = np.arange(*self._obstacles_width_range)
        obstacles_lengths = self.random_state.choice(
            available_widths, size=[num_obstacles])
        available_width = self.scene_width - np.sum(obstacles_lengths)

      # compute the left and right edges of each obstacle, assuming the
      # obstacles are all placed right next to each other beginning from the
      # left side of the scene.
      obstacles_begins = np.concatenate(
          [np.array([0], dtype=np.int32), np.cumsum(obstacles_lengths)[:-1]])
      obstacles_ends = np.cumsum(obstacles_lengths)

      # available_width now is the amount of space left on the floor, not taken
      # up by obstacles. we split this into a few chunks of random size to space
      # the obstacles out along the floor
      relative_shifts = self.random_state.uniform(
          0., 1., size=[num_obstacles + 1])
      relative_shifts /= np.sum(relative_shifts)
      relative_shifts = np.floor(relative_shifts * available_width)
      shifts = np.cumsum(relative_shifts.astype(np.int32))[:-1]
      obstacles_begins += shifts
      obstacles_ends += shifts

      # now actually create the obstacles
      for obstacle_begin, obstacle_end in zip(obstacles_begins, obstacles_ends):
        center = (obstacle_begin + obstacle_end) // 2
        width = obstacle_end - obstacle_begin
        obstacle = block_utils.Block(
            x=center, y=y, width=width, height=self.obstacle_height)
        obstacles.append(obstacle)

    observation_blocks = self._place_available_objects()
    floor = self._place_floor()

    observation = block_utils.BlocksObservation(
        blocks=[floor] + observation_blocks,
        obstacles=obstacles,
        targets=[],
        balls=[])

    return observation