198 lines
5.8 KiB
Python
198 lines
5.8 KiB
Python
import csv
|
|
from collections import deque
|
|
|
|
class TreeNode:
|
|
def __init__(self):
|
|
self.fa = None
|
|
self.children = []
|
|
self.pos = None
|
|
self.final_pos = None
|
|
self.val = 0
|
|
self.id = 0
|
|
self.dp = 0
|
|
|
|
class SourceCollector:
|
|
def __init__(self, filename=None, maze=None):
|
|
self.filename = filename
|
|
self.maze = maze
|
|
self.start_pos = None
|
|
self.end_pos = None
|
|
self.path = []
|
|
self.node_path = []
|
|
if self.filename:
|
|
self.maze = []
|
|
with open(f"{self.filename}",'r') as f:
|
|
reader = csv.reader(f)
|
|
for row in reader:
|
|
t = []
|
|
for i in row:
|
|
if i.startswith('b') or i.startswith('l'):
|
|
t.append('0')
|
|
else:
|
|
t.append(i)
|
|
self.maze.append(t)
|
|
else:
|
|
self.maze = maze
|
|
self.rowNums = len(self.maze)
|
|
self.colNums = len(self.maze[0])
|
|
|
|
|
|
for i in range(self.rowNums):
|
|
for j in range(self.colNums):
|
|
if self.maze[i][j] =='s':
|
|
self.start_pos = (i,j)
|
|
if self.maze[i][j] =='e':
|
|
self.end_pos = (i,j)
|
|
|
|
def dfs_show(self,u):
|
|
if u.id != 0:
|
|
print(f"id: {u.id} , fa:{u.fa.id} , val:{u.val} , pos:{u.pos}")
|
|
else:
|
|
print(f"id: {u.id} , val:{u.val} , pos:{u.pos}")
|
|
for child in u.children:
|
|
self.dfs_show(child)
|
|
def build_a_tree(self):
|
|
cnt = 0
|
|
root = TreeNode()
|
|
root.pos = self.start_pos
|
|
root.id = 0
|
|
root.val = 0
|
|
root.fa = None
|
|
|
|
queue = deque([(self.start_pos[0], self.start_pos[1], root)])
|
|
st = [[False] * self.colNums for _ in range(self.rowNums)]
|
|
st[self.start_pos[0]][self.start_pos[1]] = True
|
|
|
|
dx = [-1, 0, 1, 0]
|
|
dy = [0, -1, 0, 1]
|
|
|
|
while queue:
|
|
x, y, parent = queue.popleft()
|
|
for i in range(4):
|
|
nx, ny = x + dx[i], y + dy[i]
|
|
if self.outofmap(nx, ny) or st[nx][ny]:
|
|
continue
|
|
|
|
if self.maze[nx][ny] != '1':
|
|
st[nx][ny] = True
|
|
|
|
new_node = TreeNode()
|
|
new_node.pos = (nx, ny)
|
|
new_node.fa = parent
|
|
cnt+=1
|
|
new_node.id = cnt
|
|
if self.maze[nx][ny].startswith('g'):
|
|
new_node.val = int(self.maze[nx][ny][1:])
|
|
elif self.maze[nx][ny].startswith('t'):
|
|
new_node.val =-1 *int(self.maze[nx][ny][1:])
|
|
parent.children.append(new_node)
|
|
queue.append((nx, ny, new_node))
|
|
return root
|
|
|
|
|
|
|
|
|
|
def outofmap(self,x,y):
|
|
return x < 0 or y < 0 or x > self.rowNums or y > self.colNums
|
|
def getlca(self,u, v):
|
|
def get_path_to_root(node):
|
|
path = []
|
|
while node:
|
|
path.append(node)
|
|
node = node.fa
|
|
return path
|
|
path_u = get_path_to_root(u)
|
|
path_v = get_path_to_root(v)
|
|
|
|
path_u.reverse()
|
|
path_v.reverse()
|
|
|
|
lca = None
|
|
for i in range(min(len(path_u),len(path_v))):
|
|
if path_u[i] == path_v[i]:
|
|
lca = path_u[i]
|
|
else:
|
|
break
|
|
|
|
if lca is None:
|
|
return []
|
|
u_to_lca = []
|
|
node = u
|
|
while node != lca:
|
|
u_to_lca.append(node.pos)
|
|
node = node.fa
|
|
|
|
lca_to_v = []
|
|
node_list = []
|
|
node = v
|
|
while node != lca:
|
|
node_list.append(node)
|
|
node = node.fa
|
|
node_list.append(lca)
|
|
node_list.reverse()
|
|
for node in node_list:
|
|
lca_to_v.append(node.pos)
|
|
|
|
full_path = u_to_lca + lca_to_v
|
|
return full_path
|
|
def dfs(self,sn):
|
|
|
|
sn.dp = sn.val
|
|
sn.final_pos = sn.pos
|
|
sn.path= [sn.pos]
|
|
cur = None
|
|
for idx,child in enumerate(sn.children):
|
|
self.dfs(child)
|
|
if child.dp > 0:
|
|
sn.dp += child.dp
|
|
if cur != None:
|
|
sn.path.extend(self.getlca(cur,child))
|
|
sn.path.extend(child.path)
|
|
cur = child
|
|
if idx == len(sn.children)-1:
|
|
sn.final_pos = cur.final_pos
|
|
|
|
|
|
|
|
def get_path(self):
|
|
return self.path
|
|
|
|
def run(self):
|
|
sn = self.build_a_tree()
|
|
# self.dfs_show(sn)
|
|
self.dfs(sn)
|
|
self.path = sn.path
|
|
|
|
|
|
def output_list(self):
|
|
copy_maze = self.maze
|
|
for idx, (y, x) in enumerate(self.path):
|
|
if copy_maze[y][x].startswith('s') | copy_maze[y][x].startswith('e'):
|
|
continue
|
|
if copy_maze[y][x].startswith('g') | copy_maze[y][x].startswith('t'):
|
|
copy_maze[y][x] = f"{copy_maze[y][x]}p{idx}"
|
|
continue
|
|
copy_maze[y][x] = f"p{idx}"
|
|
|
|
return copy_maze
|
|
|
|
|
|
if __name__ == '__main__':
|
|
obj = SourceCollector(filename="maze.csv")
|
|
obj.run()
|
|
path = obj.get_path()
|
|
for i in path:
|
|
print(i)
|
|
# print(sn.pos)
|
|
# pre = sn.pos
|
|
# for _ in sn.dp_path:
|
|
# dx,dy = _[0] - pre[0],_[1]-pre[1]
|
|
# if dx > 0:
|
|
# print("down")
|
|
# elif dx < 0:
|
|
# print("up")
|
|
# elif dy > 0:
|
|
# print("right")
|
|
# elif dy < 0:
|
|
# print("left")
|
|
# pre = _ |