Significant performance upgrades in convoluted seeds.
This commit is contained in:
parent
2f10495248
commit
5207ccd8fd
|
@ -105,7 +105,12 @@ class World(object):
|
||||||
temp_state = self.state.copy()
|
temp_state = self.state.copy()
|
||||||
temp_state._clear_cache()
|
temp_state._clear_cache()
|
||||||
temp_state.collect(item)
|
temp_state.collect(item)
|
||||||
return len(self.get_placeable_locations()) < len(self.get_placeable_locations(temp_state))
|
|
||||||
|
for location in self.get_unfilled_locations():
|
||||||
|
if temp_state.can_reach(location) and not self.state.can_reach(location):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def can_beat_game(self):
|
def can_beat_game(self):
|
||||||
prog_locations = [location for location in self.get_locations() if location.item is not None and location.item.advancement]
|
prog_locations = [location for location in self.get_locations() if location.item is not None and location.item.advancement]
|
||||||
|
@ -137,44 +142,32 @@ class CollectionState(object):
|
||||||
self.prog_items = []
|
self.prog_items = []
|
||||||
self.world = parent
|
self.world = parent
|
||||||
self.has_everything = has_everything
|
self.has_everything = has_everything
|
||||||
self.changed = False
|
|
||||||
self.region_cache = {}
|
self.region_cache = {}
|
||||||
self.location_cache = {}
|
self.location_cache = {}
|
||||||
self.entrance_cache = {}
|
self.entrance_cache = {}
|
||||||
# use to avoid cycle dependencies during resolution
|
self.recursion_count = 0
|
||||||
self.recursion_cache = []
|
|
||||||
|
|
||||||
def _clear_cache(self):
|
def _clear_cache(self):
|
||||||
# we only need to invalidate results which were False, places we could reach before we can still reach after adding more items
|
# we only need to invalidate results which were False, places we could reach before we can still reach after adding more items
|
||||||
self.region_cache = {k: v for k, v in self.region_cache.items() if v}
|
self.region_cache = {k: v for k, v in self.region_cache.items() if v}
|
||||||
self.location_cache = {k: v for k, v in self.location_cache.items() if v}
|
self.location_cache = {k: v for k, v in self.location_cache.items() if v}
|
||||||
self.entrance_cache = {k: v for k, v in self.entrance_cache.items() if v}
|
self.entrance_cache = {k: v for k, v in self.entrance_cache.items() if v}
|
||||||
self.recursion_cache = []
|
|
||||||
self.changed = False
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
ret = CollectionState(self.world, self.has_everything)
|
ret = CollectionState(self.world, self.has_everything)
|
||||||
ret.prog_items = copy.copy(self.prog_items)
|
ret.prog_items = copy.copy(self.prog_items)
|
||||||
ret.changed = self.changed
|
|
||||||
ret.region_cache = copy.copy(self.region_cache)
|
ret.region_cache = copy.copy(self.region_cache)
|
||||||
ret.location_cache = copy.copy(self.location_cache)
|
ret.location_cache = copy.copy(self.location_cache)
|
||||||
ret.entrance_cache = copy.copy(self.entrance_cache)
|
ret.entrance_cache = copy.copy(self.entrance_cache)
|
||||||
ret.recursion_cache = copy.copy(self.recursion_cache)
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def can_reach(self, spot, resolution_hint=None):
|
def can_reach(self, spot, resolution_hint=None):
|
||||||
if self.changed:
|
|
||||||
self._clear_cache()
|
|
||||||
|
|
||||||
if spot in self.recursion_cache:
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
spot_type = spot.spot_type
|
spot_type = spot.spot_type
|
||||||
if spot_type == 'Region':
|
if spot_type == 'Location':
|
||||||
correct_cache = self.region_cache
|
|
||||||
elif spot_type == 'Location':
|
|
||||||
correct_cache = self.location_cache
|
correct_cache = self.location_cache
|
||||||
|
elif spot_type == 'Region':
|
||||||
|
correct_cache = self.region_cache
|
||||||
elif spot_type == 'Entrance':
|
elif spot_type == 'Entrance':
|
||||||
correct_cache = self.entrance_cache
|
correct_cache = self.entrance_cache
|
||||||
else:
|
else:
|
||||||
|
@ -192,15 +185,20 @@ class CollectionState(object):
|
||||||
spot = self.world.get_region(spot)
|
spot = self.world.get_region(spot)
|
||||||
correct_cache = self.region_cache
|
correct_cache = self.region_cache
|
||||||
|
|
||||||
|
if spot.recursion_count > 0:
|
||||||
|
return False
|
||||||
|
|
||||||
if spot not in correct_cache:
|
if spot not in correct_cache:
|
||||||
# for the purpose of evaluating results, recursion is resolved by always denying recursive access (as that ia what we are trying to figure out right now in the first place
|
# for the purpose of evaluating results, recursion is resolved by always denying recursive access (as that ia what we are trying to figure out right now in the first place
|
||||||
self.recursion_cache.append(spot)
|
spot.recursion_count += 1
|
||||||
|
self.recursion_count += 1
|
||||||
can_reach = spot.can_reach(self)
|
can_reach = spot.can_reach(self)
|
||||||
self.recursion_cache.pop()
|
spot.recursion_count -= 1
|
||||||
|
self.recursion_count -= 1
|
||||||
|
|
||||||
# we only store qualified false results (i.e. ones not inside a hypothetical)
|
# we only store qualified false results (i.e. ones not inside a hypothetical)
|
||||||
if not can_reach:
|
if not can_reach:
|
||||||
if not self.recursion_cache:
|
if self.recursion_count == 0:
|
||||||
correct_cache[spot] = can_reach
|
correct_cache[spot] = can_reach
|
||||||
else:
|
else:
|
||||||
correct_cache[spot] = can_reach
|
correct_cache[spot] = can_reach
|
||||||
|
@ -221,10 +219,25 @@ class CollectionState(object):
|
||||||
self.world._item_cache[item] = cached
|
self.world._item_cache[item] = cached
|
||||||
else:
|
else:
|
||||||
# this should probably not happen, wonky item distribution?
|
# this should probably not happen, wonky item distribution?
|
||||||
return len([location for location in candidates if self.can_reach(location)]) >= 1
|
return self._can_reach_n(self.world.find_items(item), 1)
|
||||||
return self.can_reach(cached)
|
return self.can_reach(cached)
|
||||||
|
|
||||||
return len([location for location in self.world.find_items(item) if self.can_reach(location)]) >= count
|
return self._can_reach_n(self.world.find_items(item), count)
|
||||||
|
|
||||||
|
def _can_reach_n(self, candidates, count):
|
||||||
|
maxfail = len(candidates) - count
|
||||||
|
fail = 0
|
||||||
|
success = 0
|
||||||
|
for candidate in candidates:
|
||||||
|
if self.can_reach(candidate):
|
||||||
|
success += 1
|
||||||
|
else:
|
||||||
|
fail += 1
|
||||||
|
if fail > maxfail:
|
||||||
|
return False
|
||||||
|
if success >= count:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def has(self, item):
|
def has(self, item):
|
||||||
if self.has_everything:
|
if self.has_everything:
|
||||||
|
@ -266,36 +279,39 @@ class CollectionState(object):
|
||||||
return self.has(self.world.required_medallions[1])
|
return self.has(self.world.required_medallions[1])
|
||||||
|
|
||||||
def collect(self, item):
|
def collect(self, item):
|
||||||
|
changed = False
|
||||||
if item.name.startswith('Progressive '):
|
if item.name.startswith('Progressive '):
|
||||||
if 'Sword' in item.name:
|
if 'Sword' in item.name:
|
||||||
if self.has('Golden Sword'):
|
if self.has('Golden Sword'):
|
||||||
return
|
pass
|
||||||
elif self.has('Tempered Sword'):
|
elif self.has('Tempered Sword'):
|
||||||
self.prog_items.append('Golden Sword')
|
self.prog_items.append('Golden Sword')
|
||||||
self.changed = True
|
changed = True
|
||||||
elif self.has('Master Sword'):
|
elif self.has('Master Sword'):
|
||||||
self.prog_items.append('Tempered Sword')
|
self.prog_items.append('Tempered Sword')
|
||||||
self.changed = True
|
changed = True
|
||||||
elif self.has('Fighter Sword'):
|
elif self.has('Fighter Sword'):
|
||||||
self.prog_items.append('Master Sword')
|
self.prog_items.append('Master Sword')
|
||||||
self.changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
self.prog_items.append('Fighter Sword')
|
self.prog_items.append('Fighter Sword')
|
||||||
self.changed = True
|
changed = True
|
||||||
elif 'Glove' in item.name:
|
elif 'Glove' in item.name:
|
||||||
if self.has('Titans Mitts'):
|
if self.has('Titans Mitts'):
|
||||||
return
|
pass
|
||||||
elif self.has('Power Glove'):
|
elif self.has('Power Glove'):
|
||||||
self.prog_items.append('Titans Mitts')
|
self.prog_items.append('Titans Mitts')
|
||||||
self.changed = True
|
changed = True
|
||||||
else:
|
else:
|
||||||
self.prog_items.append('Power Glove')
|
self.prog_items.append('Power Glove')
|
||||||
self.changed = True
|
changed = True
|
||||||
return
|
|
||||||
|
|
||||||
if item.advancement:
|
elif item.advancement:
|
||||||
self.prog_items.append(item.name)
|
self.prog_items.append(item.name)
|
||||||
self.changed = True
|
changed = True
|
||||||
|
|
||||||
|
if changed:
|
||||||
|
self._clear_cache()
|
||||||
|
|
||||||
def remove(self, item):
|
def remove(self, item):
|
||||||
if item.advancement:
|
if item.advancement:
|
||||||
|
@ -330,8 +346,7 @@ class CollectionState(object):
|
||||||
self.region_cache = {}
|
self.region_cache = {}
|
||||||
self.location_cache = {}
|
self.location_cache = {}
|
||||||
self.entrance_cache = {}
|
self.entrance_cache = {}
|
||||||
self.recursion_cache = []
|
self.recursion_count = 0
|
||||||
self.changed = False
|
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
if item.startswith('can_reach_'):
|
if item.startswith('can_reach_'):
|
||||||
|
@ -351,6 +366,7 @@ class Region(object):
|
||||||
self.locations = []
|
self.locations = []
|
||||||
self.spot_type = 'Region'
|
self.spot_type = 'Region'
|
||||||
self.hint_text = 'Hyrule'
|
self.hint_text = 'Hyrule'
|
||||||
|
self.recursion_count = 0
|
||||||
|
|
||||||
def can_reach(self, state):
|
def can_reach(self, state):
|
||||||
for entrance in self.entrances:
|
for entrance in self.entrances:
|
||||||
|
@ -373,6 +389,7 @@ class Entrance(object):
|
||||||
self.connected_region = None
|
self.connected_region = None
|
||||||
self.target = None
|
self.target = None
|
||||||
self.spot_type = 'Entrance'
|
self.spot_type = 'Entrance'
|
||||||
|
self.recursion_count = 0
|
||||||
|
|
||||||
def access_rule(self, state):
|
def access_rule(self, state):
|
||||||
return True
|
return True
|
||||||
|
@ -405,6 +422,7 @@ class Location(object):
|
||||||
self.address = address
|
self.address = address
|
||||||
self.spot_type = 'Location'
|
self.spot_type = 'Location'
|
||||||
self.hint_text = hint_text if hint_text is not None else 'Hyrule'
|
self.hint_text = hint_text if hint_text is not None else 'Hyrule'
|
||||||
|
self.recursion_count = 0
|
||||||
|
|
||||||
def access_rule(self, state):
|
def access_rule(self, state):
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in New Issue