mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 04:01:32 -06:00
Core: Generic ER fails in stage 1 when the last available target is an indirect conditioned dead end (#4679)
* Add test that stage1 ER will not fail due to speculative sweeping an indirect conditioned dead end * Skip speculative sweep if it's the last entrance placement * Better implementation of needs_speculative_sweep * pep8
This commit is contained in:
@@ -358,6 +358,34 @@ def randomize_entrances(
|
||||
if on_connect:
|
||||
on_connect(er_state, placed_exits)
|
||||
|
||||
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.
|
||||
is_last_placement = len(entrance_lookup) == 1
|
||||
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
|
||||
is_last_placement = len(entrance_lookup) == desired_target_count
|
||||
# if it's not the last placement, we need a sweep
|
||||
return not is_last_placement
|
||||
|
||||
def find_pairing(dead_end: bool, require_new_exits: bool) -> bool:
|
||||
nonlocal perform_validity_check
|
||||
placeable_exits = er_state.find_placeable_exits(perform_validity_check, exits)
|
||||
@@ -371,11 +399,9 @@ def randomize_entrances(
|
||||
# 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
|
||||
or target_entrance.connected_region not in er_state.placed_regions)
|
||||
needs_speculative_sweep = (not dead_end and require_new_exits and perform_validity_check
|
||||
and len(placeable_exits) == 1)
|
||||
or target_entrance.connected_region not in er_state.placed_regions)
|
||||
if exit_requirement_satisfied and source_exit.can_connect_to(target_entrance, dead_end, er_state):
|
||||
if (needs_speculative_sweep
|
||||
if (needs_speculative_sweep(dead_end, require_new_exits, placeable_exits)
|
||||
and not er_state.test_speculative_connection(source_exit, target_entrance, exits_set)):
|
||||
continue
|
||||
do_placement(source_exit, target_entrance)
|
||||
|
Reference in New Issue
Block a user