maze_python/greedy_resource_collector.py
2025-07-01 10:12:59 +08:00

449 lines
15 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 copy
from collections import deque
class GreedyResourceCollector:
"""
基于贪心算法的资源收集器
每次移动时选择3x3视野范围内最高价值的资源
只能进行上下左右移动
"""
def __init__(self, maze, start_pos=None, end_pos=None):
"""
初始化贪心资源收集器
Args:
maze: 迷宫地图2D列表
start_pos: 起始位置 (row, col)如果为None则自动寻找
end_pos: 目标位置 (row, col)如果为None则自动寻找
"""
self.original_maze = copy.deepcopy(maze)
self.maze = copy.deepcopy(maze)
self.rows = len(maze)
self.cols = len(maze[0]) if self.rows > 0 else 0
# 寻找起始位置和目标位置
self.start_pos = start_pos or self._find_position('s')
self.end_pos = end_pos or self._find_position('e')
if not self.start_pos:
raise ValueError("无法找到起始位置 's'")
if not self.end_pos:
raise ValueError("无法找到目标位置 'e'")
self.current_pos = self.start_pos
self.path = [self.start_pos]
self.collected_resources = []
self.total_value = 0
self.visited_resources = set()
print(f"起始位置: {self.start_pos}")
print(f"目标位置: {self.end_pos}")
def _find_position(self, target):
"""寻找地图中指定字符的位置"""
for i in range(self.rows):
for j in range(self.cols):
if self.maze[i][j].lower() == target.lower():
return (i, j)
return None
def get_3x3_vision(self, pos):
"""
获取以pos为中心的3x3视野范围内的所有单元格
Args:
pos: 当前位置 (row, col)
Returns:
dict: {(row, col): cell_value} 形式的字典
"""
row, col = pos
vision = {}
# 遍历3x3范围
for dr in range(-1, 2):
for dc in range(-1, 2):
new_row, new_col = row + dr, col + dc
# 检查边界
if 0 <= new_row < self.rows and 0 <= new_col < self.cols:
vision[(new_row, new_col)] = self.maze[new_row][new_col]
return vision
def get_adjacent_cells(self, pos):
"""
获取当前位置的上下左右四个相邻位置
Args:
pos: 当前位置 (row, col)
Returns:
list: 可移动的相邻位置列表
"""
row, col = pos
adjacent = []
# 上下左右四个方向
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
for dr, dc in directions:
new_row, new_col = row + dr, col + dc
# 检查边界和可移动性
if (0 <= new_row < self.rows and
0 <= new_col < self.cols and
self.can_move_to((new_row, new_col))):
adjacent.append((new_row, new_col))
return adjacent
def can_move_to(self, pos):
"""
检查是否可以移动到指定位置
Args:
pos: 目标位置 (row, col)
Returns:
bool: 是否可以移动
"""
row, col = pos
cell = self.maze[row][col]
# 不能移动到墙壁
if cell == '1':
return False
return True
def evaluate_resource_value(self, cell):
"""
评估资源的价值
Args:
cell: 单元格内容
Returns:
int: 资源价值,正数表示收益,负数表示损失
"""
if cell.startswith('g'):
# 金币资源,提取数值
try:
return int(cell[1:])
except ValueError:
return 0
elif cell.startswith('t'):
# 陷阱资源,提取数值并取负
try:
return -int(cell[1:])
except ValueError:
return 0
else:
# 其他类型单元格没有资源价值
return 0
def find_best_resource_in_vision(self):
"""
在3x3视野范围内找到价值最高的可到达资源
如果视野内没有正价值资源,则考虑移动到更有利的位置
Returns:
tuple: (最佳资源位置, 资源价值) 或 (None, 0)
"""
vision = self.get_3x3_vision(self.current_pos)
best_pos = None
best_value = float('-inf')
# 首先只考虑正价值资源
for pos, cell in vision.items():
# 跳过已访问的资源
if pos in self.visited_resources:
continue
# 跳过当前位置
if pos == self.current_pos:
continue
# 跳过不可移动的位置
if not self.can_move_to(pos):
continue
# 检查是否为资源
value = self.evaluate_resource_value(cell)
if value > 0 and value > best_value: # 只考虑正价值资源
# 确保可以到达这个位置
path_to_resource = self.find_path_to_target(pos)
if path_to_resource: # 可以到达
best_value = value
best_pos = pos
# 如果视野内没有正价值资源,考虑负价值资源(陷阱)
if best_pos is None:
for pos, cell in vision.items():
if pos in self.visited_resources or pos == self.current_pos:
continue
if not self.can_move_to(pos):
continue
value = self.evaluate_resource_value(cell)
if value < 0 and value > best_value: # 选择损失最小的陷阱
path_to_resource = self.find_path_to_target(pos)
if path_to_resource:
best_value = value
best_pos = pos
# 如果视野内完全没有资源,寻找最近的正价值资源
if best_pos is None:
best_pos, best_value = self.find_nearest_valuable_resource()
return best_pos, best_value if best_pos else 0
def find_nearest_valuable_resource(self):
"""
在整个地图上寻找最近的高价值正资源
Returns:
tuple: (最佳资源位置, 资源价值) 或 (None, 0)
"""
best_pos = None
best_score = float('-inf')
for i in range(self.rows):
for j in range(self.cols):
pos = (i, j)
cell = self.maze[i][j]
# 跳过已访问的资源
if pos in self.visited_resources:
continue
# 跳过当前位置
if pos == self.current_pos:
continue
# 检查是否为正价值资源
value = self.evaluate_resource_value(cell)
if value > 0: # 只考虑正价值资源
# 计算到达该资源的路径
path_to_resource = self.find_path_to_target(pos)
if path_to_resource:
# 计算性价比:价值/距离
distance = len(path_to_resource)
score = value / distance
if score > best_score:
best_score = score
best_pos = pos
if best_pos:
value = self.evaluate_resource_value(self.maze[best_pos[0]][best_pos[1]])
return best_pos, value
return None, 0
def find_path_to_target(self, target_pos):
"""
使用BFS找到到目标位置的最短路径
Args:
target_pos: 目标位置 (row, col)
Returns:
list: 从当前位置到目标位置的路径(不包含当前位置)
"""
if self.current_pos == target_pos:
return []
queue = deque([(self.current_pos, [])])
visited = {self.current_pos}
while queue:
pos, path = queue.popleft()
# 获取相邻位置
for next_pos in self.get_adjacent_cells(pos):
if next_pos in visited:
continue
new_path = path + [next_pos]
# 找到目标
if next_pos == target_pos:
return new_path
visited.add(next_pos)
queue.append((next_pos, new_path))
return [] # 无法到达
def collect_resource(self, pos):
"""
收集指定位置的资源
Args:
pos: 资源位置 (row, col)
"""
row, col = pos
cell = self.maze[row][col]
value = self.evaluate_resource_value(cell)
if value != 0:
self.collected_resources.append({
'position': pos,
'type': cell,
'value': value
})
self.total_value += value
self.visited_resources.add(pos)
print(f"收集资源: 位置{pos}, 类型{cell}, 价值{value}, 总价值{self.total_value}")
def run_greedy_collection(self):
"""
运行贪心资源收集算法
Returns:
dict: 包含路径、收集的资源等信息
"""
print("开始贪心资源收集...")
while True:
# 在3x3视野内寻找最佳资源
best_resource_pos, best_value = self.find_best_resource_in_vision()
if best_resource_pos is None:
print("视野内没有更多资源可收集")
break
print(f"发现最佳资源: 位置{best_resource_pos}, 价值{best_value}")
# 计算到最佳资源的路径
path_to_resource = self.find_path_to_target(best_resource_pos)
if not path_to_resource:
print(f"无法到达资源位置{best_resource_pos}")
self.visited_resources.add(best_resource_pos) # 标记为无法到达
continue
# 移动到资源位置
for next_pos in path_to_resource:
self.current_pos = next_pos
self.path.append(next_pos)
print(f"移动到: {next_pos}")
# 收集资源
self.collect_resource(best_resource_pos)
print("资源收集完成!")
return self.get_collection_result()
def get_collection_result(self):
"""
获取收集结果
Returns:
dict: 包含路径、资源、统计信息的字典
"""
return {
'path': self.path.copy(),
'collected_resources': self.collected_resources.copy(),
'total_value': self.total_value,
'total_moves': len(self.path) - 1,
'resources_count': len(self.collected_resources),
'start_pos': self.start_pos,
'end_pos': self.end_pos,
'final_pos': self.current_pos
}
def print_result_summary(self):
"""打印收集结果摘要"""
result = self.get_collection_result()
print("\n=== 贪心资源收集结果摘要 ===")
print(f"起始位置: {result['start_pos']}")
print(f"最终位置: {result['final_pos']}")
print(f"总移动步数: {result['total_moves']}")
print(f"收集资源数量: {result['resources_count']}")
print(f"资源总价值: {result['total_value']}")
print("\n收集的资源详情:")
for i, resource in enumerate(result['collected_resources'], 1):
print(f" {i}. 位置{resource['position']}: {resource['type']} (价值: {resource['value']})")
print(f"\n完整移动路径: {' -> '.join(map(str, result['path']))}")
def visualize_path_on_maze(self):
"""
在迷宫上可视化移动路径
Returns:
list: 标记了路径的迷宫副本
"""
visual_maze = copy.deepcopy(self.original_maze)
# 标记路径
for i, pos in enumerate(self.path):
row, col = pos
if pos == self.start_pos:
visual_maze[row][col] = 'S' # 起点
elif pos == self.end_pos:
visual_maze[row][col] = 'E' # 终点
elif pos in [r['position'] for r in self.collected_resources]:
# 已收集的资源位置
visual_maze[row][col] = '*'
else:
# 路径点
visual_maze[row][col] = str(i % 10)
return visual_maze
def print_visual_maze(self):
"""打印可视化的迷宫"""
visual_maze = self.visualize_path_on_maze()
print("\n=== 路径可视化迷宫 ===")
print("S: 起点, E: 终点, *: 已收集资源, 数字: 路径步骤")
for row in visual_maze:
print(' '.join(f"{cell:>2}" for cell in row))
def demo_greedy_resource_collection():
"""演示贪心资源收集算法"""
# 创建一个示例迷宫
demo_maze = [
['s', '0', 'g5', '1', 't3'],
['0', '1', '0', '0', 'g2'],
['g3', '0', '1', 't2', '0'],
['0', 't1', '0', '0', 'g4'],
['1', '0', 'g1', '0', 'e']
]
print("=== 贪心资源收集算法演示 ===")
print("迷宫说明:")
print(" s: 起点, e: 终点")
print(" g数字: 金币资源 (正收益)")
print(" t数字: 陷阱资源 (负收益)")
print(" 0: 可通行路径, 1: 墙壁")
print("\n原始迷宫:")
for row in demo_maze:
print(' '.join(f"{cell:>2}" for cell in row))
# 创建贪心收集器并运行
collector = GreedyResourceCollector(demo_maze)
result = collector.run_greedy_collection()
# 打印结果
collector.print_result_summary()
collector.print_visual_maze()
return collector, result
if __name__ == "__main__":
# 运行演示
collector, result = demo_greedy_resource_collection()