TR Crystal Maze adjustments

Fixed key door candidate finder to stay within own dungeon
Standard mode support added
Added missed Pre-moldorm chest
Started work on new key logic analyzer
This commit is contained in:
aerinon
2019-11-19 10:50:44 -07:00
parent 644785b140
commit 48494a09ba
8 changed files with 237 additions and 12 deletions

198
KeyDoorShuffle.py Normal file
View File

@@ -0,0 +1,198 @@
import collections
from Regions import dungeon_events
from DungeonGenerator import ExplorationState
class KeyRegion(object):
def __init__(self):
self.access_doors = set()
self.free_locations = []
self.prize_region = False
self.key_only_locations = []
self.child_doors = set()
self.bk_locked = False
self.parent_region = None
def __eq__(self, other):
if self.prize_region != other.prize_region:
return False
if self.bk_locked != other.bk_locked:
return False
if len(self.free_locations) != len(other.free_locations):
return False
if len(self.key_only_locations) != len(other.key_only_locations):
return False
if len(set(self.free_locations).difference(set(other.free_locations))) > 0:
return False
if len(set(self.key_only_locations).difference(set(other.key_only_locations))) > 0:
return False
if not self.check_child_dest(self.child_doors, other.child_doors, other.access_doors):
return False
if not self.check_child_dest(other.child_doors, self.child_doors, self.access_doors):
return False
return True
@staticmethod
def check_child_dest(child_doors, other_child, other_access):
for child in child_doors:
if child in other_child:
continue
else:
found = False
for access in other_access:
if access.dest == child:
found = True
break
if not found:
return False
return True
# def issubset(self, other):
# if self.prize_region != other.prize_region:
# return False
# if self.bk_locked != other.bk_locked:
# return False
# if not set(self.free_locations).issubset(set(other.free_locations)):
# return False
# if not set(self.key_only_locations).issubset(set(other.key_only_locations)):
# return False
# if not set(self.child_doors).issubset(set(other.child_doors)):
# return False
# return True
#
# def issuperset(self, other):
# if self.prize_region != other.prize_region:
# return False
# if self.bk_locked != other.bk_locked:
# return False
# if not set(self.free_locations).issuperset(set(other.free_locations)):
# return False
# if not set(self.key_only_locations).issuperset(set(other.key_only_locations)):
# return False
# if not set(self.child_doors).issuperset(set(other.child_doors)):
# return False
# return True
def analyze_dungeon(key_layout, world, player):
flat_proposal = flatten_pair_list(key_layout.proposal)
key_regions = create_key_regions(key_layout, flat_proposal, world, player)
start = key_regions['Origin']
def create_key_regions(key_layout, flat_proposal, world, player):
key_regions = {}
state = ExplorationState()
state.key_locations = len(world.get_dungeon(key_layout.sector.name, player).small_keys)
state.big_key_special = world.get_region('Hyrule Dungeon Cellblock', player) in key_layout.sector.regions
for region in key_layout.start_regions:
state.visit_region(region, key_checks=True)
state.add_all_doors_check_keys(region, flat_proposal, world, player)
expand_key_state(state, flat_proposal, world, player)
key_regions['Origin'] = create_key_region(state, None, None)
queue = collections.deque([(key_regions['Origin'], state)])
while len(queue) > 0:
next_key_region, parent_state = queue.popleft()
for door in next_key_region.child_doors:
child_state = parent_state.copy()
# open the door
open_a_door(door, child_state, flat_proposal)
expand_key_state(child_state, flat_proposal, world, player)
child_kr = create_key_region(child_state, next_key_region, door)
check_for_duplicates_sub_super_set(key_regions, child_kr, door.name)
queue.append((child_kr, child_state))
return key_regions
def check_for_duplicates_sub_super_set(key_regions, new_kr, door_name):
is_new = True
for kr in key_regions.values():
if new_kr == kr:
kr.access_doors.update(new_kr.access_doors)
kr.child_doors.update(new_kr.child_doors)
key_regions[door_name] = kr
is_new = False
break
# if new_kr.issubset(kr):
# break
# if new_kr.issuperset(kr):
# break
if is_new:
key_regions[door_name] = new_kr
def create_key_region(state, parent_region, door):
key_region = KeyRegion()
key_region.parent_region = parent_region
p_region = parent_region
parent_doors = set()
parent_locations = set()
while p_region is not None:
parent_doors.update(p_region.child_doors)
parent_locations.update(p_region.free_locations+p_region.key_only_locations)
p_region = p_region.parent_region
u_doors = unique_doors(state.small_doors+state.big_doors).difference(parent_doors)
key_region.child_doors.update(u_doors)
region_locations = set(state.found_locations).difference(parent_locations)
for loc in region_locations:
if '- Prize' in loc.name or loc.name in ['Agahnim 1', 'Agahnim 2']:
key_region.prize_region = True
elif loc.event and 'Small Key' in loc.item.name:
key_region.key_only_locations.append(loc)
elif loc.name not in dungeon_events:
key_region.free_locations.append(loc)
key_region.bk_locked = state.big_key_opened
if door is not None:
key_region.access_doors.add(door)
return key_region
def open_a_door(door, child_state, flat_proposal):
if door.bigKey:
child_state.big_key_opened = True
child_state.avail_doors.extend(child_state.big_doors)
child_state.opened_doors.extend(set([d.door for d in child_state.big_doors]))
child_state.big_doors.clear()
else:
child_state.opened_doors.append(door)
doors_to_open = [x for x in child_state.small_doors if x.door == door]
child_state.small_doors[:] = [x for x in child_state.small_doors if x.door != door]
child_state.avail_doors.extend(doors_to_open)
dest_door = door.dest
if dest_door in flat_proposal:
child_state.opened_doors.append(dest_door)
if child_state.in_door_list_ic(dest_door, child_state.small_doors):
now_available = [x for x in child_state.small_doors if x.door == dest_door]
child_state.small_doors[:] = [x for x in child_state.small_doors if x.door != dest_door]
child_state.avail_doors.extend(now_available)
def unique_doors(doors):
unique_d_set = set()
for d in doors:
if d.door not in unique_d_set:
unique_d_set.add(d.door)
return unique_d_set
def expand_key_state(state, flat_proposal, world, player):
while len(state.avail_doors) > 0:
exp_door = state.next_avail_door()
door = exp_door.door
connect_region = world.get_entrance(door.name, player).connected_region
if state.validate(door, connect_region, world):
state.visit_region(connect_region, key_checks=True)
state.add_all_doors_check_keys(connect_region, flat_proposal, world, player)
def flatten_pair_list(paired_list):
flat_list = []
for d in paired_list:
if type(d) is tuple:
flat_list.append(d[0])
flat_list.append(d[1])
else:
flat_list.append(d)
return flat_list