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

72
Fill.py
View File

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

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: