Early bad loop detection.
This commit is contained in:
@@ -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])
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user