Optimize fulfills_accessibility by pruning to relevant locations

This commit is contained in:
Fabian Dill 2021-01-13 14:27:17 +01:00
parent 32c5ee53e5
commit c0cdeef67a
1 changed files with 22 additions and 25 deletions

View File

@ -416,7 +416,7 @@ class World(object):
else: else:
return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1))) return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1)))
def can_beat_game(self, starting_state=None): def can_beat_game(self, starting_state : Optional[CollectionState]=None):
if starting_state: if starting_state:
if self.has_beaten_game(starting_state): if self.has_beaten_game(starting_state):
return True return True
@ -448,42 +448,38 @@ class World(object):
return False return False
def fulfills_accessibility(self): def fulfills_accessibility(self, state: Optional[CollectionState] = None):
state = CollectionState(self) """Check if accessibility rules are fulfilled with current or supplied state."""
locations = {location for location in self.get_locations() if location.item} if not state:
beatable_players = set() state = CollectionState(self)
items_players = set() players = {}
locations_players = set() for player, access in self.accessibility.items():
for player in self.player_ids: players.setdefault(access, set()).add(player)
access = self.accessibility[player]
if access == "none":
beatable_players.add(player)
elif access == "items":
items_players.add(player)
elif access == "locations":
locations_players.add(player)
else:
raise Exception(f"unknown access rule {access} for player {player}")
beatable_fulfilled = False beatable_fulfilled = False
def location_conditition(location : Location): def location_conditition(location : Location):
"""Determine if this location has to be accessible""" """Determine if this location has to be accessible, location is already filtered by location_relevant"""
if location.player in locations_players: if location.player in players["none"]:
return True return False
elif location.player in items_players: return True
return location.item.advancement or location.event
def location_relevant(location : Location):
"""Determine if this location is relevant to sweep."""
if location.player in players["locations"] or location.event or \
(location.item and location.item.advancement):
return True
return False return False
def all_done(): def all_done():
"""Check if all access rules are fulfilled""" """Check if all access rules are fulfilled"""
if beatable_fulfilled: if beatable_fulfilled:
for location in locations: if any(location_conditition(location) for location in locations):
if location_conditition(location): return False # still locations required to be collected
return False
return True return True
locations = {location for location in self.get_locations() if location_relevant(location)}
while locations: while locations:
sphere = set() sphere = set()
for location in locations: for location in locations:
@ -507,6 +503,7 @@ class World(object):
return False return False
class CollectionState(object): class CollectionState(object):
def __init__(self, parent: World): def __init__(self, parent: World):