WIP faster paths
parent
6194d555b8
commit
ab089feb6e
137
Fusion_Graph.py
137
Fusion_Graph.py
|
@ -12,6 +12,7 @@
|
|||
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
|
||||
class Game:
|
||||
|
||||
|
@ -28,18 +29,9 @@ class Game:
|
|||
self.minorItemLocations = list()
|
||||
self.itemLocations = set()
|
||||
self.patcher = dict()
|
||||
self.graph.clear()
|
||||
self.areaConnections.clear()
|
||||
self.areaConnectionOffsets.clear()
|
||||
self.doorConnections.clear()
|
||||
self.rooms.clear()
|
||||
self.requirements.clear()
|
||||
self.visited.clear()
|
||||
self.queue.clear()
|
||||
self.majorItemLocations.clear()
|
||||
self.minorItemLocations.clear()
|
||||
self.itemLocations.clear()
|
||||
self.patcher.clear()
|
||||
self.oldtime = 0.0
|
||||
self.bfstime = 0.0
|
||||
self.dfstime = 0.0
|
||||
|
||||
# print('DEBUG: Opening ROM to pick stuff')
|
||||
|
||||
|
@ -96,6 +88,8 @@ class Game:
|
|||
sys.exit(1)
|
||||
|
||||
|
||||
def print_stats(self):
|
||||
print("Path search time: old search = {}s, bfs time = {}s, dfs time = {}s".format(self.oldtime, self.bfstime, self.dfstime))
|
||||
|
||||
def set_setting(self, setting, value):
|
||||
self.settings[setting] = value
|
||||
|
@ -209,6 +203,15 @@ class Game:
|
|||
return self.requirements.get(checkRequirement)
|
||||
|
||||
def get_path(self, start, end, LimitArea=False, path=None, depth=100):
|
||||
#return [start,end] if self.has_path(start,end,LimitArea, depth) else None
|
||||
|
||||
t = time.perf_counter()
|
||||
path = self._get_path(start, end, LimitArea, path, depth)
|
||||
self.oldtime += time.perf_counter() - t
|
||||
|
||||
return path
|
||||
|
||||
def _get_path(self, start, end, LimitArea, path, depth):
|
||||
if path == None:
|
||||
self.visited.clear()
|
||||
self.queue.clear()
|
||||
|
@ -240,12 +243,118 @@ class Game:
|
|||
node = edge[1]
|
||||
pathReqs = self.get_requirements(start, node)
|
||||
if pathReqs == None:
|
||||
newpath = self.get_path(node, end, LimitArea, path, depth)
|
||||
newpath = self._get_path(node, end, LimitArea, path, depth)
|
||||
if newpath:
|
||||
path = path + [node]
|
||||
return newpath
|
||||
elif pathReqs == True:
|
||||
newpath = self.get_path(node, end, LimitArea, path, depth)
|
||||
newpath = self._get_path(node, end, LimitArea, path, depth)
|
||||
if newpath:
|
||||
path = path + [node]
|
||||
return newpath
|
||||
|
||||
def has_path(self, start, end, LimitArea=False, depth=100):
|
||||
if LimitArea:
|
||||
area = self.itemArea.get(start)
|
||||
if area == None:
|
||||
for n in range(0, 7):
|
||||
if 'S{}'.format(n) in start:
|
||||
area = n
|
||||
if area == None:
|
||||
for n in range(0, 7):
|
||||
if 'S{}'.format(n) in end:
|
||||
area = n
|
||||
else:
|
||||
area = None
|
||||
t = time.perf_counter()
|
||||
result = self.has_path_bfs(start, end, area=area, max_depth=depth)
|
||||
self.bfstime += time.perf_counter() - t
|
||||
t = time.perf_counter()
|
||||
r2 =self.has_path_dfs(start, end, area=area)
|
||||
assert result == r2, (start, end, result, r2, area)
|
||||
self.dfstime += time.perf_counter() - t
|
||||
return result
|
||||
|
||||
# NOTE: both the start and end node need to be excluded from
|
||||
# area checks because they can be things like bosses or the Water Pump
|
||||
# that aren't associated with an area. all the intermediate nodes
|
||||
# should be doors, and doors all have their sector number in their names.
|
||||
|
||||
def has_path_bfs(self, start, end, area=None, max_depth=100):
|
||||
if start not in self.graph:
|
||||
return False
|
||||
if start == end:
|
||||
return True
|
||||
if area != None:
|
||||
areaStr = 'S{}'.format(area)
|
||||
seen = {start}
|
||||
frontier = [start]
|
||||
next_frontier = []
|
||||
depth = 0
|
||||
while frontier:
|
||||
depth += 1
|
||||
#if depth > max_depth: break
|
||||
for node in frontier:
|
||||
for neighbor in self.graph[node]:
|
||||
if neighbor in seen:
|
||||
continue
|
||||
if neighbor in self.itemLocations:
|
||||
if neighbor == end:
|
||||
pathReqs = self.get_requirements(node, neighbor)
|
||||
if pathReqs == None or pathReqs == True:
|
||||
return True
|
||||
#seen.add(neighbor)
|
||||
continue
|
||||
if area is not None:
|
||||
if areaStr not in neighbor and neighbor != end:
|
||||
continue
|
||||
pathReqs = self.get_requirements(node, neighbor)
|
||||
if pathReqs != None and pathReqs != True:
|
||||
continue
|
||||
if neighbor == end:
|
||||
return True
|
||||
|
||||
next_frontier.append(neighbor)
|
||||
|
||||
# since this is a breadth-first search on an unweighted graph,
|
||||
# we know that no other paths can be shorter than this one,
|
||||
# so we can immediately mark the node as seen to prevent
|
||||
# adding it to the frontier again
|
||||
seen.add(neighbor)
|
||||
|
||||
frontier.clear()
|
||||
frontier, next_frontier = next_frontier, frontier
|
||||
|
||||
return False
|
||||
|
||||
def has_path_dfs(self, start, end, area=None):
|
||||
if start not in self.graph:
|
||||
return False
|
||||
if start == end:
|
||||
return True
|
||||
visited = set()
|
||||
stack = [start]
|
||||
if area != None:
|
||||
areaStr = 'S{}'.format(area)
|
||||
while stack:
|
||||
node = stack.pop()
|
||||
if node in visited:
|
||||
continue
|
||||
visited.add(node)
|
||||
if node == end:
|
||||
return True
|
||||
if node is not start:
|
||||
if node in self.itemLocations:
|
||||
continue
|
||||
if area is not None:
|
||||
if areaStr not in node:
|
||||
continue
|
||||
|
||||
for neighbor in reversed(self.graph[node]):
|
||||
if neighbor in visited:
|
||||
continue
|
||||
pathReqs = self.get_requirements(node, neighbor)
|
||||
if pathReqs != None and pathReqs != True:
|
||||
continue
|
||||
stack.append(neighbor)
|
||||
return False
|
||||
|
|
|
@ -3135,6 +3135,9 @@ def start_randomizer(rom, settings):
|
|||
seedTime = time.time() - startTime
|
||||
print(str(FileName))
|
||||
print('Randomized in:', seedTime)
|
||||
World.print_stats()
|
||||
print("water lowered:", WaterLowered)
|
||||
print("len(world.graph) = ", len(World.graph))
|
||||
|
||||
totalRandoTime = time.time() - totalRandoTime
|
||||
print('All seeds took:', totalRandoTime)
|
||||
|
|
Loading…
Reference in New Issue