diff --git a/BaseClasses.py b/BaseClasses.py index 9bed8841..a7a761db 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -865,11 +865,14 @@ class Direction(Enum): class Polarity: - def __init__(self, vector): - self.vector = vector + def __init__(self): + self.vector = [0, 0, 0] + + def __len__(self): + return len(self.vector) def __add__(self, other): - result = Polarity([0]*len(self.vector)) + result = Polarity() for i in range(len(self.vector)): result.vector[i] = pol_add[pol_idx_2[i]](self.vector[i], other.vector[i]) return result @@ -1037,7 +1040,7 @@ class Sector(object): # todo: make these lazy init? - when do you invalidate them def polarity(self): - pol = Polarity([0, 0, 0]) + pol = Polarity() for door in self.outstanding_doors: idx, inc = pol_idx[door.direction] pol.vector[idx] = pol_inc[inc](pol.vector[idx]) diff --git a/DoorShuffle.py b/DoorShuffle.py index 4d662c60..ea8fa989 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -4,7 +4,7 @@ import logging import operator as op 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 dungeon_regions, region_starts, split_region_starts from Regions import key_only_locations, dungeon_events @@ -430,7 +430,7 @@ def experiment(world, player): dungeon_layouts = [] 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 dungeon_layouts.append((ds, entrance_list)) @@ -537,7 +537,7 @@ def sum_vector(sector_list, func): def is_polarity_neutral(sector_list): - pol = Polarity([0, 0, 0]) + pol = Polarity() for sector in sector_list: pol += sector.polarity() 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: raise Exception('Rejected last option due to likely improper loops...') 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 if len(available_sectors) != 1: 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 elif not are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, available_sectors): 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... return False 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 +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): start_regions = convert_regions(entrances, world, player) # 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) valid, bad_region = check_if_regions_visited(state, check_paths) 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):