From e781e0c8908e218eaf694223ffc0b7c0f757a52b Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Sat, 6 Jul 2024 04:28:45 +0200 Subject: [PATCH 1/2] Core: cull events from multidata spheres --- BaseClasses.py | 43 +++++++++++++++++++++++++++++++++++++++++++ Main.py | 5 ++--- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 88857f803212..5d951c10f578 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -516,6 +516,49 @@ def get_spheres(self) -> Iterator[Set[Location]]: state.collect(location.item, True, location) locations -= sphere + def get_sendable_spheres(self) -> Iterator[Set[Location]]: + """ + yields a set of multiserver sendable locations (location.item.code: int) for each logical sphere + + If there are unreachable locations, the last sphere of reachable locations is followed by an empty set, + and then a set of all of the unreachable locations. + """ + state = CollectionState(self) + locations = set() + events = set() + for location in self.get_filled_locations(): + if type(location.item.code) == int: + locations.add(location) + else: + events.add(location) + + while locations: + sphere: Set[Location] = set() + + # cull events out + done_events = {None} + while done_events: + done_events = set() + for event in events: + if event.can_reach(state): + state.collect(event.item, True, event) + done_events.add(event) + events -= done_events + + for location in locations: + if location.can_reach(state): + sphere.add(location) + + yield sphere + if not sphere: + if locations: + yield locations # unreachable locations + break + + for location in sphere: + state.collect(location.item, True, location) + locations -= sphere + def fulfills_accessibility(self, state: Optional[CollectionState] = None): """Check if accessibility rules are fulfilled with current or supplied state.""" if not state: diff --git a/Main.py b/Main.py index de6b467f93d9..e016f7572788 100644 --- a/Main.py +++ b/Main.py @@ -374,11 +374,10 @@ def precollect_hint(location): # get spheres -> filter address==None -> skip empty spheres: List[Dict[int, Set[int]]] = [] - for sphere in multiworld.get_spheres(): + for sphere in multiworld.get_sendable_spheres(): current_sphere: Dict[int, Set[int]] = collections.defaultdict(set) for sphere_location in sphere: - if type(sphere_location.address) is int: - current_sphere[sphere_location.player].add(sphere_location.address) + current_sphere[sphere_location.player].add(sphere_location.address) if current_sphere: spheres.append(dict(current_sphere)) From 3455db7b44b16125ef8fb5a8bf999882e3ee9768 Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Sun, 7 Jul 2024 15:08:44 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Doug Hoskisson --- BaseClasses.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index 5d951c10f578..8392ed4c488f 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -524,10 +524,10 @@ def get_sendable_spheres(self) -> Iterator[Set[Location]]: and then a set of all of the unreachable locations. """ state = CollectionState(self) - locations = set() - events = set() + locations: Set[Location] = set() + events: Set[Location] = set() for location in self.get_filled_locations(): - if type(location.item.code) == int: + if type(location.item.code) is int: locations.add(location) else: events.add(location) @@ -536,7 +536,7 @@ def get_sendable_spheres(self) -> Iterator[Set[Location]]: sphere: Set[Location] = set() # cull events out - done_events = {None} + done_events: Set[Union[Location, None]] = {None} while done_events: done_events = set() for event in events: