-Multiworld key rule fix
-Minor generation fix
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import random
|
||||
import collections
|
||||
import itertools
|
||||
from collections import defaultdict, deque
|
||||
from enum import Enum, unique
|
||||
import logging
|
||||
@@ -1467,20 +1468,32 @@ def assign_polarized_sectors(dungeon_map, polarized_sectors, global_pole, logger
|
||||
problem_builders = identify_branching_issues_2(problem_builders)
|
||||
|
||||
# step 5: assign randomly until gone - must maintain connectedness, neutral polarity, branching, lack, etc.
|
||||
comb_w_replace = len(dungeon_map) ** len(neutral_choices)
|
||||
combinations = None
|
||||
if comb_w_replace <= 1000:
|
||||
combinations = list(itertools.product(dungeon_map.keys(), repeat=len(neutral_choices)))
|
||||
random.shuffle(combinations)
|
||||
tries = 0
|
||||
while len(polarized_sectors) > 0:
|
||||
if tries > 100:
|
||||
if tries > 1000 or (combinations and tries >= len(combinations)):
|
||||
raise Exception('No valid assignment found. Ref: %s' % next(iter(dungeon_map.keys())))
|
||||
choices = random.choices(list(dungeon_map.keys()), k=len(neutral_choices))
|
||||
valid = []
|
||||
if combinations:
|
||||
choices = combinations[tries]
|
||||
else:
|
||||
choices = random.choices(list(dungeon_map.keys()), k=len(neutral_choices))
|
||||
chosen_sectors = defaultdict(list)
|
||||
for i, choice in enumerate(choices):
|
||||
builder = dungeon_map[choice]
|
||||
if valid_assignment(builder, neutral_choices[i]):
|
||||
chosen_sectors[choice].extend(neutral_choices[i])
|
||||
all_valid = True
|
||||
for name, sector_list in chosen_sectors.items():
|
||||
if not valid_assignment(dungeon_map[name], sector_list):
|
||||
all_valid = False
|
||||
break
|
||||
if all_valid:
|
||||
for i, choice in enumerate(choices):
|
||||
builder = dungeon_map[choice]
|
||||
for sector in neutral_choices[i]:
|
||||
assign_sector(sector, builder, polarized_sectors, global_pole)
|
||||
valid.append(neutral_choices[i])
|
||||
for c in valid:
|
||||
neutral_choices.remove(c)
|
||||
tries += 1
|
||||
|
||||
|
||||
@@ -1931,6 +1944,7 @@ def resolve_equations(builder, sector_list):
|
||||
# negative benefit transforms (dead end)
|
||||
def find_priority_equation(equations, current_access):
|
||||
flex = calc_flex(equations, current_access)
|
||||
required = calc_required(equations, current_access)
|
||||
best_profit = None
|
||||
triplet_candidates = []
|
||||
local_profit_map = {}
|
||||
@@ -1951,14 +1965,17 @@ def find_priority_equation(equations, current_access):
|
||||
else:
|
||||
triplet_candidates.append((eq, eq_list, sector))
|
||||
local_profit_map[sector] = best_local_profit
|
||||
if len(triplet_candidates) == 0:
|
||||
filtered_candidates = filter_requirements(triplet_candidates, equations, required, current_access)
|
||||
if len(filtered_candidates) == 0:
|
||||
filtered_candidates = triplet_candidates
|
||||
if len(filtered_candidates) == 0:
|
||||
return None, None, None # can't pay for anything
|
||||
if len(triplet_candidates) == 1:
|
||||
return triplet_candidates[0]
|
||||
if len(filtered_candidates) == 1:
|
||||
return filtered_candidates[0]
|
||||
|
||||
required_candidates = [x for x in triplet_candidates if x[0].required]
|
||||
required_candidates = [x for x in filtered_candidates if x[0].required]
|
||||
if len(required_candidates) == 0:
|
||||
required_candidates = triplet_candidates
|
||||
required_candidates = filtered_candidates
|
||||
if len(required_candidates) == 1:
|
||||
return required_candidates[0]
|
||||
|
||||
@@ -1974,6 +1991,46 @@ def find_priority_equation(equations, current_access):
|
||||
return good_local_candidates[0] # just pick one I guess
|
||||
|
||||
|
||||
def calc_required(equations, current_access):
|
||||
ttl = 0
|
||||
for num in current_access.values():
|
||||
ttl += num
|
||||
local_profit_map = {}
|
||||
for sector, eq_list in equations.items():
|
||||
best_local_profit = None
|
||||
for eq in eq_list:
|
||||
profit = eq.profit()
|
||||
if best_local_profit is None or profit > best_local_profit:
|
||||
best_local_profit = profit
|
||||
local_profit_map[sector] = best_local_profit
|
||||
ttl += best_local_profit
|
||||
if ttl == 0:
|
||||
new_lists = {}
|
||||
for sector, eq_list in equations.items():
|
||||
if len(eq_list) > 1:
|
||||
rem_list = []
|
||||
for eq in eq_list:
|
||||
if eq.profit() < local_profit_map[sector]:
|
||||
rem_list.append(eq)
|
||||
if len(rem_list) > 0:
|
||||
new_lists[sector] = [x for x in eq_list if x not in rem_list]
|
||||
for sector, eq_list in new_lists.items():
|
||||
if len(eq_list) <= 1:
|
||||
for eq in eq_list:
|
||||
eq.required = True
|
||||
equations[sector] = eq_list
|
||||
required_costs = defaultdict(int)
|
||||
required_benefits = defaultdict(int)
|
||||
for sector, eq_list in equations.items():
|
||||
for eq in eq_list:
|
||||
if eq.required:
|
||||
for key, door_list in eq.cost.items():
|
||||
required_costs[key] += len(door_list)
|
||||
for key, door_list in eq.benefit.items():
|
||||
required_benefits[key] += len(door_list)
|
||||
return required_costs, required_benefits
|
||||
|
||||
|
||||
def calc_flex(equations, current_access):
|
||||
flex_spending = defaultdict(int)
|
||||
required_costs = defaultdict(int)
|
||||
@@ -1987,6 +2044,45 @@ def calc_flex(equations, current_access):
|
||||
return flex_spending
|
||||
|
||||
|
||||
def filter_requirements(triplet_candidates, equations, required, current_access):
|
||||
r_costs, r_exits = required
|
||||
valid_candidates = []
|
||||
for cand, cand_list, cand_sector in triplet_candidates:
|
||||
valid = True
|
||||
if not cand.required:
|
||||
potential_benefit = defaultdict(int)
|
||||
potential_costs = defaultdict(int)
|
||||
for h_type, benefit in current_access.items():
|
||||
cur_cost = len(cand.cost[h_type])
|
||||
if benefit - cur_cost > 0:
|
||||
potential_benefit[h_type] += benefit - cur_cost
|
||||
for h_type, benefit_list in cand.benefit.items():
|
||||
potential_benefit[h_type] += len(benefit_list)
|
||||
for sector, eq_list in equations.items():
|
||||
if sector == cand_sector:
|
||||
affected_doors = [d for x in cand.benefit.values() for d in x] + [d for x in cand.cost.values() for d in x]
|
||||
adj_list = [x for x in eq_list if x.door not in affected_doors]
|
||||
else:
|
||||
adj_list = eq_list
|
||||
for eq in adj_list:
|
||||
for h_type, benefit_list in eq.benefit.items():
|
||||
potential_benefit[h_type] += len(benefit_list)
|
||||
for h_type, cost_list in eq.cost.items():
|
||||
potential_costs[h_type] += len(cost_list)
|
||||
for h_type, requirement in r_costs.items():
|
||||
if requirement > 0 and potential_benefit[h_type] < requirement:
|
||||
valid = False
|
||||
break
|
||||
if valid:
|
||||
for h_type, requirement in r_exits.items():
|
||||
if requirement > 0 and potential_costs[h_type] < requirement:
|
||||
valid = False
|
||||
break
|
||||
if valid:
|
||||
valid_candidates.append((cand, cand_list, cand_sector))
|
||||
return valid_candidates
|
||||
|
||||
|
||||
def resolve_equation(equation, eq_list, sector, current_access, reached_doors, equations):
|
||||
for key, door_list in equation.cost.items():
|
||||
if current_access[key] - len(door_list) < 0:
|
||||
|
||||
2
Fill.py
2
Fill.py
@@ -233,7 +233,7 @@ def valid_key_placement(item, location, itempool, world):
|
||||
if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name):
|
||||
return True
|
||||
key_logic = world.key_logic[item.player][dungeon.name]
|
||||
unplaced_keys = len([x for x in itempool if x.name == key_logic.small_key_name])
|
||||
unplaced_keys = len([x for x in itempool if x.name == key_logic.small_key_name and x.player == item.player])
|
||||
return key_logic.check_placement(unplaced_keys)
|
||||
else:
|
||||
inside_dungeon_item = ((item.smallkey and not world.keyshuffle[item.player])
|
||||
|
||||
2
Main.py
2
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.17.1p'
|
||||
__version__ = '0.0.17.2p'
|
||||
|
||||
|
||||
def main(args, seed=None):
|
||||
|
||||
Reference in New Issue
Block a user