GER: Prefer expanding reachable regions in stage 1 - #6387
Conversation
I would also add for reviewers' sake, this is not a unique problem to this world, several worlds in the past have exhibited similar symptoms (I don't remember which they are but I have recommended people to implement retries many times, something I would also like in GER in a future change) |
| while stale: | ||
| copied_state.update_reachable_regions(self.world.player) | ||
| copied_state.sweep_for_advancements(self.world.get_locations()) | ||
| stale = copied_state.stale[self.world.player] |
There was a problem hiding this comment.
It would probably be good to add one or more test covering this case to prevent a regression in the various places it was observed
| 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" | ||
| region_access_requirement = "requires" if exit_requirement == ExitRequirement.NEW_REGIONS else "does not require" |
There was a problem hiding this comment.
I would consider updating this error message for additional clarity to distinguish between when we are chasing entrances vs just regions
There was a problem hiding this comment.
The error message never triggers when in the more exits state
| while er_state.entrance_lookup.others: | ||
| if not find_pairing(dead_end=False, require_new_exits=True): | ||
| break | ||
| if not find_pairing(dead_end=False, exit_requirement=ExitRequirement.MORE_EXITS): |
There was a problem hiding this comment.
I had mentioned this in discord but due to the performance cost, some worlds may wish to opt out of this new behavior. I think it is a sensible default though so I would add it as an optional input, default true. Given that the arg list to randomize_entrances is already quite long, it might be a good idea to introduce this as a kw-only arg so that it (and future optional args) can be safely rearranged for organizational purposes in the future
What is this fixing or adding?
Changes the behavior of GER to prefer expanding reachable regions in stage 1 (when placing non-dead-end entrances to reach new regions). As long as there is a valid placement and there are less reachable randomized exits than to be placed non-dead-end entrances, it will try to run
test_speculative_connectionto make sure the reachable randomized exit count doesn't decrease. However, it is possible to run out of valid placements and need to place entrances that decrease reachable exits in order to satisfy future entrance access rules.These changes were motivated by trying to solve an issue with my world where GER was often painting itself into a corner. Some of these issues I was able to solve with complicated
can_connect_tofunction but that required playing a lot of whack-a-mole and the resulting code is not very maintainable. With these generic GER changes, I was able to greatly simplify mycan_connect_tofunction while improving my ER failure rate. Here are some cases that these changes handle generically that I previously had to specifically account for in mycan_connect_tofunction.Additionally, this change uncovered a bug where GER wasn't updating reachable regions correctly in
test_speculative_connectionanddo_placement. It was callingupdate_reachable_regionsfollowed bysweep_for_advancements. The latter has the chance to collect items and stale the collection state, requiring more rounds ofupdate_reachable_regionsfollowed bysweep_for_advancementsuntil nothing is collected.How was this tested?
Fuzzing for GER failures and benchmark times.
I tested four worlds that implement GER: Toem (my world), Stardew Valley (core), The Messenger (core), and Hollow Knight (beta). The latter three worlds already had a 0% GER failure rate which was maintained by these changes. On the worst case settings with no retries, Toem has a 11% GER failure rate with the complicated
can_connect_tobefore these changes, a 57% GER failure rate with the simplecan_connect_tobefore these changes, and a 0% GER failure rate with the simplecan_connect_toafter these changes. The failure rate before these changes can be improved by retrying GER, but obviously that comes at the cost of taking more time.However, these changes are slower per GER run (around 3-4 times worse in some cases). This is due to more aggressively running
test_speculative_connectionwhich is reasonably expensive. Here is a table of benchmark times for ER for all the worlds. Note that Toem v1 is with the complicatedcan_connect_toand v2 is the simplecan_connect_to. These times include retries for Toem as well.