From a86573d529e62d751a0d43df5a10889f1ae7c4ac Mon Sep 17 00:00:00 2001 From: Kevin Cathcart Date: Sat, 6 Jan 2018 14:25:49 -0500 Subject: [PATCH] Add an extra pass to get correct spheres after culling For an example of a circumstance in which the existing code produces incorrect spheres, consider the following item locations in the vanilla entrance layout: * byrna in sphere 0 * hammer in sphere 0 * gloves in sphere 0 * bottle in sphere 0 * bow in spike cave (sphere 1) * cape in hype cave (sphere 1) * flippers on bumper cave Ledge (sphere 2) * lastly both Swamp and PoD are pendants. Well the culling phase will remove Byrna, because cape is good enough to still get the bow. But now the bow in sphere 1 depends on the cape also from sphere 1. --- Main.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Main.py b/Main.py index fbdc0e8e..c97f8637 100644 --- a/Main.py +++ b/Main.py @@ -232,8 +232,31 @@ def create_playthrough(world): for location in to_delete: sphere.remove(location) - # we are now down to just the required progress items in collection_spheres in a minimum number of spheres. As a cleanup, we right trim empty spheres (can happen if we have multiple triforces) - collection_spheres = [sphere for sphere in collection_spheres if sphere] + # we are now down to just the required progress items in collection_spheres. Unfortunately + # the previous pruning stage could potentially have made certain items dependant on others + # in the same or later sphere (because the location had 2 ways to access but the item originally + # used to access it was deemed not required.) So we need to do one final sphere collection pass + # to build up the correct spheres + + required_locations = [item for sphere in collection_spheres for item in sphere] + state = CollectionState(world) + collection_spheres = [] + while required_locations: + if not world.keysanity: + state.sweep_for_events(key_only=True) + + sphere = list(filter(state.can_reach, required_locations)) + + for location in sphere: + required_locations.remove(location) + state.collect(location.item, True, location) + + collection_spheres.append(sphere) + + logging.getLogger('').debug('Calculated final sphere %i, containing %i of %i progress items.', len(collection_spheres), len(sphere), len(required_locations)) + if not sphere: + raise RuntimeError('Not all required items reachable. Something went terribly wrong here.') + # store the required locations for statistical analysis old_world.required_locations = [location.name for sphere in collection_spheres for location in sphere]