From 4982ef0d9ce884e48e2aa0d8d3ca99c7bd10092c Mon Sep 17 00:00:00 2001 From: aerinon Date: Sat, 14 Sep 2019 22:27:38 -0600 Subject: [PATCH] Starting thinking about a backtracking algorithm --- BaseClasses.py | 29 ++++++++++++++ DoorShuffle.py | 77 ++++++++++++++++++++++++++++++++++++++ asm/asm_investigations.txt | 3 +- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/BaseClasses.py b/BaseClasses.py index ea4dda9e..2089673f 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -821,6 +821,20 @@ class Direction(Enum): Down = 5 +pol_idx = { + Direction.North: (0, 'Pos'), + Direction.South: (0, 'Neg'), + Direction.East: (1, 'Pos'), + Direction.West: (1, 'Neg'), + Direction.Up: (2, 'Pos'), + Direction.Down: (2, 'Neg') +} +pol_inc = { + 'Pos': lambda x: x + 1, + 'Neg': lambda x: x - 1, +} + + class Door(object): def __init__(self, player, name, type, direction, roomIndex, doorIndex, layer, toggle=False): self.player = player @@ -847,6 +861,7 @@ class Door(object): self.dest = None self.parentChunk = None self.blocked = False # Indicates if the door is normally blocked off. (Sanc door or always closed) + self.landing = False # Indicates a door only for matching Holes/Warp # Todo: add to those self.smallKey = False # There's a small key door on this side self.bigKey = False # There's a big key door on this side @@ -892,6 +907,20 @@ class Sector(object): self.regions = [] self.oustandings_doors = [] + def polarity(self): + polarity = [0, 0, 0] + for door in self.oustandings_doors: + idx, inc = pol_idx[door.direction] + polarity[idx] = pol_inc[inc](polarity[idx]) + return polarity + + def magnitude(self): + magnitude = [0, 0, 0] + for door in self.oustandings_doors: + idx, inc = pol_idx[door.direction] + magnitude[idx] = magnitude[idx] + 1 + return magnitude + class Boss(object): def __init__(self, name, enemizer_name, defeat_rule, player): diff --git a/DoorShuffle.py b/DoorShuffle.py index 697d6f18..6ce4d36b 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -693,8 +693,11 @@ def experiment(world, player): print(region.name) for door in sector.oustandings_doors: print(door.name) + print('pol: ' + str(sector.polarity())) + print('mag: ' + str(sector.magnitude())) print() print() + split_up_sectors(dp, desert_default_entrance_sets) dungeon_region_lists = [hyrule_castle_regions, eastern_regions, desert_regions] for region_list in dungeon_region_lists: @@ -747,6 +750,8 @@ def convert_to_sectors(region_names, world, player): def split_up_sectors(sector_list, entrance_sets): new_sector_grid = [] + leftover_sectors = [] + leftover_sectors.extend(sector_list) for entrance_set in entrance_sets: new_sector_list = [] for sector in sector_list: @@ -754,12 +759,84 @@ def split_up_sectors(sector_list, entrance_sets): for entrance in entrance_set: if entrance in s_regions: new_sector_list.append(sector) + leftover_sectors.remove(sector) break new_sector_grid.append(new_sector_list) # appalling I know - how to split up other things + for s_list in new_sector_grid: + print('pol:'+str(sum_vector(s_list, lambda s: s.polarity()))) + print('mag:'+str(sum_vector(s_list, lambda s: s.magnitude()))) + print('pol:'+str(sum_vector(leftover_sectors, lambda s: s.polarity()))) + print('mag:'+str(sum_vector(leftover_sectors, lambda s: s.magnitude()))) + + return new_sector_grid +def sum_vector(sector_list, func): + sum = [0, 0, 0] + for sector in sector_list: + vector = func(sector) + for i in range(len(sum)): + sum[i] = sum[i] + vector[i] + return sum + + +# def add_vectors(vector_one, vector_two): +# result = [0]*len(vector_one) +# for i in range(len(result)): +# result[i] = vector_one[i] + vector_two[i] +# return result + + +def is_polarity_neutral(polarity): + neutral = 0 + for value in polarity: + neutral = neutral + value + return neutral == 0 + + +def is_proposal_valid(proposal, buckets, candidates): + # check that proposal is complete + for i in range(len(proposal)): + if proposal[i] is -1: + return False # indicates an incomplete proposal + test_bucket = [[]]*len(buckets) + for bucket_idx in range(len(buckets)): + test_bucket[bucket_idx].extend(buckets[bucket_idx]) + for i in range(len(proposal)): + test_bucket[proposal[i]].append(candidates[i]) + for test in test_bucket: + valid = is_polarity_neutral(sum_vector(test, lambda s: s.polarity())) + if not valid: + return False + return True + + +def assignment(buckets, candidates): + random.shuffle(buckets) + random.shuffle(candidates) + proposal = [-1]*len(candidates) + + solution = next_proposal(proposal, buckets, candidates) + if solution is None: + raise Exception('Unable to find a proposal') + # todo: use solution to assign to buckets and candidates + # buckets = + + +def next_proposal(proposal, buckets, candidates): + if is_proposal_valid(proposal, buckets, candidates): + return proposal + + next_candidate_idx = proposal.index(-1) + for i in range(len(buckets)): # todo: this produces a weighted solution unfortunately, good for a mode called OneBigHappyDungeon in crossed, not good for a balanced, or random approach + proposal[next_candidate_idx] = i + found_proposal = next_proposal(proposal, buckets, candidates) + if found_proposal is not None: + return found_proposal + return None # there was no valid assignment + # code below is for an algorithm without restarts diff --git a/asm/asm_investigations.txt b/asm/asm_investigations.txt index bebc2382..13911c40 100644 --- a/asm/asm_investigations.txt +++ b/asm/asm_investigations.txt @@ -18,7 +18,8 @@ a5 a0 -Modules 04 and 05 skip the PaletteFiltering right above it - moving the pointers slightly might help +Modules 04 and 05 skip the PaletteFiltering right above it - moving the pointers slightly might help - didn't help +mostly for the black fade out 60 a5 b0 c9 07 90 ?? ?? jsl ?? ?? ??