Don't allow items to swap infinitly

This commit is contained in:
Brad Humphrey 2021-12-20 18:14:50 -07:00 committed by Fabian Dill
parent 6a34fe5184
commit d719eb356f
2 changed files with 29 additions and 3 deletions

11
Fill.py
View File

@ -2,6 +2,8 @@ import logging
import typing import typing
import collections import collections
import itertools import itertools
from collections import Counter
from BaseClasses import CollectionState, Location, MultiWorld, Item from BaseClasses import CollectionState, Location, MultiWorld, Item
from worlds.generic import PlandoItem from worlds.generic import PlandoItem
@ -25,6 +27,7 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations,
unplaced_items = [] unplaced_items = []
placements = [] placements = []
swapped_items: Counter[Item] = Counter()
reachable_items = {} reachable_items = {}
for item in itempool: for item in itempool:
reachable_items.setdefault(item.player, []).append(item) reachable_items.setdefault(item.player, []).append(item)
@ -59,15 +62,19 @@ def fill_restrictive(world: MultiWorld, base_state: CollectionState, locations,
# try swaping this item with previously placed items # try swaping this item with previously placed items
for(i, location) in enumerate(placements): for(i, location) in enumerate(placements):
placed_item = location.item placed_item = location.item
if swapped_items[placed_item.name] > 0:
continue
location.item = None location.item = None
placed_item.location = None placed_item.location = None
swap_state = sweep_from_pool(base_state, itempool) swap_state = sweep_from_pool(base_state, itempool)
if (not single_player_placement or location.player == item_to_place.player) \ if (not single_player_placement or location.player == item_to_place.player) \
and location.can_fill(swap_state, item_to_place, perform_access_check): and location.can_fill(swap_state, item_to_place, perform_access_check):
# Add this item to the exisiting placement, and # Add this item to the exisiting placement, and
# add the old item to the back of the queue # add the old item to the back of the queue
spot_to_fill = placements.pop(i) spot_to_fill = placements.pop(i)
reachable_items.setdefault(placed_item.player, []).append(placed_item) swapped_items[placed_item.name] += 1
reachable_items.setdefault(
placed_item.player, []).append(placed_item)
itempool.append(placed_item) itempool.append(placed_item)
break break
else: else:

View File

@ -149,4 +149,23 @@ class TestBase(unittest.TestCase):
set_rule(loc2, lambda state: state.has(item1.name, player1_id)) set_rule(loc2, lambda state: state.has(item1.name, player1_id))
set_rule(loc0, lambda state: state.has(item2.name, player1_id)) set_rule(loc0, lambda state: state.has(item2.name, player1_id))
with pytest.raises(FillError): with pytest.raises(FillError):
fill_restrictive(multi_world, multi_world.state, locations, items) fill_restrictive(multi_world, multi_world.state, locations, items)
def test_competing_fill_restrictive(self):
multi_world = generate_multi_world()
player1_id = 1
player1_menu = multi_world.get_region("Menu", player1_id)
locations = generate_locations(2, player1_id, None, player1_menu)
items = generate_items(2, player1_id, True)
item0 = items[0]
item1 = items[1]
loc1 = locations[1]
multi_world.completion_condition[player1_id] = lambda state: state.has(
item0.name, player1_id) and state.has(item0.name, player1_id) and state.has(item1.name, player1_id)
set_rule(loc1, lambda state: state.has(item0.name, player1_id)
and state.has(item1.name, player1_id))
with pytest.raises(FillError):
fill_restrictive(multi_world, multi_world.state, locations, items)