Пример #1
0
def fill_unassigned_hints(
    patches: GamePatches,
    world_list: WorldList,
    rng: Random,
) -> GamePatches:
    new_hints = copy.copy(patches.hints)

    # Get all LogbookAssets from the WorldList
    potential_hint_locations: Set[LogbookAsset] = {
        node.resource()
        for node in world_list.all_nodes if isinstance(node, LogbookNode)
    }

    # But remove these that already have hints
    potential_hint_locations -= patches.hints.keys()

    # Get interesting items to place hints for
    possible_indices = set(patches.pickup_assignment.keys())
    possible_indices -= {hint.target for hint in patches.hints.values()}
    possible_indices -= {
        index
        for index in possible_indices
        if not should_have_hint(patches.pickup_assignment[index].item_category)
    }

    debug.debug_print(
        "fill_unassigned_hints had {} decent indices for {} hint locations".
        format(len(possible_indices), len(potential_hint_locations)))

    # But if we don't have enough hints, just pick randomly from everything
    if len(possible_indices) < len(potential_hint_locations):
        possible_indices = {
            node.pickup_index
            for node in world_list.all_nodes if isinstance(node, PickupNode)
        }

    # Get an stable order then shuffle
    possible_indices = list(sorted(possible_indices))
    rng.shuffle(possible_indices)

    for logbook in sorted(potential_hint_locations):
        new_hints[logbook] = Hint(HintType.LOCATION, None,
                                  possible_indices.pop())
        debug.debug_print(
            f"Added hint at {logbook} for item at {new_hints[logbook].target}")

    return dataclasses.replace(patches, hints=new_hints)
Пример #2
0
def _calculate_hint_location_for_action(action: PickupEntry,
                                        current_uncollected: UncollectedState,
                                        pickup_index: PickupIndex,
                                        rng: Random,
                                        scan_asset_initial_pickups: Dict[LogbookAsset, FrozenSet[PickupIndex]],
                                        ) -> Optional[LogbookAsset]:
    """
    Calculates where a hint for the given action should be placed.
    :return: A LogbookAsset to use, or None if no hint should be placed.
    """
    if should_have_hint(action.item_category):
        potential_hint_locations = [
            logbook_asset
            for logbook_asset in current_uncollected.logbooks
            if pickup_index not in scan_asset_initial_pickups[logbook_asset]
        ]
        if potential_hint_locations:
            return rng.choice(potential_hint_locations)
    return None
Пример #3
0
def fill_unassigned_hints(patches: GamePatches,
                          world_list: WorldList,
                          rng: Random,
                          scan_asset_initial_pickups: Dict[LogbookAsset, FrozenSet[PickupIndex]],
                          ) -> GamePatches:
    new_hints = copy.copy(patches.hints)

    # Get all LogbookAssets from the WorldList
    potential_hint_locations: Set[LogbookAsset] = {
        node.resource()
        for node in world_list.all_nodes
        if isinstance(node, LogbookNode)
    }
    for logbook in potential_hint_locations:
        if logbook not in scan_asset_initial_pickups:
            scan_asset_initial_pickups[logbook] = frozenset()

    # But remove these that already have hints
    potential_hint_locations -= patches.hints.keys()

    # Get interesting items to place hints for
    possible_indices = set(patches.pickup_assignment.keys())
    possible_indices -= {hint.target for hint in patches.hints.values() if hint.target is not None}
    possible_indices -= {index for index in possible_indices
                         if not should_have_hint(patches.pickup_assignment[index].pickup.item_category)}

    debug.debug_print("fill_unassigned_hints had {} decent indices for {} hint locations".format(
        len(possible_indices), len(potential_hint_locations)))

    if debug.debug_level() > 1:
        print(f"> Num pickups per asset:")
        for asset, pickups in scan_asset_initial_pickups.items():
            print(f"* {asset}: {len(pickups)} pickups")
        print("> Done.")

    # But if we don't have enough hints, just pick randomly from everything
    if len(possible_indices) < len(potential_hint_locations):
        possible_indices = {node.pickup_index
                            for node in world_list.all_nodes
                            if isinstance(node, PickupNode)}

    # Get an stable order
    ordered_possible_indices = list(sorted(possible_indices))
    ordered_potential_hint_locations = list(sorted(potential_hint_locations))

    num_logbooks: Dict[PickupIndex, int] = {
        index: sum(1 for indices in scan_asset_initial_pickups.values() if index in indices)
        for index in ordered_possible_indices
    }
    max_seen = max(num_logbooks.values())
    pickup_indices_weight: Dict[PickupIndex, int] = {
        index: max_seen - num_logbook
        for index, num_logbook in num_logbooks.items()
    }
    # Ensure all indices are present with at least weight 0
    for index in ordered_possible_indices:
        if index not in pickup_indices_weight:
            pickup_indices_weight[index] = 0

    for logbook in sorted(ordered_potential_hint_locations,
                          key=lambda r: len(scan_asset_initial_pickups[r]),
                          reverse=True):
        try:
            new_index = random_lib.select_element_with_weight(pickup_indices_weight, rng)
        except StopIteration:
            # If everything has weight 0, then just choose randomly.
            new_index = random_lib.random_key(pickup_indices_weight, rng)
            
        del pickup_indices_weight[new_index]

        new_hints[logbook] = Hint(HintType.LOCATION, None, new_index)
        debug.debug_print(f"Added hint at {logbook} for item at {new_index}")

    return dataclasses.replace(patches, hints=new_hints)