Beispiel #1
0
 def _calculate_distance(self, source_location: PickupIndex,
                         target: Area) -> int:
     source = self._index_to_node[source_location]
     return node_search.distances_to_node(self.world_list,
                                          source,
                                          patches=self.patches,
                                          ignore_elevators=False)[target]
Beispiel #2
0
def add_relative_hint(world_list: WorldList,
                      patches: GamePatches,
                      rng: Random,
                      target: PickupIndex,
                      target_precision: HintItemPrecision,
                      relative_type: HintLocationPrecision,
                      precise_distance: bool,
                      precision: Union[HintItemPrecision, HintRelativeAreaName],
                      max_distance: int,
                      ) -> Optional[Hint]:
    """
    Creates a relative hint.
    :return: Might be None, if no hint could be created.
    """
    target_node = node_search.pickup_index_to_node(world_list, target)
    target_area = world_list.nodes_to_area(target_node)
    distances = node_search.distances_to_node(world_list, target_node, patches=patches, cutoff=max_distance)

    def _major_pickups(area: Area) -> Iterator[PickupIndex]:
        for index in area.pickup_indices:
            t = patches.pickup_assignment.get(index)
            # FIXME: None should be ok, but this must be called after junk has been filled
            if t is not None:
                cat = t.pickup.item_category
                if cat.is_major_category or (cat != ItemCategory.EXPANSION
                                             and target_precision == HintItemPrecision.DETAILED):
                    yield index

    area_choices = {
        area: 1 / max(distance, 2)
        for area, distance in distances.items()
        if (distance > 0 and area.in_dark_aether == target_area.in_dark_aether
            and (relative_type == HintLocationPrecision.RELATIVE_TO_AREA or _not_empty(_major_pickups(area))))
    }
    if not area_choices:
        return None
    area = random_lib.select_element_with_weight(dict(sorted(area_choices.items(),
                                                             key=lambda a: a[0].area_asset_id)), rng)

    distance_offset = 0
    if not precise_distance:
        distance_offset = max_distance - distances[area]

    if relative_type == HintLocationPrecision.RELATIVE_TO_AREA:
        relative = RelativeDataArea(distance_offset, world_list.area_to_area_location(area),
                                    precision)
    elif relative_type == HintLocationPrecision.RELATIVE_TO_INDEX:
        relative = RelativeDataItem(distance_offset, rng.choice(list(_major_pickups(area))), precision)
    else:
        raise ValueError(f"Invalid relative_type: {relative_type}")

    precision_pair = PrecisionPair(relative_type, target_precision, include_owner=False, relative=relative)
    return Hint(HintType.LOCATION, precision_pair, target)
Beispiel #3
0
def test_distances_to_node(echoes_game_description):
    world_list = echoes_game_description.world_list
    starting_area = world_list.area_by_area_location(
        echoes_game_description.starting_location)
    starting_node = world_list.resolve_teleporter_connection(
        echoes_game_description.starting_location)

    # Run
    result = node_search.distances_to_node(world_list, starting_node)

    # Assert
    assert result[starting_area] == 0