diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 9f61361f..36c87738 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -1540,9 +1540,30 @@ def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger def polarity_step_3(dungeon_map, polarized_sectors, global_pole, logger): + # step 3a: fix odd builders + odd_builders = [x for x in dungeon_map.values() if sum_polarity(x.sectors).charge() % 2 != 0] + random.shuffle(odd_builders) + for builder in odd_builders: + while sum_polarity(builder.sectors).charge() % 2 != 0: + odd_candidates = find_odd_sectors_ranked_by_charge(builder, polarized_sectors) + sub_candidates, valid, best_charge, candidate = [], False, min(list(odd_candidates.keys())), None + while not valid: + if len(sub_candidates) == 0: + if len(odd_candidates) == 0: + raise NeutralizingException('Unable to fix dungeon parity: %s' % builder.name) + while best_charge not in odd_candidates.keys(): + best_charge += 2 + sub_candidates = odd_candidates.pop(best_charge) + candidate = random.choice(sub_candidates) + sub_candidates.remove(candidate) + valid = global_pole.is_valid_choice(dungeon_map, builder, [candidate]) + assign_sector(candidate, builder, polarized_sectors, global_pole) + + # step 3b: neutralize all builders builder_order = list(dungeon_map.values()) random.shuffle(builder_order) for builder in builder_order: + # global_pole.check_odd_polarities(polarized_sectors, dungeon_map) logger.info('--Balancing %s', builder.name) while not builder.polarity().is_neutral(): rejects = [] @@ -1659,6 +1680,12 @@ class GlobalPolarity: proposal.consume(sector) return proposal._check_parity(non_neutral_polarities) and proposal._is_valid_polarities(non_neutral_polarities) + # def check_odd_polarities(self, candidate_sectors, dungeon_map): + # odd_candidates = [x for x in candidate_sectors if x.polarity().charge() % 2 != 0] + # odd_map = {n: x for (n, x) in dungeon_map.items() if sum_polarity(x.sectors).charge() % 2 != 0} + # gp = GlobalPolarity(odd_candidates) + # return gp.is_valid(odd_map) + def find_connection_candidates(mag_needed, sector_pool): candidates = [] @@ -1715,6 +1742,15 @@ def calc_sector_balance(sector): # todo: move to base class? sector.conn_balance[hanger_from_door(door)] += 1 +def find_odd_sectors_ranked_by_charge(builder, polarized_sectors): + polarity = builder.polarity() + candidates = defaultdict(list) + for candidate in [x for x in polarized_sectors if x.polarity().charge() % 2 != 0]: + p_charge = (polarity + candidate.polarity()).charge() + candidates[p_charge].append(candidate) + return candidates + + # todo: refactor to return prioritized lists def find_neutralizing_candidates(builder, sector_pool, rejects): polarity = builder.polarity() diff --git a/Main.py b/Main.py index 4feb9edb..1212a88e 100644 --- a/Main.py +++ b/Main.py @@ -24,7 +24,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute from ItemList import generate_itempool, difficulties, fill_prizes from Utils import output_path, parse_player_names -__version__ = '0.0.e-dev' +__version__ = '0.0.f-dev' def main(args, seed=None):