Ban big keys from locations that will block required freestanding keys

TBD how to handle regular rules
This commit is contained in:
compiling
2020-01-21 22:12:06 +11:00
parent 2c3f5a9aff
commit 1586267a80

View File

@@ -1,3 +1,4 @@
import logging
from collections import defaultdict, deque from collections import defaultdict, deque
from Regions import dungeon_events from Regions import dungeon_events
@@ -46,8 +47,9 @@ class KeyLogic(object):
class DoorRules(object): class DoorRules(object):
def __init__(self, number): def __init__(self, number, is_valid):
self.small_key_num = number self.small_key_num = number
self.is_valid = is_valid
# allowing a different number if bk is behind this door in a set of locations # allowing a different number if bk is behind this door in a set of locations
self.alternate_small_key = None self.alternate_small_key = None
self.alternate_big_key_loc = set() self.alternate_big_key_loc = set()
@@ -144,6 +146,8 @@ def analyze_dungeon(key_layout, world, player):
if not child.bigKey and child not in doors_completed: if not child.bigKey and child not in doors_completed:
best_counter = find_best_counter(child, odd_counter, key_counter, key_layout, world, player, False, empty_flag) best_counter = find_best_counter(child, odd_counter, key_counter, key_layout, world, player, False, empty_flag)
rule = create_rule(best_counter, key_counter, key_layout, world, player) rule = create_rule(best_counter, key_counter, key_layout, world, player)
if not rule.is_valid:
logging.getLogger('').warning('Key logic for door %s requires too many chests. Seed may be beatable anyway.', child.name)
if smallest_rule is None or rule.small_key_num < smallest_rule: if smallest_rule is None or rule.small_key_num < smallest_rule:
smallest_rule = rule.small_key_num smallest_rule = rule.small_key_num
check_for_self_lock_key(rule, child, best_counter, key_layout, world, player) check_for_self_lock_key(rule, child, best_counter, key_layout, world, player)
@@ -343,9 +347,10 @@ def create_rule(key_counter, prev_counter, key_layout, world, player):
required_keys = key_counter.used_keys + 1 # this makes more sense, if key_counter has wasted all keys required_keys = key_counter.used_keys + 1 # this makes more sense, if key_counter has wasted all keys
adj_chest_keys = min(chest_keys, required_keys) adj_chest_keys = min(chest_keys, required_keys)
needed_chests = required_keys - len(key_counter.key_only_locations) needed_chests = required_keys - len(key_counter.key_only_locations)
is_valid = needed_chests <= chest_keys
unneeded_chests = min(key_gain, adj_chest_keys - needed_chests) unneeded_chests = min(key_gain, adj_chest_keys - needed_chests)
rule_num = required_keys - unneeded_chests rule_num = required_keys - unneeded_chests
return DoorRules(rule_num) return DoorRules(rule_num, is_valid)
def check_for_self_lock_key(rule, door, parent_counter, key_layout, world, player): def check_for_self_lock_key(rule, door, parent_counter, key_layout, world, player):
@@ -451,8 +456,8 @@ def bk_restricted_rules(rule, door, odd_counter, empty_flag, key_counter, key_la
if key_counter.big_key_opened: if key_counter.big_key_opened:
return return
best_counter = find_best_counter(door, odd_counter, key_counter, key_layout, world, player, True, empty_flag) best_counter = find_best_counter(door, odd_counter, key_counter, key_layout, world, player, True, empty_flag)
bk_number = create_rule(best_counter, key_counter, key_layout, world, player).small_key_num bk_rule = create_rule(best_counter, key_counter, key_layout, world, player)
if bk_number == rule.small_key_num: if bk_rule.is_valid and bk_rule.small_key_num == rule.small_key_num:
return return
door_open = find_next_counter(door, best_counter, key_layout) door_open = find_next_counter(door, best_counter, key_layout)
ignored_doors = dict_intersection(best_counter.child_doors, door_open.child_doors) ignored_doors = dict_intersection(best_counter.child_doors, door_open.child_doors)
@@ -463,10 +468,11 @@ def bk_restricted_rules(rule, door, odd_counter, empty_flag, key_counter, key_la
ignored_doors = {**ignored_doors, **dict.fromkeys(dest_ignored)} ignored_doors = {**ignored_doors, **dict.fromkeys(dest_ignored)}
post_counter = open_some_counter(door_open, key_layout, ignored_doors.keys()) post_counter = open_some_counter(door_open, key_layout, ignored_doors.keys())
unique_loc = dict_difference(post_counter.free_locations, best_counter.free_locations) unique_loc = dict_difference(post_counter.free_locations, best_counter.free_locations)
if len(unique_loc) > 0: if bk_rule.is_valid and len(unique_loc) > 0:
rule.alternate_small_key = bk_number rule.alternate_small_key = bk_rule.small_key_num
rule.alternate_big_key_loc.update(unique_loc) rule.alternate_big_key_loc.update(unique_loc)
elif not bk_rule.is_valid:
key_layout.key_logic.bk_restricted.update(unique_loc)
def open_a_door(door, child_state, flat_proposal): def open_a_door(door, child_state, flat_proposal):
if door.bigKey: if door.bigKey:
@@ -604,7 +610,7 @@ def check_rules(original_counter, key_layout, world, player):
access_rules = key_only_map[loc] access_rules = key_only_map[loc]
if access_door is None or access_door.name not in key_layout.key_logic.door_rules.keys(): if access_door is None or access_door.name not in key_layout.key_logic.door_rules.keys():
if access_door is None or not access_door.bigKey: if access_door is None or not access_door.bigKey:
access_rules.append(DoorRules(0)) access_rules.append(DoorRules(0, True))
else: else:
rule = key_layout.key_logic.door_rules[access_door.name] rule = key_layout.key_logic.door_rules[access_door.name]
if rule not in access_rules: if rule not in access_rules: