Core: Don't waste swaps by swapping two copies of the same item (#5516)

There is a limit to the number of times an item can be swapped to
prevent swapping going on potentially forever. Swapping an item with a
copy of itself is assumed to be a pointless swap, and was wasting
possible swaps in cases where there were multiple copies of an item
being placed.

This swapping behaviour was noticed from debugging solo LADX generations
that was wasting swaps by swapping copies of the same item.

This patch adds a check that if the placed_item and item_to_place are
equal, then the location is skipped and no attempt to swap is made.

If worlds do intend to have seemingly equal items to actually have
different logical behaviour, those worlds should override __eq__ on
their Item subclasses so that the item instances are not considered
equal.

Generally, fill_restrictive should only be used with progression items,
so it is assumed that swapping won't have to deal with multiple copies
of an item where some copies are progression and some are not. This is
relevant because Item.__eq__ only compares .name and .player.
This commit is contained in:
Mysteryem
2025-10-05 14:07:12 +01:00
committed by GitHub
parent adb5a7d632
commit 8decde0370

View File

@@ -129,6 +129,10 @@ def fill_restrictive(multiworld: MultiWorld, base_state: CollectionState, locati
for i, location in enumerate(placements)) for i, location in enumerate(placements))
for (i, location, unsafe) in swap_attempts: for (i, location, unsafe) in swap_attempts:
placed_item = location.item placed_item = location.item
if item_to_place == placed_item:
# The number of allowed swaps is limited, so do not allow a swap of an item with a copy of
# itself.
continue
# Unplaceable items can sometimes be swapped infinitely. Limit the # Unplaceable items can sometimes be swapped infinitely. Limit the
# number of times we will swap an individual item to prevent this # number of times we will swap an individual item to prevent this
swap_count = swapped_items[placed_item.player, placed_item.name, unsafe] swap_count = swapped_items[placed_item.player, placed_item.name, unsafe]