Skip to content

Core: linearish, create playthrough alternative - #6326

Open
Severencir wants to merge 16 commits into
ArchipelagoMW:mainfrom
Severencir:sphere-fulfillment
Open

Core: linearish, create playthrough alternative#6326
Severencir wants to merge 16 commits into
ArchipelagoMW:mainfrom
Severencir:sphere-fulfillment

Conversation

@Severencir

Copy link
Copy Markdown
Contributor

What is this fixing or adding?

This is a new pr to replace one that was lost with the deletion of a branch.

the algorithm is linear with number of unique advancements x spheres. with progression balancing on, number of spheres tends to stay relatively consistent. without progression balancing, spheres grow sublinearly with number of players and seems to plateu around 300 from my testing. either way it has consistently beaten stock create playthrough in every test i have made.

the algorithm first builds spheres and takes a state snapshot at each sphere to use as a base for later sphere processing.
it then separates locations that require cross world logic by rebuilding the spheres per player using only that players items. any locations that are not reachable at the same sphere they were with the global sphere build are considered global (relies on another players' items)

we loop through every sphere in reverse sphere order looking for an irreducible set of items that allow us to beat the game and collect locations that are required to beat the game or required for other required locations.

the main loop relies on a couple patterns:

  1. if a player only relies on that players' items, then we can use a cheap player scoped copy of the player's state to process it.
  2. you don't need to collect every available advancement to prove beatability. this algorithm assumes every lower sphere is fully collected (will be reduced later), and just looks for what in this sphere is required to beat the game, and acquire any other items deemed necessary. looking for an irreducible set of items from a sphere that allow the goals, and all higher sphere required locations to be reached.
  3. if at any point a fungible item (items for which there are multiple copies that do the same thing) is determined to be necessary it is guaranteed that every copy in the state, including those that came before it in this sphere, and those in lower spheres, are required. the reason being that because the search looks for which item flips a condition, we know that before the item was added, the condition was false, and after, the condition is true. since the condition turned true on collection of the fungible item, we know that whatever count of fungible items we have was required.

the search method takes a bulk group of locations and looks for the minimal set from the sphere that satisfies the group using a binary search with a state cache stack. we collect all items in a sphere in order to a probe point. when we find the item that satisfies the whole set, we know that it is required by the set and nothing before it can satisfy the set, and it's the earliest point in the sphere where that is true, therefore it is minimal to the set we are searching, and necessary. we keep searching in this manner until we find all such items.

for global items we binary search the whole sphere, but for others, we only use player scoped states and their partition of the sphere.

for efficiency and minimal-ness, we force all higher sphere required items into the state before we search for dependencies so that we can let the set use them as prerequisites. this allows items to become their own prerequisite though, so we have to individually resolve any locations that are still not able to be reached after the search. because we are now adding items that were not found in the bulk search, we lose the minimal guarantee, so we can run it again with the circular resolving items forced to re-minimize. loop through that until there are no circular dependencies.

because the items required to resolve circular dependencies, as well as the prerequisites found in the global search, were found outside the last bulk search, we cannot guarantee that these are necessary. but they are few, and we only need to know if we can reach higher spheres with them, so we do a typical remove and test but cheaper than the stock method and on only a handful of locations.

because we know that all lower sphere copies of a type of fungible item are required whenever we find any required, we can simply promote them to the required set, add them to the base, and move on to the rest of the sphere.

at the end we use a can_beat_game check to ensure that the set is sufficient. falling back to stock if it fails, or any other step cannot fulfill something.

How was this tested?

this was tested by generating many seeds (i have lost track) across 5-320 player sets with default and randomized settings all coming back sufficient and minimal. (unable to be reduced by the remove and test method)
additional testing was done with hk's grubhunt and item-links with all successful
i even found other bugs with generation while testing and submitted a fix for one i was able to identify the cause of.

@github-actions github-actions Bot added affects: core Issues/PRs that touch core and may need additional validation. waiting-on: peer-review Issue/PR has not been reviewed by enough people yet. labels Jul 11, 2026
@duckboycool duckboycool added the is: enhancement Issues requesting new features or pull requests implementing new features. label Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

affects: core Issues/PRs that touch core and may need additional validation. is: enhancement Issues requesting new features or pull requests implementing new features. waiting-on: peer-review Issue/PR has not been reviewed by enough people yet.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants