Fill: Priority locks when placing and does not swap. (#1099)
Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
parent
1aa3e431c8
commit
af0cfc5a38
121
Fill.py
121
Fill.py
|
@ -23,7 +23,8 @@ def sweep_from_pool(base_state: CollectionState, itempool: typing.Sequence[Item]
|
||||||
|
|
||||||
|
|
||||||
def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations: typing.List[Location],
|
def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations: typing.List[Location],
|
||||||
itempool: typing.List[Item], single_player_placement: bool = False, lock: bool = False) -> None:
|
itempool: typing.List[Item], single_player_placement: bool = False, lock: bool = False,
|
||||||
|
swap: bool = True, on_place: typing.Optional[typing.Callable[[Location], None]] = None) -> None:
|
||||||
unplaced_items: typing.List[Item] = []
|
unplaced_items: typing.List[Item] = []
|
||||||
placements: typing.List[Location] = []
|
placements: typing.List[Location] = []
|
||||||
|
|
||||||
|
@ -70,61 +71,66 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# we filled all reachable spots.
|
# we filled all reachable spots.
|
||||||
# try swapping this item with previously placed items
|
if swap:
|
||||||
for (i, location) in enumerate(placements):
|
# try swapping this item with previously placed items
|
||||||
placed_item = location.item
|
for (i, location) in enumerate(placements):
|
||||||
# Unplaceable items can sometimes be swapped infinitely. Limit the
|
placed_item = location.item
|
||||||
# number of times we will swap an individual item to prevent this
|
# Unplaceable items can sometimes be swapped infinitely. Limit the
|
||||||
swap_count = swapped_items[placed_item.player,
|
# number of times we will swap an individual item to prevent this
|
||||||
placed_item.name]
|
swap_count = swapped_items[placed_item.player,
|
||||||
if swap_count > 1:
|
placed_item.name]
|
||||||
|
if swap_count > 1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
location.item = None
|
||||||
|
placed_item.location = None
|
||||||
|
swap_state = sweep_from_pool(base_state, [placed_item])
|
||||||
|
# swap_state assumes we can collect placed item before item_to_place
|
||||||
|
if (not single_player_placement or location.player == item_to_place.player) \
|
||||||
|
and location.can_fill(swap_state, item_to_place, perform_access_check):
|
||||||
|
|
||||||
|
# Verify that placing this item won't reduce available locations, which could happen with rules
|
||||||
|
# that want to not have both items. Left in until removal is proven useful.
|
||||||
|
prev_state = swap_state.copy()
|
||||||
|
prev_loc_count = len(
|
||||||
|
world.get_reachable_locations(prev_state))
|
||||||
|
|
||||||
|
swap_state.collect(item_to_place, True)
|
||||||
|
new_loc_count = len(
|
||||||
|
world.get_reachable_locations(swap_state))
|
||||||
|
|
||||||
|
if new_loc_count >= prev_loc_count:
|
||||||
|
# Add this item to the existing placement, and
|
||||||
|
# add the old item to the back of the queue
|
||||||
|
spot_to_fill = placements.pop(i)
|
||||||
|
|
||||||
|
swap_count += 1
|
||||||
|
swapped_items[placed_item.player,
|
||||||
|
placed_item.name] = swap_count
|
||||||
|
|
||||||
|
reachable_items[placed_item.player].appendleft(
|
||||||
|
placed_item)
|
||||||
|
itempool.append(placed_item)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
# Item can't be placed here, restore original item
|
||||||
|
location.item = placed_item
|
||||||
|
placed_item.location = location
|
||||||
|
|
||||||
|
if spot_to_fill is None:
|
||||||
|
# Can't place this item, move on to the next
|
||||||
|
unplaced_items.append(item_to_place)
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
location.item = None
|
|
||||||
placed_item.location = None
|
|
||||||
swap_state = sweep_from_pool(base_state, [placed_item])
|
|
||||||
# swap_state assumes we can collect placed item before item_to_place
|
|
||||||
if (not single_player_placement or location.player == item_to_place.player) \
|
|
||||||
and location.can_fill(swap_state, item_to_place, perform_access_check):
|
|
||||||
|
|
||||||
# Verify that placing this item won't reduce available locations, which could happen with rules
|
|
||||||
# that want to not have both items. Left in until removal is proven useful.
|
|
||||||
prev_state = swap_state.copy()
|
|
||||||
prev_loc_count = len(
|
|
||||||
world.get_reachable_locations(prev_state))
|
|
||||||
|
|
||||||
swap_state.collect(item_to_place, True)
|
|
||||||
new_loc_count = len(
|
|
||||||
world.get_reachable_locations(swap_state))
|
|
||||||
|
|
||||||
if new_loc_count >= prev_loc_count:
|
|
||||||
# Add this item to the existing placement, and
|
|
||||||
# add the old item to the back of the queue
|
|
||||||
spot_to_fill = placements.pop(i)
|
|
||||||
|
|
||||||
swap_count += 1
|
|
||||||
swapped_items[placed_item.player,
|
|
||||||
placed_item.name] = swap_count
|
|
||||||
|
|
||||||
reachable_items[placed_item.player].appendleft(
|
|
||||||
placed_item)
|
|
||||||
itempool.append(placed_item)
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
# Item can't be placed here, restore original item
|
|
||||||
location.item = placed_item
|
|
||||||
placed_item.location = location
|
|
||||||
|
|
||||||
if spot_to_fill is None:
|
|
||||||
# Can't place this item, move on to the next
|
|
||||||
unplaced_items.append(item_to_place)
|
unplaced_items.append(item_to_place)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
world.push_item(spot_to_fill, item_to_place, False)
|
world.push_item(spot_to_fill, item_to_place, False)
|
||||||
spot_to_fill.locked = lock
|
spot_to_fill.locked = lock
|
||||||
placements.append(spot_to_fill)
|
placements.append(spot_to_fill)
|
||||||
spot_to_fill.event = item_to_place.advancement
|
spot_to_fill.event = item_to_place.advancement
|
||||||
|
if on_place:
|
||||||
|
on_place(spot_to_fill)
|
||||||
|
|
||||||
if len(unplaced_items) > 0 and len(locations) > 0:
|
if len(unplaced_items) > 0 and len(locations) > 0:
|
||||||
# There are leftover unplaceable items and locations that won't accept them
|
# There are leftover unplaceable items and locations that won't accept them
|
||||||
|
@ -272,19 +278,26 @@ def distribute_items_restrictive(world: MultiWorld) -> None:
|
||||||
defaultlocations = locations[LocationProgressType.DEFAULT]
|
defaultlocations = locations[LocationProgressType.DEFAULT]
|
||||||
excludedlocations = locations[LocationProgressType.EXCLUDED]
|
excludedlocations = locations[LocationProgressType.EXCLUDED]
|
||||||
|
|
||||||
prioritylocations_lock = prioritylocations.copy()
|
# can't lock due to accessibility corrections touching things, so we remember which ones got placed and lock later
|
||||||
|
lock_later = []
|
||||||
|
|
||||||
fill_restrictive(world, world.state, prioritylocations, progitempool)
|
def mark_for_locking(location: Location):
|
||||||
|
nonlocal lock_later
|
||||||
|
lock_later.append(location)
|
||||||
|
|
||||||
|
# "priority fill"
|
||||||
|
fill_restrictive(world, world.state, prioritylocations, progitempool, swap=False, on_place=mark_for_locking)
|
||||||
accessibility_corrections(world, world.state, prioritylocations, progitempool)
|
accessibility_corrections(world, world.state, prioritylocations, progitempool)
|
||||||
|
|
||||||
for location in prioritylocations_lock:
|
for location in lock_later:
|
||||||
if location.item:
|
location.locked = True
|
||||||
location.locked = True
|
del mark_for_locking, lock_later
|
||||||
|
|
||||||
if prioritylocations:
|
if prioritylocations:
|
||||||
defaultlocations = prioritylocations + defaultlocations
|
defaultlocations = prioritylocations + defaultlocations
|
||||||
|
|
||||||
if progitempool:
|
if progitempool:
|
||||||
|
# "progression fill"
|
||||||
fill_restrictive(world, world.state, defaultlocations, progitempool)
|
fill_restrictive(world, world.state, defaultlocations, progitempool)
|
||||||
if progitempool:
|
if progitempool:
|
||||||
raise FillError(
|
raise FillError(
|
||||||
|
|
Loading…
Reference in New Issue