maze_python/SourceCollector.py
2025-07-04 12:22:51 +08:00

399 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = []
self.boss_pos = None
self.lock_pos = None
# 添加资源收集统计
self.collected_resources = [] # 收集的资源详情
self.total_coins = 0 # 金币总价值
self.total_traps = 0 # 陷阱总损失
self.total_value = 0 # 总价值(金币-陷阱)
if self.filename:
self.maze = []
with open(f"{self.filename}",'r') as f:
reader = csv.reader(f)
for idx,row in enumerate(reader):
t = []
for idy,i in enumerate(row):
if i.startswith('b'):
t.append('0')
self.boss_pos = (idx,idy)
elif i.startswith('l'):
t.append('0')
self.lock_pos = (idx,idy)
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)
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)
full_path = u_to_lca + lca_to_v[:-1]
return full_path
def dfs(self, sn):
sn.dp = sn.val
sn.final_pos = sn.pos
sn.path = [sn]
# 先对子节点全部深搜一遍,收集路径长度
children = sn.children[:]
for child in children:
self.dfs(child)
children.sort(key=lambda c: len(c.path))
cur = None
for idx, child in enumerate(children):
if child.dp > 0:
sn.dp += child.dp
if cur is not None:
sn.path.extend(self.getlca(sn.path[-1], child))
sn.path.extend(child.path)
cur = child
sn.final_pos = cur.final_pos
def get_path(self):
return self.path
def bfs_path(self, start, end):
"""从start到end的最短路径含首尾"""
from collections import deque
n, m = self.rowNums, self.colNums
visited = [[False]*m for _ in range(n)]
prev = [[None]*m for _ in range(n)]
q = deque([start])
visited[start[0]][start[1]] = True
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
while q:
x, y = q.popleft()
if (x, y) == end:
break
for i in range(4):
nx, ny = x + dx[i], y + dy[i]
if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny]:
if self.maze[nx][ny] != '1':
visited[nx][ny] = True
prev[nx][ny] = (x, y)
q.append((nx, ny))
# 回溯路径
path = []
cur = end
while cur and cur != start:
path.append(cur)
cur = prev[cur[0]][cur[1]]
if cur == start:
path.append(start)
path.reverse()
return path
return []
def run(self):
sn = self.build_a_tree()
# self.dfs_show(sn)
self.dfs(sn)
self.path =[_.pos for _ in sn.path]
for idx,item in enumerate(self.path):
if idx > 0:
if item == self.path[idx-1]:
del self.path[idx]
self.path.extend(self.bfs_path(self.path[-1],self.end_pos))
# 计算并打印资源总结
self.print_resource_summary()
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
def calculate_resources(self):
"""计算路径上收集到的资源总量"""
self.collected_resources = []
self.total_coins = 0
self.total_traps = 0
self.total_value = 0
visited_positions = set() # 避免重复计算同一位置的资源
for step, (y, x) in enumerate(self.path):
if (y, x) in visited_positions:
continue
visited_positions.add((y, x))
cell = self.maze[y][x]
if cell.startswith('g'): # 金币
try:
coin_value = int(cell[1:])
self.total_coins += coin_value
self.total_value += coin_value
self.collected_resources.append({
'type': 'coin',
'position': (y, x),
'value': coin_value,
'step': step
})
except ValueError:
# 如果没有数值默认为1
self.total_coins += 1
self.total_value += 1
self.collected_resources.append({
'type': 'coin',
'position': (y, x),
'value': 1,
'step': step
})
elif cell.startswith('t'): # 陷阱
try:
trap_value = int(cell[1:])
self.total_traps += trap_value
self.total_value -= trap_value
self.collected_resources.append({
'type': 'trap',
'position': (y, x),
'value': -trap_value,
'step': step
})
except ValueError:
# 如果没有数值默认为1
self.total_traps += 1
self.total_value -= 1
self.collected_resources.append({
'type': 'trap',
'position': (y, x),
'value': -1,
'step': step
})
elif cell.startswith('b'): # Boss (记录但不计入总价值)
self.collected_resources.append({
'type': 'boss',
'position': (y, x),
'value': 0,
'step': step
})
elif cell.startswith('l'): # 机关 (记录但不计入总价值)
self.collected_resources.append({
'type': 'mechanism',
'position': (y, x),
'value': 0,
'step': step
})
def print_resource_summary(self):
"""打印资源收集总结"""
print("\n" + "="*50)
print("SourceCollector 资源收集总结")
print("="*50)
if not self.path:
print("没有生成路径,无法统计资源")
return
# 先计算资源
self.calculate_resources()
print(f"路径总长度: {len(self.path)}")
print(f"收集资源总数: {len(self.collected_resources)}")
print()
# 按类型分组统计
coins = [r for r in self.collected_resources if r['type'] == 'coin']
traps = [r for r in self.collected_resources if r['type'] == 'trap']
bosses = [r for r in self.collected_resources if r['type'] == 'boss']
mechanisms = [r for r in self.collected_resources if r['type'] == 'mechanism']
print(f"金币收集: {len(coins)} 个,总价值: +{self.total_coins}")
if coins:
for coin in coins:
print(f" 步骤{coin['step']}: 位置{coin['position']}, 价值+{coin['value']}")
print(f"\n陷阱触发: {len(traps)} 个,总损失: -{self.total_traps}")
if traps:
for trap in traps:
print(f" 步骤{trap['step']}: 位置{trap['position']}, 损失{trap['value']}")
if bosses:
print(f"\nBoss遭遇: {len(bosses)}")
for boss in bosses:
print(f" 步骤{boss['step']}: 位置{boss['position']}")
if mechanisms:
print(f"\n机关触发: {len(mechanisms)}")
for mech in mechanisms:
print(f" 步骤{mech['step']}: 位置{mech['position']}")
print()
print("-"*30)
print(f"最终总价值: {self.total_value} (金币: +{self.total_coins}, 陷阱: -{self.total_traps})")
print("-"*30)
print("="*50)
def get_resource_summary(self):
"""获取资源收集摘要(用于其他模块调用)"""
if not hasattr(self, 'collected_resources') or not self.collected_resources:
self.calculate_resources()
return {
'path_length': len(self.path),
'total_resources': len(self.collected_resources),
'total_coins': self.total_coins,
'total_traps': self.total_traps,
'total_value': self.total_value,
'collected_resources': self.collected_resources.copy()
}
if __name__ == '__main__':
obj = SourceCollector(filename="maze.csv")
obj.run()
path = obj.get_path()
print("\n路径坐标序列:")
for i, pos in enumerate(path):
print(f"步骤{i}: {pos}")
# 获取资源总结
summary = obj.get_resource_summary()
print(f"\n最终资源总价值: {summary['total_value']}")
# 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 = _