Speed up restrictive_fill a bit.

This also changes behaviour slightly; it used to fill beatable only players' items first, now it shuffles it all together. It is not documented why this was done, so hopefully this doesn't undo something intentional.
This commit is contained in:
Fabian Dill 2021-03-18 17:27:31 +01:00
parent ae72fa1561
commit bbe51c4cc7
3 changed files with 38 additions and 41 deletions

32
Fill.py
View File

@ -24,48 +24,46 @@ def fill_restrictive(world, base_state: CollectionState, locations, itempool, si
unplaced_items = [] unplaced_items = []
placements = [] placements = []
no_access_checks = {}
reachable_items = {} reachable_items = {}
for item in itempool: for item in itempool:
if world.accessibility[item.player] == 'none':
no_access_checks.setdefault(item.player, []).append(item)
else:
reachable_items.setdefault(item.player, []).append(item) reachable_items.setdefault(item.player, []).append(item)
for player_items in [no_access_checks, reachable_items]: while any(reachable_items.values()) and locations:
while any(player_items.values()) and locations: items_to_place = [items.pop() for items in reachable_items.values() if items] # grab one item per player
items_to_place = [[itempool.remove(items[-1]), items.pop()][-1] for items in player_items.values() if items] for item in items_to_place:
itempool.remove(item)
maximum_exploration_state = sweep_from_pool() maximum_exploration_state = sweep_from_pool()
has_beaten_game = world.has_beaten_game(maximum_exploration_state) has_beaten_game = world.has_beaten_game(maximum_exploration_state)
for item_to_place in items_to_place: for item_to_place in items_to_place:
perform_access_check = True
if world.accessibility[item_to_place.player] == 'none': if world.accessibility[item_to_place.player] == 'none':
perform_access_check = not world.has_beaten_game(maximum_exploration_state, perform_access_check = not world.has_beaten_game(maximum_exploration_state,
item_to_place.player) if single_player_placement else not has_beaten_game item_to_place.player) if single_player_placement else not has_beaten_game
for location in locations: else:
perform_access_check = True
for i, location in enumerate(locations):
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(maximum_exploration_state, item_to_place, perform_access_check): and location.can_fill(maximum_exploration_state, item_to_place, perform_access_check):
spot_to_fill = location spot_to_fill = locations.pop(i) # poping by index is faster than removing by content,
# skipping a scan for the element
break break
else: else:
# fill in name of world for item
item_to_place.world = world
# we filled all reachable spots. Maybe the game can be beaten anyway? # we filled all reachable spots. Maybe the game can be beaten anyway?
unplaced_items.insert(0, item_to_place) unplaced_items.append(item_to_place)
if world.accessibility[item_to_place.player] != 'none' and world.can_beat_game(): if world.accessibility[item_to_place.player] != 'none' and world.can_beat_game():
logging.warning( logging.warning(
f'Not all items placed. Game beatable anyway. (Could not place {item_to_place})') f'Not all items placed. Game beatable anyway. (Could not place {item_to_place})')
continue continue
# fill in name of world for item
item_to_place.world = world
raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. ' raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. '
f'Already placed {len(placements)}: {", ".join(str(place) for place in placements)}') f'Already placed {len(placements)}: {", ".join(str(place) for place in placements)}')
world.push_item(spot_to_fill, item_to_place, False) world.push_item(spot_to_fill, item_to_place, False)
if lock: spot_to_fill.locked = lock
spot_to_fill.locked = True
locations.remove(spot_to_fill)
placements.append(spot_to_fill) placements.append(spot_to_fill)
spot_to_fill.event = True spot_to_fill.event = True

2
Gui.py
View File

@ -404,7 +404,7 @@ def guiMain(args=None):
guiargs.red_clock_time = timerRedVar.get() guiargs.red_clock_time = timerRedVar.get()
guiargs.blue_clock_time = timerBlueVar.get() guiargs.blue_clock_time = timerBlueVar.get()
guiargs.green_clock_time = timerGreenVar.get() guiargs.green_clock_time = timerGreenVar.get()
guiargs.skip_progression_balancing = not balancingVar.get() guiargs.progression_balancing = balancingVar.get()
if guiargs.timer == "none": if guiargs.timer == "none":
guiargs.timer = False guiargs.timer = False
guiargs.dungeon_counters = dungeonCounterVar.get() guiargs.dungeon_counters = dungeonCounterVar.get()

View File

@ -526,9 +526,8 @@ def fill_prizes(world, attempts=15):
empty_crystal_locations = [loc for loc in crystal_locations if not loc.item] empty_crystal_locations = [loc for loc in crystal_locations if not loc.item]
for attempt in range(attempts): for attempt in range(attempts):
try: try:
prizepool = list(unplaced_prizes) prizepool = unplaced_prizes.copy()
prize_locs = list(empty_crystal_locations) prize_locs = empty_crystal_locations.copy()
world.random.shuffle(prizepool)
world.random.shuffle(prize_locs) world.random.shuffle(prize_locs)
fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True) fill_restrictive(world, all_state, prize_locs, prizepool, True, lock=True)
except FillError as e: except FillError as e: