From 27f240abf5d11b77f91b33a9942bc0d8835b4a39 Mon Sep 17 00:00:00 2001 From: Dragion147 Date: Wed, 25 Dec 2024 10:32:59 +0100 Subject: [PATCH 1/2] Alter mimic scaling to instead of creating new items it now swaps mimics from future spheres. It does a best effort to try and scale the mimics according to sphere depth with some variety in each sphere so it's not all just the same types over and over again. As with all random based solutions it's hard to find a good middle ground where it is diverse enough but still fair, about 50% preplaced mimics in correct spheres will remain in that sphere, the rest will get swapped up to a certain sphere depth. --- worlds/gstla/__init__.py | 82 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/worlds/gstla/__init__.py b/worlds/gstla/__init__.py index 3639bc1d357b..b7471d849c20 100644 --- a/worlds/gstla/__init__.py +++ b/worlds/gstla/__init__.py @@ -272,25 +272,93 @@ def _handle_spheres(self): def _scale_mimics(self, max_sphere: int, mimic_map: defaultdict[int, List[GSTLALocation]]): mimic_lists = [] + mimic_lists.append(mimics[:2]) for i in range(1, len(mimics) - 1): mimic_lists.append(mimics[i - 1:i + 2]) + mimic_lists.append(mimics[-2:]) - breakpoints = [(max_sphere + 1) / 7 * i for i in range(1, 8)] + breakpoints = [(max_sphere + 1) / len(mimic_lists) * i for i in range(1, len(mimic_lists))] - for sphere, mimic_locs in mimic_map.items(): + #First pass checking if mimics are already located in spheres they are allowed to be, if so we can lock those in place so they wont get altered anymore + for sphere, mimic_locs in sorted(mimic_map.items(), key= lambda s: s[0]): breakpoint_index = bisect(breakpoints, sphere) if breakpoint_index >= len(mimic_lists): breakpoint_index = len(mimic_lists) - 1 mimic_list = mimic_lists[breakpoint_index] + #logger.info("Sphere %d, Mimic List %s", sphere, [mimic.name for mimic in mimic_list]) for mimic_loc in mimic_locs: if mimic_loc.locked: # Guess someone really wanted this mimic here continue - current_item = mimic_loc.item - current_item.location = None - new_mimic = create_item_direct(self.random.choice(mimic_list), self.player) - # logger.info("Replacing mimic %s with mimic %s in sphere %d", current_item.name, new_mimic.name, sphere) - mimic_loc.item = new_mimic + + if mimic_loc.item.name in [mimic.name for mimic in mimic_list]: + #this mimic is allowed to be in this sphere so most of the time we leave it alone, if this is guarenteed the end swap results tend to be very chaotic as not a lot of mimics can be swapped + if self.random.randint(0, 1) == 1: + mimic_loc.locked = True + continue + + #optimization to avoid looping over mimic types we already know we have swapped all future sphere instances of a particular type + swapped_mimic_types = [] + #second pass where real swapping of mimics can take place + for sphere, mimic_locs in sorted(mimic_map.items(), key= lambda s: s[0]): + breakpoint_index = bisect(breakpoints, sphere) + if breakpoint_index >= len(mimic_lists): + breakpoint_index = len(mimic_lists) - 1 + mimic_list = mimic_lists[breakpoint_index] + for mimic_loc in mimic_locs: + if mimic_loc.locked: + # Guess someone really wanted this mimic here + continue + + if mimic_loc.item.name in [mimic.name for mimic in mimic_list]: + #This mimic is allowed to be in this sphere so we leave it alone + mimic_loc.locked = True + continue + + mimic_swapped = False + for mimic_type in mimics: + if mimic_type.name in swapped_mimic_types: + continue + + if mimic_swapped: + break + for sphere2, mimic_locs2 in sorted(mimic_map.items(), key= lambda s: s[0], reverse=True): + if mimic_swapped: + break + + #Do no try to swap mimics from the same or earlier spheres, assuming that earlier spheres are weaker and we do not want to move those around again + if sphere2 <= sphere: + swapped_mimic_types.append(mimic_type.name) + #logger.info("No suitable mimics of type %s found to swap with in sphere %d or later, trying next type", mimic_type.name, sphere2) + break + + for mimic_loc2 in mimic_locs2: + if mimic_loc2.locked: + continue + + #should only occur if we have a weaker mimic than our sphere allows and this fail safe makes sure we dont put a tougher mimic earlier + #if a weaker mimic is available it would have gone through the next if statement below + if mimic_loc.item.name == mimic_type.name: + mimic_loc.locked = True + mimic_swapped = True + swapped_mimic_types.append(mimic_type.name) + #logger.info("Hit same type mimic %s, search is over in sphere %d. Not replacing instance at %s in sphere %d from player", mimic_type.name, sphere2, mimic_loc.name, sphere, mimic_loc.item.player) + break + + if mimic_loc2.item.name == mimic_type.name: + temp_item = mimic_loc.item + mimic_loc.item = mimic_loc2.item + mimic_loc.item.location = mimic_loc + mimic_loc.locked = True + mimic_loc2.item = temp_item + mimic_loc2.item.location = mimic_loc2 + mimic_swapped = True + #logger.info("Swapping mimic %s at %s in sphere %d from player %s with mimic %s from %s in sphere %d from player %s", temp_item.name, mimic_loc.name, sphere, temp_item.player, mimic_loc.item.name, mimic_loc2.name, sphere2, mimic_loc.item.player) + break + + #Restrict swapping to not bother sweeping all spheres, by this point it should be organized enough + if sphere >= max_sphere * 0.75: + break def _scale_characters(self, max_sphere: int, char_map: defaultdict[int, List[GSTLAItem]]): max_level = self.options.max_scaled_level.value From aaa9044495287fbf8964202a7dd4c75d51a44d68 Mon Sep 17 00:00:00 2001 From: Dragion147 Date: Wed, 25 Dec 2024 11:02:34 +0100 Subject: [PATCH 2/2] Additional optimization and introduces a bit more randomness in mimics in the spheres that just happen to be correctly placed by the randomizer. Therefor we only swap mimics that really do not belong in their spheres and swap them with whatever the weakest mimics are left that we can find and aren't locked --- worlds/gstla/__init__.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/worlds/gstla/__init__.py b/worlds/gstla/__init__.py index b7471d849c20..912d13e9c201 100644 --- a/worlds/gstla/__init__.py +++ b/worlds/gstla/__init__.py @@ -292,9 +292,8 @@ def _scale_mimics(self, max_sphere: int, mimic_map: defaultdict[int, List[GSTLAL continue if mimic_loc.item.name in [mimic.name for mimic in mimic_list]: - #this mimic is allowed to be in this sphere so most of the time we leave it alone, if this is guarenteed the end swap results tend to be very chaotic as not a lot of mimics can be swapped - if self.random.randint(0, 1) == 1: - mimic_loc.locked = True + #this mimic is allowed to be in this sphere so we leave it alone + mimic_loc.locked = True continue #optimization to avoid looping over mimic types we already know we have swapped all future sphere instances of a particular type @@ -310,11 +309,6 @@ def _scale_mimics(self, max_sphere: int, mimic_map: defaultdict[int, List[GSTLAL # Guess someone really wanted this mimic here continue - if mimic_loc.item.name in [mimic.name for mimic in mimic_list]: - #This mimic is allowed to be in this sphere so we leave it alone - mimic_loc.locked = True - continue - mimic_swapped = False for mimic_type in mimics: if mimic_type.name in swapped_mimic_types: