| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | import itertools | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | import random | 
					
						
							|  |  |  | import time | 
					
						
							|  |  |  | from collections import deque | 
					
						
							|  |  |  | from collections.abc import Callable, Iterable | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from BaseClasses import CollectionState, Entrance, Region, EntranceType | 
					
						
							|  |  |  | from Options import Accessibility | 
					
						
							|  |  |  | from worlds.AutoWorld import World | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EntranceRandomizationError(RuntimeError): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EntranceLookup: | 
					
						
							|  |  |  |     class GroupLookup: | 
					
						
							|  |  |  |         _lookup: dict[int, list[Entrance]] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __init__(self): | 
					
						
							|  |  |  |             self._lookup = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __len__(self): | 
					
						
							|  |  |  |             return sum(map(len, self._lookup.values())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __bool__(self): | 
					
						
							|  |  |  |             return bool(self._lookup) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __getitem__(self, item: int) -> list[Entrance]: | 
					
						
							|  |  |  |             return self._lookup.get(item, []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __iter__(self): | 
					
						
							|  |  |  |             return itertools.chain.from_iterable(self._lookup.values()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def __repr__(self): | 
					
						
							|  |  |  |             return str(self._lookup) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def add(self, entrance: Entrance) -> None: | 
					
						
							|  |  |  |             self._lookup.setdefault(entrance.randomization_group, []).append(entrance) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def remove(self, entrance: Entrance) -> None: | 
					
						
							|  |  |  |             group = self._lookup[entrance.randomization_group] | 
					
						
							|  |  |  |             group.remove(entrance) | 
					
						
							|  |  |  |             if not group: | 
					
						
							|  |  |  |                 del self._lookup[entrance.randomization_group] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dead_ends: GroupLookup | 
					
						
							|  |  |  |     others: GroupLookup | 
					
						
							|  |  |  |     _random: random.Random | 
					
						
							|  |  |  |     _expands_graph_cache: dict[Entrance, bool] | 
					
						
							|  |  |  |     _coupled: bool | 
					
						
							| 
									
										
										
										
											2025-04-05 08:21:38 -05:00
										 |  |  |     _usable_exits: set[Entrance] | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     def __init__(self, rng: random.Random, coupled: bool, usable_exits: set[Entrance], targets: Iterable[Entrance]): | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         self.dead_ends = EntranceLookup.GroupLookup() | 
					
						
							|  |  |  |         self.others = EntranceLookup.GroupLookup() | 
					
						
							|  |  |  |         self._random = rng | 
					
						
							|  |  |  |         self._expands_graph_cache = {} | 
					
						
							|  |  |  |         self._coupled = coupled | 
					
						
							| 
									
										
										
										
											2025-04-05 08:21:38 -05:00
										 |  |  |         self._usable_exits = usable_exits | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         for target in targets: | 
					
						
							|  |  |  |             self.add(target) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _can_expand_graph(self, entrance: Entrance) -> bool: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Checks whether an entrance is able to expand the region graph, either by | 
					
						
							|  |  |  |         providing access to randomizable exits or by granting access to items or | 
					
						
							|  |  |  |         regions used in logic conditions. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param entrance: A randomizable (no parent) region entrance | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # we've seen this, return cached result | 
					
						
							|  |  |  |         if entrance in self._expands_graph_cache: | 
					
						
							|  |  |  |             return self._expands_graph_cache[entrance] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         visited = set() | 
					
						
							|  |  |  |         q: deque[Region] = deque() | 
					
						
							|  |  |  |         q.append(entrance.connected_region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while q: | 
					
						
							|  |  |  |             region = q.popleft() | 
					
						
							|  |  |  |             visited.add(region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # check if the region itself is progression | 
					
						
							|  |  |  |             if region in region.multiworld.indirect_connections: | 
					
						
							|  |  |  |                 self._expands_graph_cache[entrance] = True | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # check if any placed locations are progression | 
					
						
							|  |  |  |             for loc in region.locations: | 
					
						
							|  |  |  |                 if loc.advancement: | 
					
						
							|  |  |  |                     self._expands_graph_cache[entrance] = True | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # check if there is a randomized exit out (expands the graph directly) or else search any connected | 
					
						
							|  |  |  |             # regions to see if they are/have progression | 
					
						
							|  |  |  |             for exit_ in region.exits: | 
					
						
							|  |  |  |                 # randomizable exits which are not reverse of the incoming entrance. | 
					
						
							|  |  |  |                 # uncoupled mode is an exception because in this case going back in the door you just came in could | 
					
						
							|  |  |  |                 # actually lead somewhere new | 
					
						
							| 
									
										
										
										
											2025-04-05 08:21:38 -05:00
										 |  |  |                 if (not exit_.connected_region and (not self._coupled or exit_.name != entrance.name) | 
					
						
							|  |  |  |                         and exit_ in self._usable_exits): | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                     self._expands_graph_cache[entrance] = True | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  |                 elif exit_.connected_region and exit_.connected_region not in visited: | 
					
						
							|  |  |  |                     q.append(exit_.connected_region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._expands_graph_cache[entrance] = False | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def add(self, entrance: Entrance) -> None: | 
					
						
							|  |  |  |         lookup = self.others if self._can_expand_graph(entrance) else self.dead_ends | 
					
						
							|  |  |  |         lookup.add(entrance) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def remove(self, entrance: Entrance) -> None: | 
					
						
							|  |  |  |         lookup = self.others if self._can_expand_graph(entrance) else self.dead_ends | 
					
						
							|  |  |  |         lookup.remove(entrance) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_targets( | 
					
						
							|  |  |  |             self, | 
					
						
							|  |  |  |             groups: Iterable[int], | 
					
						
							|  |  |  |             dead_end: bool, | 
					
						
							|  |  |  |             preserve_group_order: bool | 
					
						
							|  |  |  |     ) -> Iterable[Entrance]: | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         Gets available targets for the requested groups | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         :param groups: The groups to find targets for | 
					
						
							|  |  |  |         :param dead_end: Whether to find dead ends. If false, finds non-dead-ends | 
					
						
							|  |  |  |         :param preserve_group_order: Whether to preserve the group order in the returned iterable. If true, a sequence | 
					
						
							|  |  |  |                                      like AAABBB is guaranteed. If false, groups can be interleaved, e.g. BAABAB. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         lookup = self.dead_ends if dead_end else self.others | 
					
						
							|  |  |  |         if preserve_group_order: | 
					
						
							|  |  |  |             for group in groups: | 
					
						
							|  |  |  |                 self._random.shuffle(lookup[group]) | 
					
						
							|  |  |  |             ret = [entrance for group in groups for entrance in lookup[group]] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             ret = [entrance for group in groups for entrance in lookup[group]] | 
					
						
							|  |  |  |             self._random.shuffle(ret) | 
					
						
							|  |  |  |         return ret | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     def find_target(self, name: str, group: int | None = None, dead_end: bool | None = None) -> Entrance | None: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Finds a specific target in the lookup, if it is present. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param name: The name of the target | 
					
						
							|  |  |  |         :param group: The target's group. Providing this will make the lookup faster, but can be omitted if it is not | 
					
						
							|  |  |  |                       known ahead of time for some reason. | 
					
						
							|  |  |  |         :param dead_end: Whether the target is a dead end. Providing this will make the lookup faster, but can be | 
					
						
							|  |  |  |                          omitted if this is not known ahead of time (much more likely) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if dead_end is None: | 
					
						
							|  |  |  |             return (found | 
					
						
							|  |  |  |                     if (found := self.find_target(name, group, True)) | 
					
						
							|  |  |  |                     else self.find_target(name, group, False)) | 
					
						
							|  |  |  |         lookup = self.dead_ends if dead_end else self.others | 
					
						
							|  |  |  |         targets_to_check = lookup if group is None else lookup[group] | 
					
						
							|  |  |  |         for target in targets_to_check: | 
					
						
							|  |  |  |             if target.name == name: | 
					
						
							|  |  |  |                 return target | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     def __len__(self): | 
					
						
							|  |  |  |         return len(self.dead_ends) + len(self.others) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ERPlacementState: | 
					
						
							|  |  |  |     """The state of an ongoing or completed entrance randomization""" | 
					
						
							|  |  |  |     placements: list[Entrance] | 
					
						
							|  |  |  |     """The list of randomized Entrance objects which have been connected successfully""" | 
					
						
							|  |  |  |     pairings: list[tuple[str, str]] | 
					
						
							|  |  |  |     """A list of pairings of connected entrance names, of the form (source_exit, target_entrance)""" | 
					
						
							|  |  |  |     world: World | 
					
						
							|  |  |  |     """The world which is having its entrances randomized""" | 
					
						
							|  |  |  |     collection_state: CollectionState | 
					
						
							|  |  |  |     """The CollectionState backing the entrance randomization logic""" | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     entrance_lookup: EntranceLookup | 
					
						
							|  |  |  |     """A lookup table of all unconnected ER targets""" | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     coupled: bool | 
					
						
							|  |  |  |     """Whether entrance randomization is operating in coupled mode""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     def __init__(self, world: World, entrance_lookup: EntranceLookup, coupled: bool): | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         self.placements = [] | 
					
						
							|  |  |  |         self.pairings = [] | 
					
						
							|  |  |  |         self.world = world | 
					
						
							|  |  |  |         self.coupled = coupled | 
					
						
							|  |  |  |         self.collection_state = world.multiworld.get_all_state(False, True) | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         self.entrance_lookup = entrance_lookup | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def placed_regions(self) -> set[Region]: | 
					
						
							|  |  |  |         return self.collection_state.reachable_regions[self.world.player] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |     def find_placeable_exits(self, check_validity: bool, usable_exits: list[Entrance]) -> list[Entrance]: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         if check_validity: | 
					
						
							|  |  |  |             blocked_connections = self.collection_state.blocked_connections[self.world.player] | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |             placeable_randomized_exits = [ex for ex in usable_exits | 
					
						
							|  |  |  |                                           if not ex.connected_region | 
					
						
							|  |  |  |                                           and ex in blocked_connections | 
					
						
							|  |  |  |                                           and ex.is_valid_source_transition(self)] | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         else: | 
					
						
							|  |  |  |             # this is on a beaten minimal attempt, so any exit anywhere is fair game | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |             placeable_randomized_exits = [ex for ex in usable_exits if not ex.connected_region] | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         self.world.random.shuffle(placeable_randomized_exits) | 
					
						
							|  |  |  |         return placeable_randomized_exits | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _connect_one_way(self, source_exit: Entrance, target_entrance: Entrance) -> None: | 
					
						
							|  |  |  |         target_region = target_entrance.connected_region | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         target_region.entrances.remove(target_entrance) | 
					
						
							|  |  |  |         source_exit.connect(target_region) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.collection_state.stale[self.world.player] = True | 
					
						
							|  |  |  |         self.placements.append(source_exit) | 
					
						
							|  |  |  |         self.pairings.append((source_exit.name, target_entrance.name)) | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         self.entrance_lookup.remove(target_entrance) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |     def test_speculative_connection(self, source_exit: Entrance, target_entrance: Entrance, | 
					
						
							| 
									
										
										
										
											2025-02-27 10:21:48 -08:00
										 |  |  |                                     usable_exits: set[Entrance]) -> bool: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         copied_state = self.collection_state.copy() | 
					
						
							|  |  |  |         # simulated connection. A real connection is unsafe because the region graph is shallow-copied and would | 
					
						
							|  |  |  |         # propagate back to the real multiworld. | 
					
						
							|  |  |  |         copied_state.reachable_regions[self.world.player].add(target_entrance.connected_region) | 
					
						
							|  |  |  |         copied_state.blocked_connections[self.world.player].remove(source_exit) | 
					
						
							|  |  |  |         copied_state.blocked_connections[self.world.player].update(target_entrance.connected_region.exits) | 
					
						
							|  |  |  |         copied_state.update_reachable_regions(self.world.player) | 
					
						
							|  |  |  |         copied_state.sweep_for_advancements() | 
					
						
							|  |  |  |         # test that at there are newly reachable randomized exits that are ACTUALLY reachable | 
					
						
							|  |  |  |         available_randomized_exits = copied_state.blocked_connections[self.world.player] | 
					
						
							|  |  |  |         for _exit in available_randomized_exits: | 
					
						
							|  |  |  |             if _exit.connected_region: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             # ignore the source exit, and, if coupled, the reverse exit. They're not actually new | 
					
						
							|  |  |  |             if _exit.name == source_exit.name or (self.coupled and _exit.name == target_entrance.name): | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |             # make sure we are only paying attention to usable exits | 
					
						
							|  |  |  |             if _exit not in usable_exits: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |             # technically this should be is_valid_source_transition, but that may rely on side effects from | 
					
						
							|  |  |  |             # on_connect, which have not happened here (because we didn't do a real connection, and if we did, we would | 
					
						
							|  |  |  |             # not want them to persist). can_reach is a close enough approximation most of the time. | 
					
						
							|  |  |  |             if _exit.can_reach(copied_state): | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def connect( | 
					
						
							|  |  |  |             self, | 
					
						
							|  |  |  |             source_exit: Entrance, | 
					
						
							|  |  |  |             target_entrance: Entrance | 
					
						
							|  |  |  |     ) -> tuple[list[Entrance], list[Entrance]]: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Connects a source exit to a target entrance in the graph, accounting for coupling | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :returns: The newly placed exits and the dummy entrance(s) which were removed from the graph | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         source_region = source_exit.parent_region | 
					
						
							|  |  |  |         target_region = target_entrance.connected_region | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._connect_one_way(source_exit, target_entrance) | 
					
						
							|  |  |  |         # if we're doing coupled randomization place the reverse transition as well. | 
					
						
							|  |  |  |         if self.coupled and source_exit.randomization_type == EntranceType.TWO_WAY: | 
					
						
							|  |  |  |             for reverse_entrance in source_region.entrances: | 
					
						
							|  |  |  |                 if reverse_entrance.name == source_exit.name: | 
					
						
							|  |  |  |                     if reverse_entrance.parent_region: | 
					
						
							|  |  |  |                         raise EntranceRandomizationError( | 
					
						
							|  |  |  |                             f"Could not perform coupling on {source_exit.name} -> {target_entrance.name} " | 
					
						
							|  |  |  |                             f"because the reverse entrance is already parented to " | 
					
						
							|  |  |  |                             f"{reverse_entrance.parent_region.name}.") | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise EntranceRandomizationError(f"Two way exit {source_exit.name} had no corresponding entrance in " | 
					
						
							|  |  |  |                                                  f"{source_exit.parent_region.name}") | 
					
						
							|  |  |  |             for reverse_exit in target_region.exits: | 
					
						
							|  |  |  |                 if reverse_exit.name == target_entrance.name: | 
					
						
							|  |  |  |                     if reverse_exit.connected_region: | 
					
						
							|  |  |  |                         raise EntranceRandomizationError( | 
					
						
							|  |  |  |                             f"Could not perform coupling on {source_exit.name} -> {target_entrance.name} " | 
					
						
							|  |  |  |                             f"because the reverse exit is already connected to " | 
					
						
							|  |  |  |                             f"{reverse_exit.connected_region.name}.") | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise EntranceRandomizationError(f"Two way entrance {target_entrance.name} had no corresponding exit " | 
					
						
							|  |  |  |                                                  f"in {target_region.name}.") | 
					
						
							|  |  |  |             self._connect_one_way(reverse_exit, reverse_entrance) | 
					
						
							|  |  |  |             return [source_exit, reverse_exit], [target_entrance, reverse_entrance] | 
					
						
							|  |  |  |         return [source_exit], [target_entrance] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def bake_target_group_lookup(world: World, get_target_groups: Callable[[int], list[int]]) \ | 
					
						
							|  |  |  |         -> dict[int, list[int]]: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Applies a transformation to all known entrance groups on randomizable exists to build a group lookup table. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param world: Your World instance | 
					
						
							|  |  |  |     :param get_target_groups: Function to call that returns the groups that a specific group type is allowed to | 
					
						
							|  |  |  |                               connect to | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     unique_groups = { entrance.randomization_group for entrance in world.multiworld.get_entrances(world.player) | 
					
						
							|  |  |  |                       if entrance.parent_region and not entrance.connected_region } | 
					
						
							|  |  |  |     return { group: get_target_groups(group) for group in unique_groups } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-22 12:58:35 -07:00
										 |  |  | def disconnect_entrance_for_randomization(entrance: Entrance, target_group: int | None = None, | 
					
						
							|  |  |  |                                           one_way_target_name: str | None = None) -> None: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Given an entrance in a "vanilla" region graph, splits that entrance to prepare it for randomization | 
					
						
							| 
									
										
										
										
											2025-03-22 12:58:35 -07:00
										 |  |  |     in randomize_entrances. This should be done after setting the type and group of the entrance. Because it attempts | 
					
						
							|  |  |  |     to meet strict entrance naming requirements for coupled mode, this function may produce unintuitive results when | 
					
						
							|  |  |  |     called only on a single entrance; it produces eventually-correct outputs only after calling it on all entrances. | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     :param entrance: The entrance which will be disconnected in preparation for randomization. | 
					
						
							|  |  |  |     :param target_group: The group to assign to the created ER target. If not specified, the group from | 
					
						
							|  |  |  |                          the original entrance will be copied. | 
					
						
							| 
									
										
										
										
											2025-03-22 12:58:35 -07:00
										 |  |  |     :param one_way_target_name: The name of the created ER target if `entrance` is one-way. This argument | 
					
						
							|  |  |  |                                 is required for one-way entrances and is ignored otherwise. | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     child_region = entrance.connected_region | 
					
						
							|  |  |  |     parent_region = entrance.parent_region | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # disconnect the edge | 
					
						
							|  |  |  |     child_region.entrances.remove(entrance) | 
					
						
							|  |  |  |     entrance.connected_region = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create the needed ER target | 
					
						
							|  |  |  |     if entrance.randomization_type == EntranceType.TWO_WAY: | 
					
						
							|  |  |  |         # for 2-ways, create a target in the parent region with a matching name to support coupling. | 
					
						
							|  |  |  |         # targets in the child region will be created when the other direction edge is disconnected | 
					
						
							|  |  |  |         target = parent_region.create_er_target(entrance.name) | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2025-03-22 12:58:35 -07:00
										 |  |  |         # for 1-ways, the child region needs a target. naming is not a concern for coupling so we | 
					
						
							|  |  |  |         # allow it to be user provided (and require it, to prevent an unhelpful assumed name in pairings) | 
					
						
							|  |  |  |         if not one_way_target_name: | 
					
						
							|  |  |  |             raise ValueError("Cannot disconnect a one-way entrance without a target name specified") | 
					
						
							|  |  |  |         target = child_region.create_er_target(one_way_target_name) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     target.randomization_type = entrance.randomization_type | 
					
						
							|  |  |  |     target.randomization_group = target_group or entrance.randomization_group | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def randomize_entrances( | 
					
						
							|  |  |  |         world: World, | 
					
						
							|  |  |  |         coupled: bool, | 
					
						
							|  |  |  |         target_group_lookup: dict[int, list[int]], | 
					
						
							|  |  |  |         preserve_group_order: bool = False, | 
					
						
							|  |  |  |         er_targets: list[Entrance] | None = None, | 
					
						
							|  |  |  |         exits: list[Entrance] | None = None, | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | ) -> ERPlacementState: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Randomizes Entrances for a single world in the multiworld. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param world: Your World instance | 
					
						
							|  |  |  |     :param coupled: Whether connected entrances should be coupled to go in both directions | 
					
						
							|  |  |  |     :param target_group_lookup: Map from each group to a list of the groups that it can be connect to. Every group | 
					
						
							|  |  |  |                                 used on an exit must be provided and must map to at least one other group. The default | 
					
						
							|  |  |  |                                 group is 0. | 
					
						
							|  |  |  |     :param preserve_group_order: Whether the order of groupings should be preserved for the returned target_groups | 
					
						
							|  |  |  |     :param er_targets: The list of ER targets (Entrance objects with no parent region) to use for randomization. | 
					
						
							|  |  |  |                        Remember to be deterministic! If not provided, automatically discovers all valid targets | 
					
						
							|  |  |  |                        in your world. | 
					
						
							|  |  |  |     :param exits: The list of exits (Entrance objects with no target region) to use for randomization. | 
					
						
							|  |  |  |                   Remember to be deterministic! If not provided, automatically discovers all valid exits in your world. | 
					
						
							|  |  |  |     :param on_connect: A callback function which allows specifying side effects after a placement is completed | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |                        successfully and the underlying collection state has been updated. The arguments are | 
					
						
							|  |  |  |                        1. The ER state | 
					
						
							|  |  |  |                        2. The exits placed in this placement pass | 
					
						
							|  |  |  |                        3. The entrances they were connected to. | 
					
						
							|  |  |  |                        If you use on_connect to make additional placements, you are expected to return True to inform | 
					
						
							|  |  |  |                        GER that an additional sweep is needed. | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if not world.explicit_indirect_conditions: | 
					
						
							|  |  |  |         raise EntranceRandomizationError("Entrance randomization requires explicit indirect conditions in order " | 
					
						
							|  |  |  |                                          + "to correctly analyze whether dead end regions can be required in logic.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     start_time = time.perf_counter() | 
					
						
							|  |  |  |     # similar to fill, skip validity checks on entrances if the game is beatable on minimal accessibility | 
					
						
							|  |  |  |     perform_validity_check = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-27 10:21:48 -08:00
										 |  |  |     if not er_targets: | 
					
						
							|  |  |  |         er_targets = sorted([entrance for region in world.multiworld.get_regions(world.player) | 
					
						
							|  |  |  |                              for entrance in region.entrances if not entrance.parent_region], key=lambda x: x.name) | 
					
						
							|  |  |  |     if not exits: | 
					
						
							|  |  |  |         exits = sorted([ex for region in world.multiworld.get_regions(world.player) | 
					
						
							|  |  |  |                         for ex in region.exits if not ex.connected_region], key=lambda x: x.name) | 
					
						
							|  |  |  |     if len(er_targets) != len(exits): | 
					
						
							|  |  |  |         raise EntranceRandomizationError(f"Unable to randomize entrances due to a mismatched count of " | 
					
						
							|  |  |  |                                          f"entrances ({len(er_targets)}) and exits ({len(exits)}.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # used when membership checks are needed on the exit list, e.g. speculative sweep | 
					
						
							|  |  |  |     exits_set = set(exits) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     er_state = ERPlacementState( | 
					
						
							|  |  |  |         world, | 
					
						
							|  |  |  |         EntranceLookup(world.random, coupled, exits_set, er_targets), | 
					
						
							|  |  |  |         coupled | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2025-02-27 10:21:48 -08:00
										 |  |  |     # place the menu region and connected start region(s) | 
					
						
							|  |  |  |     er_state.collection_state.update_reachable_regions(world.player) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     def do_placement(source_exit: Entrance, target_entrance: Entrance) -> None: | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |         placed_exits, paired_entrances = er_state.connect(source_exit, target_entrance) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         # propagate new connections | 
					
						
							|  |  |  |         er_state.collection_state.update_reachable_regions(world.player) | 
					
						
							|  |  |  |         er_state.collection_state.sweep_for_advancements() | 
					
						
							|  |  |  |         if on_connect: | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |             change = on_connect(er_state, placed_exits, paired_entrances) | 
					
						
							|  |  |  |             if change: | 
					
						
							|  |  |  |                 er_state.collection_state.update_reachable_regions(world.player) | 
					
						
							|  |  |  |                 er_state.collection_state.sweep_for_advancements() | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-15 10:56:07 -07:00
										 |  |  |     def needs_speculative_sweep(dead_end: bool, require_new_exits: bool, placeable_exits: list[Entrance]) -> bool: | 
					
						
							|  |  |  |         # speculative sweep is expensive. We currently only do it as a last resort, if we might cap off the graph | 
					
						
							|  |  |  |         # entirely | 
					
						
							|  |  |  |         if len(placeable_exits) > 1: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # in certain stages of randomization we either expect or don't care if the search space shrinks. | 
					
						
							|  |  |  |         # we should never speculative sweep here. | 
					
						
							|  |  |  |         if dead_end or not require_new_exits or not perform_validity_check: | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # edge case - if all dead ends have pre-placed progression or indirect connections, they are pulled forward | 
					
						
							|  |  |  |         # into the non dead end stage. In this case, and only this case, it's possible that the last connection may | 
					
						
							|  |  |  |         # actually be placeable in stage 1. We need to skip speculative sweep in this case because we expect the graph | 
					
						
							|  |  |  |         # to get capped off. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # check to see if we are proposing the last placement | 
					
						
							|  |  |  |         if not coupled: | 
					
						
							|  |  |  |             # in uncoupled, this check is easy as there will only be one target. | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |             is_last_placement = len(er_state.entrance_lookup) == 1 | 
					
						
							| 
									
										
										
										
											2025-03-15 10:56:07 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             # a bit harder, there may be 1 or 2 targets depending on if the exit to place is one way or two way. | 
					
						
							|  |  |  |             # if it is two way, we can safely assume that one of the targets is the logical pair of the exit. | 
					
						
							|  |  |  |             desired_target_count = 2 if placeable_exits[0].randomization_type == EntranceType.TWO_WAY else 1 | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |             is_last_placement = len(er_state.entrance_lookup) == desired_target_count | 
					
						
							| 
									
										
										
										
											2025-03-15 10:56:07 -07:00
										 |  |  |         # if it's not the last placement, we need a sweep | 
					
						
							|  |  |  |         return not is_last_placement | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |     def find_pairing(dead_end: bool, require_new_exits: bool) -> bool: | 
					
						
							|  |  |  |         nonlocal perform_validity_check | 
					
						
							| 
									
										
										
										
											2025-02-27 08:12:35 -08:00
										 |  |  |         placeable_exits = er_state.find_placeable_exits(perform_validity_check, exits) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         for source_exit in placeable_exits: | 
					
						
							|  |  |  |             target_groups = target_group_lookup[source_exit.randomization_group] | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |             for target_entrance in er_state.entrance_lookup.get_targets(target_groups, dead_end, preserve_group_order): | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                 # when requiring new exits, ideally we would like to make it so that every placement increases | 
					
						
							|  |  |  |                 # (or keeps the same number of) reachable exits. The goal is to continue to expand the search space | 
					
						
							|  |  |  |                 # so that we do not crash. In the interest of performance and bias reduction, generally, just checking | 
					
						
							|  |  |  |                 # that we are going to a new region is a good approximation. however, we should take extra care on the | 
					
						
							|  |  |  |                 # very last exit and check whatever exits we open up are functionally accessible. | 
					
						
							|  |  |  |                 # this requirement can be ignored on a beaten minimal, islands are no issue there. | 
					
						
							|  |  |  |                 exit_requirement_satisfied = (not perform_validity_check or not require_new_exits | 
					
						
							| 
									
										
										
										
											2025-03-15 10:56:07 -07:00
										 |  |  |                                               or target_entrance.connected_region not in er_state.placed_regions) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                 if exit_requirement_satisfied and source_exit.can_connect_to(target_entrance, dead_end, er_state): | 
					
						
							| 
									
										
										
										
											2025-03-15 10:56:07 -07:00
										 |  |  |                     if (needs_speculative_sweep(dead_end, require_new_exits, placeable_exits) | 
					
						
							| 
									
										
										
										
											2025-02-27 10:21:48 -08:00
										 |  |  |                             and not er_state.test_speculative_connection(source_exit, target_entrance, exits_set)): | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                         continue | 
					
						
							|  |  |  |                     do_placement(source_exit, target_entrance) | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # no source exits had any valid target so this stage is deadlocked. retries may be implemented if early | 
					
						
							|  |  |  |             # deadlocking is a frequent issue. | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |             lookup = er_state.entrance_lookup.dead_ends if dead_end else er_state.entrance_lookup.others | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # if we're in a stage where we're trying to get to new regions, we could also enter this | 
					
						
							|  |  |  |             # branch in a success state (when all regions of the preferred type have been placed, but there are still | 
					
						
							|  |  |  |             # additional unplaced entrances into those regions) | 
					
						
							|  |  |  |             if require_new_exits: | 
					
						
							|  |  |  |                 if all(e.connected_region in er_state.placed_regions for e in lookup): | 
					
						
							|  |  |  |                     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # if we're on minimal accessibility and can guarantee the game is beatable, | 
					
						
							|  |  |  |             # we can prevent a failure by bypassing future validity checks. this check may be | 
					
						
							|  |  |  |             # expensive; fortunately we only have to do it once | 
					
						
							|  |  |  |             if perform_validity_check and world.options.accessibility == Accessibility.option_minimal \ | 
					
						
							|  |  |  |                     and world.multiworld.has_beaten_game(er_state.collection_state, world.player): | 
					
						
							|  |  |  |                 # ensure that we have enough locations to place our progression | 
					
						
							|  |  |  |                 accessible_location_count = 0 | 
					
						
							| 
									
										
										
										
											2025-02-16 14:21:09 -05:00
										 |  |  |                 prog_item_count = len([item for item in world.multiworld.itempool if item.advancement and item.player == world.player]) | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                 # short-circuit location checking in this case | 
					
						
							|  |  |  |                 if prog_item_count == 0: | 
					
						
							|  |  |  |                     return True | 
					
						
							|  |  |  |                 for region in er_state.placed_regions: | 
					
						
							|  |  |  |                     for loc in region.locations: | 
					
						
							| 
									
										
										
										
											2025-02-16 14:21:09 -05:00
										 |  |  |                         if not loc.item and loc.can_reach(er_state.collection_state): | 
					
						
							|  |  |  |                             # don't count locations with preplaced items | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |                             accessible_location_count += 1 | 
					
						
							|  |  |  |                             if accessible_location_count >= prog_item_count: | 
					
						
							|  |  |  |                                 perform_validity_check = False | 
					
						
							|  |  |  |                                 # pretend that this was successful to retry the current stage | 
					
						
							|  |  |  |                                 return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             unplaced_entrances = [entrance for region in world.multiworld.get_regions(world.player) | 
					
						
							|  |  |  |                                   for entrance in region.entrances if not entrance.parent_region] | 
					
						
							|  |  |  |             unplaced_exits = [exit_ for region in world.multiworld.get_regions(world.player) | 
					
						
							|  |  |  |                               for exit_ in region.exits if not exit_.connected_region] | 
					
						
							|  |  |  |             entrance_kind = "dead ends" if dead_end else "non-dead ends" | 
					
						
							|  |  |  |             region_access_requirement = "requires" if require_new_exits else "does not require" | 
					
						
							|  |  |  |             raise EntranceRandomizationError( | 
					
						
							|  |  |  |                 f"None of the available entrances are valid targets for the available exits.\n" | 
					
						
							|  |  |  |                 f"Randomization stage is placing {entrance_kind} and {region_access_requirement} " | 
					
						
							|  |  |  |                 f"new region/exit access by default\n" | 
					
						
							|  |  |  |                 f"Placeable entrances: {lookup}\n" | 
					
						
							|  |  |  |                 f"Placeable exits: {placeable_exits}\n" | 
					
						
							|  |  |  |                 f"All unplaced entrances: {unplaced_entrances}\n" | 
					
						
							|  |  |  |                 f"All unplaced exits: {unplaced_exits}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # stage 1 - try to place all the non-dead-end entrances | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     while er_state.entrance_lookup.others: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         if not find_pairing(dead_end=False, require_new_exits=True): | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |     # stage 2 - try to place all the dead-end entrances | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     while er_state.entrance_lookup.dead_ends: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         if not find_pairing(dead_end=True, require_new_exits=True): | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |     # stage 3 - all the regions should be placed at this point. We now need to connect dangling edges | 
					
						
							|  |  |  |     # stage 3a - get the rest of the dead ends (e.g. second entrances into already-visited regions) | 
					
						
							|  |  |  |     #            doing this before the non-dead-ends is important to ensure there are enough connections to | 
					
						
							|  |  |  |     #            go around | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     while er_state.entrance_lookup.dead_ends: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         find_pairing(dead_end=True, require_new_exits=False) | 
					
						
							|  |  |  |     # stage 3b - tie all the other loose ends connecting visited regions to each other | 
					
						
							| 
									
										
										
										
											2025-07-25 11:55:22 -07:00
										 |  |  |     while er_state.entrance_lookup.others: | 
					
						
							| 
									
										
											  
											
												Core: Generic Entrance Rando (#2883)
* Initial implementation of Generic ER
* Move ERType to Entrance.Type, fix typing imports
* updates based on testing (read: flailing)
* Updates from feedback
* Various bug fixes in ERCollectionState
* Use deque instead of queue.Queue
* Allow partial entrances in collection state earlier, doc improvements
* Prevent early loops in region graph, improve reusability of ER stage code
* Typos, grammar, PEP8, and style "fixes"
* use RuntimeError instead of bare Exceptions
* return tuples from connect since it's slightly faster for our purposes
* move the shuffle to the beginning of find_pairing
* do er_state placements within pairing lookups to remove code duplication
* requested adjustments
* Add some temporary performance logging
* Use CollectionState to track available exits and placed regions
* Add a method to automatically disconnect entrances in a coupled-compliant way
 Update docs and cleanup todos
* Make find_placeable_exits deterministic by sorting blocked_connections set
* Move EntranceType out of Entrance
* Handle minimal accessibility, autodetect regions, and improvements to disconnect
* Add on_connect callback to react to succeeded entrance placements
* Relax island-prevention constraints after a successful run on minimal accessibility; better error message on failure
* First set of unit tests for generic ER
* Change on_connect to send lists, add unit tests for EntranceLookup
* Fix duplicated location names in tests
* Update tests after merge
* Address review feedback, start docs with diagrams
* Fix rendering of hidden nodes in ER doc
* Move most docstring content into a docs article
* Clarify when randomize_entrances can be called safely
* Address review feedback
* Apply suggestions from code review
Co-authored-by: Aaron Wagener <mmmcheese158@gmail.com>
* Docs on ERPlacementState, add coupled/uncoupled handling to deadend detection
* Documentation clarifications
* Update groups to allow any hashable
* Restrict groups from hashable to int
* Implement speculative sweeping in stage 1, address misc review comments
* Clean unused imports in BaseClasses.py
* Restrictive region/speculative sweep test
* sweep_for_events->advancement
* Remove redundant __str__
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
* Allow partial entrances in auto indirect condition sweep
* Treat regions needed for logic as non-dead-end regardless of if they have exits, flip order of stage 3 and 4 to ensure there are enough exits for the dead ends
* Typing fixes suggested by mypy
* Remove erroneous newline 
Not sure why the merge conflict editor is different and worse than the normal editor. Crazy
* Use modern typing for ER
* Enforce the use of explicit indirect conditions
* Improve doc on required indirect conditions
---------
Co-authored-by: qwint <qwint.42@gmail.com>
Co-authored-by: alwaysintreble <mmmcheese158@gmail.com>
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
											
										 
											2024-12-27 12:04:02 -08:00
										 |  |  |         find_pairing(dead_end=False, require_new_exits=False) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     running_time = time.perf_counter() - start_time | 
					
						
							|  |  |  |     if running_time > 1.0: | 
					
						
							|  |  |  |         logging.info(f"Took {running_time:.4f} seconds during entrance randomization for player {world.player}," | 
					
						
							|  |  |  |                      f"named {world.multiworld.player_name[world.player]}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return er_state |