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()