Early bad loop detection.

This commit is contained in:
aerinon
2019-10-18 11:56:56 -06:00
parent beb15951a0
commit c090bd7003
2 changed files with 37 additions and 9 deletions

View File

@@ -865,11 +865,14 @@ class Direction(Enum):
class Polarity: class Polarity:
def __init__(self, vector): def __init__(self):
self.vector = vector self.vector = [0, 0, 0]
def __len__(self):
return len(self.vector)
def __add__(self, other): def __add__(self, other):
result = Polarity([0]*len(self.vector)) result = Polarity()
for i in range(len(self.vector)): for i in range(len(self.vector)):
result.vector[i] = pol_add[pol_idx_2[i]](self.vector[i], other.vector[i]) result.vector[i] = pol_add[pol_idx_2[i]](self.vector[i], other.vector[i])
return result return result
@@ -1037,7 +1040,7 @@ class Sector(object):
# todo: make these lazy init? - when do you invalidate them # todo: make these lazy init? - when do you invalidate them
def polarity(self): def polarity(self):
pol = Polarity([0, 0, 0]) pol = Polarity()
for door in self.outstanding_doors: for door in self.outstanding_doors:
idx, inc = pol_idx[door.direction] idx, inc = pol_idx[door.direction]
pol.vector[idx] = pol_inc[inc](pol.vector[idx]) pol.vector[idx] = pol_inc[inc](pol.vector[idx])

View File

@@ -4,7 +4,7 @@ import logging
import operator as op import operator as op
from functools import reduce from functools import reduce
from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier, Polarity, pol_idx from BaseClasses import RegionType, Door, DoorType, Direction, Sector, CrystalBarrier, Polarity, pol_idx, pol_inc
from Dungeons import hyrule_castle_regions, eastern_regions, desert_regions, hera_regions, tower_regions, pod_regions from Dungeons import hyrule_castle_regions, eastern_regions, desert_regions, hera_regions, tower_regions, pod_regions
from Dungeons import dungeon_regions, region_starts, split_region_starts from Dungeons import dungeon_regions, region_starts, split_region_starts
from Regions import key_only_locations, dungeon_events from Regions import key_only_locations, dungeon_events
@@ -430,7 +430,7 @@ def experiment(world, player):
dungeon_layouts = [] dungeon_layouts = []
for key, sector_list, entrance_list in dungeon_sectors: for key, sector_list, entrance_list in dungeon_sectors:
ds = shuffle_dungeon_no_repeats(world, player, sector_list, entrance_list) ds = shuffle_dungeon_no_repeats_new(world, player, sector_list, entrance_list)
ds.name = key ds.name = key
dungeon_layouts.append((ds, entrance_list)) dungeon_layouts.append((ds, entrance_list))
@@ -537,7 +537,7 @@ def sum_vector(sector_list, func):
def is_polarity_neutral(sector_list): def is_polarity_neutral(sector_list):
pol = Polarity([0, 0, 0]) pol = Polarity()
for sector in sector_list: for sector in sector_list:
pol += sector.polarity() pol += sector.polarity()
return pol.is_neutral() return pol.is_neutral()
@@ -909,7 +909,7 @@ def shuffle_dungeon_no_repeats_new(world, player, available_sectors, entrance_re
if len(state.unattached_doors) <= 2: if len(state.unattached_doors) <= 2:
raise Exception('Rejected last option due to likely improper loops...') raise Exception('Rejected last option due to likely improper loops...')
else: else:
raise Exception('Nothing is apparently compatible with %s', door.name) raise Exception('Nothing is apparently compatible with %s' % door.name)
# Check that we used everything, we failed otherwise # Check that we used everything, we failed otherwise
if len(available_sectors) != 1: if len(available_sectors) != 1:
logger.warning('Failed to add all regions/doors to dungeon, generation will likely fail.') logger.warning('Failed to add all regions/doors to dungeon, generation will likely fail.')
@@ -1060,6 +1060,8 @@ def is_valid(door_a, door_b, sector_a, sector_b, available_sectors):
return True return True
elif not are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, available_sectors): elif not are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, available_sectors):
return False return False
elif early_loop_dies(door_a, sector_a, sector_b, available_sectors):
return False
elif door_a.blocked and door_b.blocked: # I can't see this going well unless we are in loop generation... elif door_a.blocked and door_b.blocked: # I can't see this going well unless we are in loop generation...
return False return False
elif not door_a.blocked and not door_b.blocked and sector_a != sector_b: elif not door_a.blocked and not door_b.blocked and sector_a != sector_b:
@@ -1115,6 +1117,29 @@ def are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, avai
return True return True
def early_loop_dies(door_a, sector_a, sector_b, available_sectors):
other_sectors = list(available_sectors)
other_sectors.remove(sector_a)
if sector_a != sector_b:
other_sectors.remove(sector_b)
current_pol = sector_a.polarity() + sector_b.polarity()
current_mag = sum_vector([sector_a, sector_b], lambda x: x.magnitude())
else:
current_pol = sector_a.polarity()
current_mag = sector_a.magnitude()
idx, inc = pol_idx[door_a.direction]
current_pol.vector[idx] = pol_inc[inc](current_pol[idx])
current_mag[idx] -= 1
other_mag = sum_vector(other_sectors, lambda x: x.magnitude())
# other_polarity = reduce(lambda x, y: x+y, map(lambda x: x.polarity(), other_sectors))
ttl_magnitude = 0
for i in range(len(current_mag)):
ttl_magnitude += 0 if current_pol[i] == 0 and other_mag[i] == 0 else current_mag[i]
if ttl_magnitude == 0:
return True
return False
def shuffle_key_doors(dungeon_sector, entrances, world, player): def shuffle_key_doors(dungeon_sector, entrances, world, player):
start_regions = convert_regions(entrances, world, player) start_regions = convert_regions(entrances, world, player)
# count number of key doors - this could be a table? # count number of key doors - this could be a table?
@@ -1494,7 +1519,7 @@ def check_required_paths(paths, world, player):
explore_state(state, world, player) explore_state(state, world, player)
valid, bad_region = check_if_regions_visited(state, check_paths) valid, bad_region = check_if_regions_visited(state, check_paths)
if not valid: if not valid:
raise Exception('% cannot reach %', dungeon_name, bad_region.name) raise Exception('%s cannot reach %s' % (dungeon_name, bad_region.name))
def explore_state(state, world, player): def explore_state(state, world, player):