381 lines
13 KiB
Python
381 lines
13 KiB
Python
"""
|
||
3x3视野贪心资源收集算法
|
||
|
||
该模块实现了一个基于3x3视野的贪心算法,用于在迷宫中收集资源。
|
||
算法特点:
|
||
1. 每次移动时只考虑当前位置周围3x3范围内的资源
|
||
2. 优先选择正价值资源(金币),如果没有则选择损失最小的负价值资源(陷阱)
|
||
3. 只能进行上下左右四个方向的移动
|
||
4. 当视野内没有资源时,会进行探索性移动
|
||
5. 避免无限循环,当连续多步无法找到新资源时会自动停止
|
||
|
||
使用方法:
|
||
```python
|
||
from greedy_3x3_algorithm import Greedy3x3Algorithm
|
||
|
||
# 创建迷宫(二维数组,[y][x]格式)
|
||
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']
|
||
]
|
||
|
||
# 创建算法实例并运行
|
||
algorithm = Greedy3x3Algorithm(maze)
|
||
result = algorithm.run()
|
||
|
||
# 获取结果
|
||
print(f"总价值: {result['total_value']}")
|
||
print(f"路径: {result['path']}")
|
||
```
|
||
"""
|
||
|
||
import copy
|
||
from collections import deque
|
||
|
||
|
||
class Greedy3x3Algorithm:
|
||
"""
|
||
3x3视野贪心资源收集算法
|
||
|
||
该算法在每个位置只考虑周围3x3范围内的资源,选择价值最高的资源进行收集。
|
||
如果视野内没有资源,则进行探索性移动。
|
||
"""
|
||
|
||
def __init__(self, maze, start_pos=None, end_pos=None, debug=False):
|
||
"""
|
||
初始化算法
|
||
|
||
Args:
|
||
maze: 二维列表,表示迷宫地图 ([y][x]格式)
|
||
start_pos: 起始位置 (x, y),默认自动寻找's'
|
||
end_pos: 目标位置 (x, y),默认自动寻找'e'
|
||
debug: 是否输出调试信息
|
||
"""
|
||
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.debug = debug
|
||
|
||
# 寻找起始位置和目标位置
|
||
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()
|
||
self.explored_positions = set([self.start_pos])
|
||
|
||
if self.debug:
|
||
print(f"3x3视野贪心算法初始化")
|
||
print(f"迷宫大小: {self.rows}x{self.cols}")
|
||
print(f"起始位置: {self.start_pos}")
|
||
print(f"目标位置: {self.end_pos}")
|
||
|
||
def _find_position(self, target):
|
||
"""寻找地图中指定字符的位置,返回(x, y)格式"""
|
||
for y in range(self.rows):
|
||
for x in range(self.cols):
|
||
if self.maze[y][x].lower() == target.lower():
|
||
return (x, y)
|
||
return None
|
||
|
||
def get_3x3_vision(self, pos):
|
||
"""
|
||
获取以pos为中心的3x3视野范围内的所有单元格
|
||
|
||
Args:
|
||
pos: 当前位置 (x, y)
|
||
|
||
Returns:
|
||
dict: {(x, y): cell_value} 形式的字典
|
||
"""
|
||
x, y = pos
|
||
vision = {}
|
||
|
||
# 遍历3x3范围
|
||
for dx in range(-1, 2):
|
||
for dy in range(-1, 2):
|
||
new_x, new_y = x + dx, y + dy
|
||
|
||
# 检查边界
|
||
if 0 <= new_x < self.cols and 0 <= new_y < self.rows:
|
||
vision[(new_x, new_y)] = self.maze[new_y][new_x]
|
||
|
||
return vision
|
||
|
||
def get_adjacent_positions(self, pos):
|
||
"""
|
||
获取当前位置的上下左右四个相邻位置
|
||
|
||
Args:
|
||
pos: 当前位置 (x, y)
|
||
|
||
Returns:
|
||
list: 可移动的相邻位置列表
|
||
"""
|
||
x, y = pos
|
||
adjacent = []
|
||
|
||
# 上下左右四个方向
|
||
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] # 上、下、左、右
|
||
|
||
for dx, dy in directions:
|
||
new_x, new_y = x + dx, y + dy
|
||
|
||
# 检查边界和可移动性
|
||
if (0 <= new_x < self.cols and
|
||
0 <= new_y < self.rows and
|
||
self._can_move_to((new_x, new_y))):
|
||
adjacent.append((new_x, new_y))
|
||
|
||
return adjacent
|
||
|
||
def _can_move_to(self, pos):
|
||
"""检查是否可以移动到指定位置"""
|
||
x, y = pos
|
||
cell = self.maze[y][x]
|
||
return cell != '1' # 不能移动到墙壁
|
||
|
||
def _evaluate_resource_value(self, cell):
|
||
"""评估资源的价值"""
|
||
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)
|
||
adjacent_positions = self.get_adjacent_positions(self.current_pos)
|
||
|
||
best_pos = None
|
||
best_value = float('-inf')
|
||
|
||
# 只考虑相邻且在视野内的位置
|
||
for pos in adjacent_positions:
|
||
if pos in vision and pos not in self.visited_resources:
|
||
cell = vision[pos]
|
||
value = self._evaluate_resource_value(cell)
|
||
|
||
if value != 0 and value > best_value:
|
||
best_value = value
|
||
best_pos = pos
|
||
|
||
return best_pos, best_value if best_pos else 0
|
||
|
||
def _find_exploration_target(self):
|
||
"""当视野内没有资源时,寻找探索目标"""
|
||
adjacent = self.get_adjacent_positions(self.current_pos)
|
||
|
||
# 优先选择未探索的位置
|
||
unexplored = [pos for pos in adjacent if pos not in self.explored_positions]
|
||
if unexplored:
|
||
return unexplored[0]
|
||
|
||
# 如果所有相邻位置都探索过,选择任意一个
|
||
if adjacent:
|
||
return adjacent[0]
|
||
|
||
return None
|
||
|
||
def _collect_resource(self, pos):
|
||
"""收集指定位置的资源"""
|
||
x, y = pos
|
||
cell = self.maze[y][x]
|
||
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)
|
||
|
||
if self.debug:
|
||
print(f"收集资源: 位置{pos}, 类型{cell}, 价值{value}, 总价值{self.total_value}")
|
||
|
||
def run(self, max_moves=1000, max_stuck=20):
|
||
"""
|
||
运行3x3视野贪心资源收集算法
|
||
|
||
Args:
|
||
max_moves: 最大移动步数,防止无限循环
|
||
max_stuck: 连续无资源的最大步数
|
||
|
||
Returns:
|
||
dict: 包含路径、收集的资源等信息的结果字典
|
||
"""
|
||
if self.debug:
|
||
print("\\n开始3x3视野贪心资源收集...")
|
||
|
||
moves = 0
|
||
stuck_count = 0
|
||
|
||
while moves < max_moves and stuck_count < max_stuck:
|
||
moves += 1
|
||
|
||
# 在3x3视野内寻找最佳资源
|
||
best_resource_pos, best_value = self._find_best_resource_in_vision()
|
||
|
||
if best_resource_pos is not None:
|
||
if self.debug:
|
||
print(f"第{moves}步: 发现视野内资源 位置{best_resource_pos}, 价值{best_value}")
|
||
|
||
# 移动到资源位置并收集
|
||
self.current_pos = best_resource_pos
|
||
self.path.append(best_resource_pos)
|
||
self.explored_positions.add(best_resource_pos)
|
||
self._collect_resource(best_resource_pos)
|
||
|
||
stuck_count = 0 # 重置无资源计数
|
||
else:
|
||
# 视野内没有资源,进行探索性移动
|
||
exploration_target = self._find_exploration_target()
|
||
|
||
if exploration_target:
|
||
if self.debug:
|
||
print(f"第{moves}步: 视野内无资源,探索移动到 {exploration_target}")
|
||
self.current_pos = exploration_target
|
||
self.path.append(exploration_target)
|
||
self.explored_positions.add(exploration_target)
|
||
stuck_count += 1
|
||
else:
|
||
if self.debug:
|
||
print(f"第{moves}步: 无法进行任何移动,结束收集")
|
||
break
|
||
|
||
if self.debug:
|
||
if moves >= max_moves:
|
||
print(f"达到最大移动步数 {max_moves},结束收集")
|
||
elif stuck_count >= max_stuck:
|
||
print(f"连续 {max_stuck} 步未找到资源,结束收集")
|
||
print("3x3视野资源收集完成!")
|
||
|
||
return self._get_result()
|
||
|
||
def _get_result(self):
|
||
"""获取算法执行结果"""
|
||
return {
|
||
'path': self.path.copy(),
|
||
'path_yx_format': [(y, x) for (x, y) in self.path], # 兼容现有代码的(y,x)格式
|
||
'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,
|
||
'explored_positions_count': len(self.explored_positions),
|
||
'algorithm_name': '3x3视野贪心算法'
|
||
}
|
||
|
||
def get_marked_maze(self):
|
||
"""
|
||
获取标记了路径的迷宫
|
||
|
||
Returns:
|
||
list: 标记后的迷宫,S=起点, E=终点, *=已收集资源, .=路径
|
||
"""
|
||
marked_maze = copy.deepcopy(self.original_maze)
|
||
|
||
# 标记路径点
|
||
for i, (x, y) in enumerate(self.path):
|
||
if (x, y) == self.start_pos:
|
||
marked_maze[y][x] = 'S' # 起点
|
||
elif (x, y) == self.end_pos:
|
||
marked_maze[y][x] = 'E' # 终点
|
||
elif (x, y) in [r['position'] for r in self.collected_resources]:
|
||
marked_maze[y][x] = '*' # 已收集资源
|
||
else:
|
||
marked_maze[y][x] = '.' # 路径点
|
||
|
||
return marked_maze
|
||
|
||
def print_result(self):
|
||
"""打印算法执行结果"""
|
||
result = self._get_result()
|
||
|
||
print("\\n=== 3x3视野贪心算法执行结果 ===")
|
||
print(f"起始位置: {result['start_pos']}")
|
||
print(f"最终位置: {result['final_pos']}")
|
||
print(f"总移动步数: {result['total_moves']}")
|
||
print(f"探索位置数: {result['explored_positions_count']}")
|
||
print(f"收集资源数量: {result['resources_count']}")
|
||
print(f"资源总价值: {result['total_value']}")
|
||
|
||
if result['collected_resources']:
|
||
print("\\n收集的资源详情:")
|
||
for i, resource in enumerate(result['collected_resources'], 1):
|
||
print(f" {i}. 位置{resource['position']}: {resource['type']} (价值: {resource['value']})")
|
||
else:
|
||
print("\\n未收集到任何资源")
|
||
|
||
# 显示标记后的迷宫
|
||
marked_maze = self.get_marked_maze()
|
||
print("\\n标记路径后的迷宫:")
|
||
print("S: 起点, E: 终点, *: 已收集资源, .: 路径")
|
||
for row in marked_maze:
|
||
print(' '.join(f"{cell:>2}" for cell in row))
|
||
|
||
|
||
def demo():
|
||
"""演示函数"""
|
||
# 创建示例迷宫
|
||
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("=== 3x3视野贪心算法演示 ===")
|
||
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))
|
||
|
||
# 运行算法
|
||
algorithm = Greedy3x3Algorithm(demo_maze, debug=True)
|
||
result = algorithm.run()
|
||
|
||
# 打印结果
|
||
algorithm.print_result()
|
||
|
||
return algorithm, result
|
||
|
||
|
||
if __name__ == "__main__":
|
||
demo()
|