Optimize fulfills_accessibility by pruning to relevant locations
This commit is contained in:
		
							parent
							
								
									32c5ee53e5
								
							
						
					
					
						commit
						c0cdeef67a
					
				| 
						 | 
				
			
			@ -416,7 +416,7 @@ class World(object):
 | 
			
		|||
        else:
 | 
			
		||||
            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 self.has_beaten_game(starting_state):
 | 
			
		||||
                return True
 | 
			
		||||
| 
						 | 
				
			
			@ -448,42 +448,38 @@ class World(object):
 | 
			
		|||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def fulfills_accessibility(self):
 | 
			
		||||
        state = CollectionState(self)
 | 
			
		||||
        locations = {location for location in self.get_locations() if location.item}
 | 
			
		||||
        beatable_players = set()
 | 
			
		||||
        items_players = set()
 | 
			
		||||
        locations_players = set()
 | 
			
		||||
        for player in self.player_ids:
 | 
			
		||||
            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}")
 | 
			
		||||
    def fulfills_accessibility(self, state: Optional[CollectionState] = None):
 | 
			
		||||
        """Check if accessibility rules are fulfilled with current or supplied state."""
 | 
			
		||||
        if not state:
 | 
			
		||||
            state = CollectionState(self)
 | 
			
		||||
        players = {}
 | 
			
		||||
        for player, access in self.accessibility.items():
 | 
			
		||||
            players.setdefault(access, set()).add(player)
 | 
			
		||||
 | 
			
		||||
        beatable_fulfilled = False
 | 
			
		||||
 | 
			
		||||
        def location_conditition(location : Location):
 | 
			
		||||
            """Determine if this location has to be accessible"""
 | 
			
		||||
            if location.player in locations_players:
 | 
			
		||||
                return True
 | 
			
		||||
            elif location.player in items_players:
 | 
			
		||||
                return location.item.advancement or location.event
 | 
			
		||||
            """Determine if this location has to be accessible, location is already filtered by location_relevant"""
 | 
			
		||||
            if location.player in players["none"]:
 | 
			
		||||
                return False
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
        def all_done():
 | 
			
		||||
            """Check if all access rules are fulfilled"""
 | 
			
		||||
            if beatable_fulfilled:
 | 
			
		||||
                for location in locations:
 | 
			
		||||
                    if location_conditition(location):
 | 
			
		||||
                        return False
 | 
			
		||||
                if any(location_conditition(location) for location in locations):
 | 
			
		||||
                    return False  # still locations required to be collected
 | 
			
		||||
                return True
 | 
			
		||||
 | 
			
		||||
        locations = {location for location in self.get_locations() if location_relevant(location)}
 | 
			
		||||
 | 
			
		||||
        while locations:
 | 
			
		||||
            sphere = set()
 | 
			
		||||
            for location in locations:
 | 
			
		||||
| 
						 | 
				
			
			@ -507,6 +503,7 @@ class World(object):
 | 
			
		|||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CollectionState(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, parent: World):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue