贪心搜索
This commit is contained in:
parent
ff217ece77
commit
712160462e
267
README_3x3_GREEDY.md
Normal file
267
README_3x3_GREEDY.md
Normal file
@ -0,0 +1,267 @@
|
||||
# 3x3视野贪心资源收集算法使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
本项目实现了一个基于3x3视野的贪心算法,用于在迷宫环境中收集资源。该算法的核心特点是:
|
||||
|
||||
- **视野限制**:每次移动时只考虑当前位置周围3x3范围内的单元格
|
||||
- **贪心策略**:在可见范围内选择价值最高的资源
|
||||
- **移动限制**:只能进行上下左右四个方向的移动
|
||||
- **智能探索**:当视野内没有资源时,会进行探索性移动寻找新资源
|
||||
|
||||
## 文件说明
|
||||
|
||||
### 主要文件
|
||||
|
||||
1. **`greedy_3x3_algorithm.py`** - 独立的3x3视野贪心算法模块
|
||||
2. **`tanxin.py`** - 原有的贪心算法实现,已集成新的3x3算法
|
||||
3. **`greedy_resource_collector.py`** - 完整版本的贪心收集器(支持全局搜索)
|
||||
4. **`strict_3x3_greedy.py`** - 严格的3x3视野算法演示
|
||||
|
||||
### 演示文件
|
||||
|
||||
- **`greedy_resource_collector.py`** - 包含演示的完整贪心算法
|
||||
- **`strict_3x3_greedy.py`** - 专门的3x3算法演示
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 基本使用
|
||||
|
||||
```python
|
||||
from greedy_3x3_algorithm import Greedy3x3Algorithm
|
||||
|
||||
# 创建迷宫(二维数组,[y][x]格式)
|
||||
maze = [
|
||||
['s', '0', 'g5', '1', 't3'], # s=起点, g5=价值5的金币, 1=墙壁, t3=损失3的陷阱
|
||||
['0', '1', '0', '0', 'g2'], # 0=可通行路径
|
||||
['g3', '0', '1', 't2', '0'],
|
||||
['0', 't1', '0', '0', 'g4'],
|
||||
['1', '0', 'g1', '0', 'e'] # e=终点
|
||||
]
|
||||
|
||||
# 创建算法实例
|
||||
algorithm = Greedy3x3Algorithm(maze, debug=True)
|
||||
|
||||
# 运行算法
|
||||
result = algorithm.run()
|
||||
|
||||
# 查看结果
|
||||
print(f"总价值: {result['total_value']}")
|
||||
print(f"收集资源数量: {result['resources_count']}")
|
||||
print(f"移动步数: {result['total_moves']}")
|
||||
|
||||
# 打印详细结果
|
||||
algorithm.print_result()
|
||||
```
|
||||
|
||||
### 2. 在现有项目中集成
|
||||
|
||||
```python
|
||||
from tanxin import Greedy3x3ResourceCollector
|
||||
|
||||
# 使用现有的迷宫数据
|
||||
map_data = your_maze_data # 二维数组格式
|
||||
|
||||
# 创建收集器
|
||||
collector = Greedy3x3ResourceCollector(map_data)
|
||||
|
||||
# 运行收集算法
|
||||
result = collector.run_3x3_greedy_collection()
|
||||
|
||||
# 获取兼容格式的路径 (y, x格式)
|
||||
path_yx = collector.get_path()
|
||||
total_reward = collector.get_total_reward()
|
||||
marked_map = collector.add_path_to_map()
|
||||
```
|
||||
|
||||
### 3. 运行演示
|
||||
|
||||
```bash
|
||||
# 运行独立算法演示
|
||||
python greedy_3x3_algorithm.py
|
||||
|
||||
# 运行集成演示
|
||||
echo "2" | python tanxin.py
|
||||
|
||||
# 运行比较演示
|
||||
python strict_3x3_greedy.py
|
||||
```
|
||||
|
||||
## 算法详解
|
||||
|
||||
### 地图元素说明
|
||||
|
||||
- **`s`** - 起点 (Start)
|
||||
- **`e`** - 终点 (End)
|
||||
- **`g数字`** - 金币资源,数字表示价值(如 `g5` = 价值5的金币)
|
||||
- **`t数字`** - 陷阱资源,数字表示损失(如 `t3` = 损失3的陷阱)
|
||||
- **`0`** - 可通行的路径
|
||||
- **`1`** - 墙壁,无法通过
|
||||
- **`l`** - 锁/机关
|
||||
- **`b`** - Boss
|
||||
|
||||
### 算法流程
|
||||
|
||||
1. **初始化**:从起点开始,初始化路径和收集状态
|
||||
2. **视野扫描**:获取当前位置3x3范围内的所有单元格
|
||||
3. **资源评估**:
|
||||
- 优先选择正价值资源(金币)
|
||||
- 如果没有正价值资源,选择损失最小的负价值资源(陷阱)
|
||||
4. **移动决策**:
|
||||
- 如果找到资源,移动到该位置并收集
|
||||
- 如果没有资源,进行探索性移动到未访问的位置
|
||||
5. **循环执行**:重复步骤2-4直到满足停止条件
|
||||
|
||||
### 停止条件
|
||||
|
||||
- 达到最大移动步数(默认1000步)
|
||||
- 连续多步(默认20步)无法找到新资源
|
||||
- 无法进行任何移动
|
||||
|
||||
## 算法参数
|
||||
|
||||
### Greedy3x3Algorithm 参数
|
||||
|
||||
```python
|
||||
algorithm = Greedy3x3Algorithm(
|
||||
maze, # 必需:迷宫地图
|
||||
start_pos=None, # 可选:起始位置(x,y),默认自动寻找
|
||||
end_pos=None, # 可选:目标位置(x,y),默认自动寻找
|
||||
debug=False # 可选:是否输出调试信息
|
||||
)
|
||||
|
||||
result = algorithm.run(
|
||||
max_moves=1000, # 最大移动步数
|
||||
max_stuck=20 # 连续无资源的最大步数
|
||||
)
|
||||
```
|
||||
|
||||
## 结果格式
|
||||
|
||||
算法执行后返回的结果字典包含:
|
||||
|
||||
```python
|
||||
{
|
||||
'path': [(x1,y1), (x2,y2), ...], # 移动路径 (x,y格式)
|
||||
'path_yx_format': [(y1,x1), (y2,x2), ...], # 移动路径 (y,x格式,兼容现有代码)
|
||||
'collected_resources': [ # 收集的资源详情
|
||||
{
|
||||
'position': (x, y),
|
||||
'type': 'g5',
|
||||
'value': 5
|
||||
},
|
||||
...
|
||||
],
|
||||
'total_value': 15, # 资源总价值
|
||||
'total_moves': 25, # 总移动步数
|
||||
'resources_count': 8, # 收集资源数量
|
||||
'start_pos': (0, 0), # 起始位置
|
||||
'end_pos': (4, 4), # 目标位置
|
||||
'final_pos': (2, 3), # 最终位置
|
||||
'explored_positions_count': 15, # 探索位置数量
|
||||
'algorithm_name': '3x3视野贪心算法'
|
||||
}
|
||||
```
|
||||
|
||||
## 性能特点
|
||||
|
||||
### 优势
|
||||
|
||||
1. **局部最优**:在有限视野内做出最优决策
|
||||
2. **探索能力**:能够智能探索未知区域
|
||||
3. **资源优先**:优先收集高价值资源,避免低价值陷阱
|
||||
4. **防死循环**:具备多种机制防止无限循环
|
||||
|
||||
### 限制
|
||||
|
||||
1. **视野限制**:可能错过视野外的高价值资源
|
||||
2. **局部陷阱**:可能陷入局部最优解
|
||||
3. **路径效率**:为了收集资源,路径可能不是最短的
|
||||
|
||||
## 测试用例
|
||||
|
||||
项目包含多个测试迷宫:
|
||||
|
||||
### 简单测试迷宫
|
||||
|
||||
```python
|
||||
simple_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']
|
||||
]
|
||||
```
|
||||
|
||||
### 复杂测试迷宫
|
||||
|
||||
```python
|
||||
complex_maze = [
|
||||
['s', '0', 'g5', '1', 't3', '0', 'g8'],
|
||||
['0', '1', '0', '0', 'g2', '1', '0'],
|
||||
['g3', '0', '1', 't2', '0', '0', 'g6'],
|
||||
['0', 't1', '0', '0', 'g4', '1', '0'],
|
||||
['1', '0', 'g1', '0', '0', '0', 't5'],
|
||||
['0', 'g7', '0', '1', '0', 'g9', '0'],
|
||||
['t4', '0', '0', '0', '1', '0', 'e']
|
||||
]
|
||||
```
|
||||
|
||||
## 扩展开发
|
||||
|
||||
### 自定义评估函数
|
||||
|
||||
可以通过继承 `Greedy3x3Algorithm` 类来自定义资源评估逻辑:
|
||||
|
||||
```python
|
||||
class CustomGreedy3x3(Greedy3x3Algorithm):
|
||||
def _evaluate_resource_value(self, cell):
|
||||
# 自定义评估逻辑
|
||||
if cell.startswith('special'):
|
||||
return 100 # 特殊资源高价值
|
||||
return super()._evaluate_resource_value(cell)
|
||||
```
|
||||
|
||||
### 自定义移动策略
|
||||
|
||||
```python
|
||||
class CustomGreedy3x3(Greedy3x3Algorithm):
|
||||
def _find_exploration_target(self):
|
||||
# 自定义探索策略
|
||||
adjacent = self.get_adjacent_positions(self.current_pos)
|
||||
# 选择最靠近终点的位置
|
||||
if adjacent:
|
||||
return min(adjacent, key=lambda pos:
|
||||
abs(pos[0] - self.end_pos[0]) + abs(pos[1] - self.end_pos[1]))
|
||||
return None
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 算法为什么会在某些位置反复移动?
|
||||
|
||||
A: 这是因为算法在视野内找不到新资源时,会进行探索性移动。连续20步无资源后会自动停止。
|
||||
|
||||
### Q: 如何提高算法的收集效率?
|
||||
|
||||
A: 可以调整参数:
|
||||
- 减小 `max_stuck` 参数,减少无效探索
|
||||
- 增加迷宫中的资源密度
|
||||
- 优化迷宫布局,减少死胡同
|
||||
|
||||
### Q: 算法支持什么样的迷宫格式?
|
||||
|
||||
A: 支持二维列表格式,使用 `[y][x]` 索引方式。单元格内容为字符串。
|
||||
|
||||
### Q: 如何集成到现有项目?
|
||||
|
||||
A: 可以使用 `tanxin.py` 中的 `Greedy3x3ResourceCollector` 类,它与现有代码兼容。
|
||||
|
||||
## 版本信息
|
||||
|
||||
- **版本**: 1.0
|
||||
- **作者**: GitHub Copilot
|
||||
- **创建日期**: 2025年1月
|
||||
- **Python版本**: 3.6+
|
||||
- **依赖**: 无额外依赖,使用Python标准库
|
@ -57,6 +57,9 @@ def get_button_positions(maze_display_size=MAZE_SIZE):
|
||||
'next_step_button': (control_panel_x, 200),
|
||||
'reset_path_button': (control_panel_x + 120, 200),
|
||||
'auto_play_button': (control_panel_x + 250, 200),
|
||||
# 贪心搜索按钮
|
||||
'greedy_search_button': (control_panel_x + 380, 200),
|
||||
'greedy_auto_play_button': (control_panel_x + 500, 200),
|
||||
# 历史迭代控制按钮
|
||||
'history_prev_button': (control_panel_x, 260),
|
||||
'history_next_button': (control_panel_x + 120, 260),
|
||||
@ -67,5 +70,6 @@ def get_button_positions(maze_display_size=MAZE_SIZE):
|
||||
'history_progress_text': (control_panel_x, 350),
|
||||
'hint_text': (control_panel_x, 380),
|
||||
'shortcut_text': (control_panel_x, 410),
|
||||
'save_list_area': (control_panel_x, 440, 400, 330) # x, y, width, height - 增加高度到330
|
||||
'greedy_info_text': (control_panel_x, 440), # 贪心算法信息显示位置
|
||||
'save_list_area': (control_panel_x, 470, 400, 300) # x, y, width, height - 调整位置和高度
|
||||
}
|
||||
|
380
greedy_3x3_algorithm.py
Normal file
380
greedy_3x3_algorithm.py
Normal file
@ -0,0 +1,380 @@
|
||||
"""
|
||||
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()
|
448
greedy_resource_collector.py
Normal file
448
greedy_resource_collector.py
Normal file
@ -0,0 +1,448 @@
|
||||
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()
|
75
main.py
75
main.py
@ -7,6 +7,7 @@ from draw import Button, Toast
|
||||
from save_ui import SaveLoadUI
|
||||
from boss_fight_ui import BossFightUI
|
||||
from mechanism_ui import MechanismUI
|
||||
from greedy_3x3_algorithm import Greedy3x3Algorithm
|
||||
from config import *
|
||||
import sys
|
||||
import os
|
||||
@ -50,6 +51,10 @@ def create_buttons(button_positions):
|
||||
button_reset_path = Button(pygame.rect.Rect(*button_positions['reset_path_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
button_auto_play = Button(pygame.rect.Rect(*button_positions['auto_play_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
|
||||
# 贪心搜索按钮
|
||||
button_greedy_search = Button(pygame.rect.Rect(*button_positions['greedy_search_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
button_greedy_auto_play = Button(pygame.rect.Rect(*button_positions['greedy_auto_play_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
|
||||
# 历史迭代控制按钮
|
||||
button_history_prev = Button(pygame.rect.Rect(*button_positions['history_prev_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
button_history_next = Button(pygame.rect.Rect(*button_positions['history_next_button'], *BUTTON_CONTROL_SIZE), None)
|
||||
@ -63,6 +68,8 @@ def create_buttons(button_positions):
|
||||
'next_step': button_next_step,
|
||||
'reset_path': button_reset_path,
|
||||
'auto_play': button_auto_play,
|
||||
'greedy_search': button_greedy_search,
|
||||
'greedy_auto_play': button_greedy_auto_play,
|
||||
'history_prev': button_history_prev,
|
||||
'history_next': button_history_next,
|
||||
'history_auto': button_history_auto,
|
||||
@ -95,6 +102,7 @@ if __name__ == "__main__":
|
||||
mes4 = Toast("存档加载成功", UI_WIDTH, UI_HEIGHT, font=textFont)
|
||||
mes5 = Toast("加载失败", UI_WIDTH, UI_HEIGHT, font=textFont)
|
||||
mes_boss = Toast("遇到Boss!准备战斗!", UI_WIDTH, UI_HEIGHT, font=textFont, duration=3, color=(255, 255, 0), bg_color=(255, 0, 0))
|
||||
mes_greedy = Toast("贪心搜索完成!", UI_WIDTH, UI_HEIGHT, font=textFont, duration=3, color=(255, 255, 255), bg_color=(0, 128, 0))
|
||||
|
||||
# 创建存档界面
|
||||
save_ui = SaveLoadUI(textFont)
|
||||
@ -111,6 +119,11 @@ if __name__ == "__main__":
|
||||
auto_play_timer = 0
|
||||
auto_play_interval = AUTO_PLAY_INTERVAL
|
||||
|
||||
# 贪心算法控制变量
|
||||
greedy_auto_play = False
|
||||
greedy_auto_timer = 0
|
||||
greedy_auto_interval = AUTO_PLAY_INTERVAL
|
||||
|
||||
# 历史迭代控制变量
|
||||
history_auto_play = False
|
||||
history_auto_timer = 0
|
||||
@ -152,6 +165,15 @@ if __name__ == "__main__":
|
||||
auto_play = False # 遇到机关时停止自动播放
|
||||
auto_play_timer = 0
|
||||
|
||||
# 贪心算法自动播放逻辑
|
||||
if greedy_auto_play and hasattr(maze, 'greedy_path') and maze.greedy_path and not maze.show_history and not boss_fight_ui.is_showing and not mechanism_ui.is_showing:
|
||||
greedy_auto_timer += 1
|
||||
if greedy_auto_timer >= greedy_auto_interval:
|
||||
has_next = maze.next_greedy_step()
|
||||
if not has_next:
|
||||
greedy_auto_play = False # 贪心路径播放完成后停止自动播放
|
||||
greedy_auto_timer = 0
|
||||
|
||||
# 历史迭代自动播放逻辑
|
||||
if history_auto_play and len(maze.history_mazes) > 0 and maze.show_history:
|
||||
history_auto_timer += 1
|
||||
@ -188,6 +210,10 @@ if __name__ == "__main__":
|
||||
buttons['reset_path'].handle_event(event=event)
|
||||
buttons['auto_play'].handle_event(event=event)
|
||||
|
||||
# 贪心搜索按钮
|
||||
buttons['greedy_search'].handle_event(event=event)
|
||||
buttons['greedy_auto_play'].handle_event(event=event)
|
||||
|
||||
# 历史迭代控制按钮
|
||||
buttons['history_prev'].handle_event(event=event)
|
||||
buttons['history_next'].handle_event(event=event)
|
||||
@ -263,6 +289,18 @@ if __name__ == "__main__":
|
||||
auto_play = not auto_play
|
||||
auto_play_timer = 0
|
||||
|
||||
# 贪心搜索控制
|
||||
if buttons['greedy_search'].pressed == True and len(maze.grid) > 0:
|
||||
success = maze.run_greedy_search()
|
||||
if success:
|
||||
greedy_auto_play = False # 重新生成路径时停止自动播放
|
||||
mes_greedy.text = f"贪心搜索完成!收集{len(maze.greedy_result['collected_resources'])}个资源,总价值{maze.greedy_result['total_value']}"
|
||||
mes_greedy.show()
|
||||
|
||||
if buttons['greedy_auto_play'].pressed == True and hasattr(maze, 'greedy_path') and maze.greedy_path:
|
||||
greedy_auto_play = not greedy_auto_play
|
||||
greedy_auto_timer = 0
|
||||
|
||||
# 历史迭代控制
|
||||
if buttons['history_prev'].pressed == True and len(maze.history_mazes) > 0 and maze.show_history:
|
||||
maze.prev_history_step()
|
||||
@ -326,6 +364,18 @@ if __name__ == "__main__":
|
||||
# Ctrl+L 打开读档界面
|
||||
save_ui.update_save_list(maze)
|
||||
save_ui.toggle_save_list()
|
||||
# 贪心算法快捷键
|
||||
elif event.key == pygame.K_g and len(maze.grid) > 0:
|
||||
# G键 运行贪心搜索
|
||||
success = maze.run_greedy_search()
|
||||
if success:
|
||||
greedy_auto_play = False
|
||||
mes_greedy.text = f"贪心搜索完成!收集{len(maze.greedy_result['collected_resources'])}个资源,总价值{maze.greedy_result['total_value']}"
|
||||
mes_greedy.show()
|
||||
elif event.key == pygame.K_g and pygame.key.get_pressed()[pygame.K_LSHIFT] and hasattr(maze, 'greedy_path') and maze.greedy_path:
|
||||
# Shift+G 贪心自动播放
|
||||
greedy_auto_play = not greedy_auto_play
|
||||
greedy_auto_timer = 0
|
||||
|
||||
if event.type == QUIT:
|
||||
running = False
|
||||
@ -355,6 +405,25 @@ if __name__ == "__main__":
|
||||
# 显示当前步数信息
|
||||
progress_text = textFont.render(f"路径进度: {maze.path_step}/{len(maze.full_path)}", True, COLOR_BLACK)
|
||||
screen.blit(progress_text, button_positions['progress_text'])
|
||||
|
||||
# 绘制贪心搜索按钮(仅在有迷宫时显示)
|
||||
if len(maze.grid) > 0:
|
||||
# 绘制按钮背景
|
||||
pygame.draw.rect(screen, COLOR_GOLD, buttons['greedy_search'].rect)
|
||||
|
||||
# 绘制按钮文字
|
||||
greedy_text = textFont.render("贪心搜索", True, COLOR_BLACK)
|
||||
screen.blit(greedy_text, (buttons['greedy_search'].rect.x + 5, buttons['greedy_search'].rect.y + 15))
|
||||
|
||||
# 绘制贪心自动播放按钮(仅在有贪心路径时显示)
|
||||
if hasattr(maze, 'greedy_path') and maze.greedy_path:
|
||||
pygame.draw.rect(screen, COLOR_GREEN if greedy_auto_play else COLOR_GRAY, buttons['greedy_auto_play'].rect)
|
||||
greedy_auto_text = textFont.render("贪心播放" if not greedy_auto_play else "停止", True, COLOR_BLACK)
|
||||
screen.blit(greedy_auto_text, (buttons['greedy_auto_play'].rect.x + 5, buttons['greedy_auto_play'].rect.y + 15))
|
||||
|
||||
# 显示贪心算法信息
|
||||
greedy_info_text = textFont.render(maze.get_greedy_progress(), True, COLOR_BLACK)
|
||||
screen.blit(greedy_info_text, button_positions['greedy_info_text'])
|
||||
|
||||
# 绘制历史迭代控制按钮(仅在有历史且为历史模式时显示)
|
||||
if len(maze.history_mazes) > 0 and maze.show_history:
|
||||
@ -384,11 +453,14 @@ if __name__ == "__main__":
|
||||
|
||||
# 显示操作提示
|
||||
if len(maze.full_path) > 0 and not maze.show_history:
|
||||
hint_text = textFont.render("空格键: 下一步 | R键: 重置 | A键: 自动播放", True, COLOR_LIGHT_GRAY)
|
||||
hint_text = textFont.render("空格键: 下一步 | R键: 重置 | A键: 自动播放 | G键: 贪心搜索", True, COLOR_LIGHT_GRAY)
|
||||
screen.blit(hint_text, button_positions['hint_text'])
|
||||
elif len(maze.history_mazes) > 0 and maze.show_history:
|
||||
hint_text = textFont.render("←→键: 历史步骤 | P键: 自动播放 | H键: 切换模式", True, COLOR_LIGHT_GRAY)
|
||||
screen.blit(hint_text, button_positions['hint_text'])
|
||||
elif len(maze.grid) > 0:
|
||||
hint_text = textFont.render("G键: 运行贪心搜索 | Shift+G: 贪心自动播放", True, COLOR_LIGHT_GRAY)
|
||||
screen.blit(hint_text, button_positions['hint_text'])
|
||||
|
||||
# 显示快捷键提示
|
||||
shortcut_text = textFont.render("Ctrl+S: 保存JSON | Shift+S: 保存CSV | Ctrl+L: 读档", True, COLOR_LIGHT_GRAY)
|
||||
@ -400,6 +472,7 @@ if __name__ == "__main__":
|
||||
mes4.draw(screen=screen)
|
||||
mes5.draw(screen=screen)
|
||||
mes_boss.draw(screen=screen)
|
||||
mes_greedy.draw(screen=screen)
|
||||
|
||||
# 绘制存档界面(必须在最后绘制以显示在最上层)
|
||||
save_ui.draw(screen)
|
||||
|
124
maze.py
124
maze.py
@ -3,11 +3,12 @@ from maze_generator import MazeGenerator
|
||||
from SourceCollector import SourceCollector
|
||||
from tanxin import *
|
||||
from simple_save_manager import simple_save_manager
|
||||
from greedy_3x3_algorithm import Greedy3x3Algorithm
|
||||
from config import UI_WIDTH
|
||||
import time
|
||||
import random
|
||||
import json
|
||||
INPUT_DATA = "/home/guan/dev/python_dev/maze_python/saves/input/input_case_1.json"
|
||||
INPUT_DATA = "/Users/gary/dev/maze_python/saves/input_case_1.json"
|
||||
class Maze:
|
||||
def __init__(self, wall_size, maze_size, file_name):
|
||||
self.wall_size = wall_size
|
||||
@ -359,6 +360,10 @@ class Maze:
|
||||
|
||||
# 绘制迷宫边界线(动态位置)
|
||||
pygame.draw.line(screen, (0, 0, 0), (self.actual_display_size, 0), (self.actual_display_size, self.actual_display_size), 3)
|
||||
|
||||
# 绘制贪心路径
|
||||
if hasattr(self, 'greedy_path') and self.greedy_path and hasattr(self, 'greedy_step'):
|
||||
self._draw_greedy_path(screen, tile_size)
|
||||
|
||||
def toggle_history_mode(self):
|
||||
"""切换历史展示模式"""
|
||||
@ -414,8 +419,125 @@ class Maze:
|
||||
self.encountered_bosses = set()
|
||||
self.encountered_mechanisms = set()
|
||||
|
||||
# 重置贪心算法相关状态
|
||||
if hasattr(self, 'greedy_path'):
|
||||
delattr(self, 'greedy_path')
|
||||
if hasattr(self, 'greedy_result'):
|
||||
delattr(self, 'greedy_result')
|
||||
if hasattr(self, 'greedy_step'):
|
||||
delattr(self, 'greedy_step')
|
||||
if hasattr(self, 'is_greedy_path_complete'):
|
||||
delattr(self, 'is_greedy_path_complete')
|
||||
|
||||
# 显示相关状态
|
||||
self.grid = []
|
||||
|
||||
print("所有状态已重置")
|
||||
|
||||
def run_greedy_search(self):
|
||||
"""运行3x3视野贪心搜索算法"""
|
||||
if not self.grid:
|
||||
print("没有迷宫数据,无法运行贪心搜索")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 创建贪心算法实例
|
||||
algorithm = Greedy3x3Algorithm(self.grid, debug=True)
|
||||
|
||||
# 运行算法
|
||||
result = algorithm.run()
|
||||
|
||||
# 将结果转换为路径格式 (y, x)
|
||||
self.greedy_path = result['path_yx_format']
|
||||
self.greedy_result = result
|
||||
self.greedy_step = 0
|
||||
self.is_greedy_path_complete = False
|
||||
|
||||
print(f"贪心搜索完成!")
|
||||
print(f"收集资源数量: {result['resources_count']}")
|
||||
print(f"资源总价值: {result['total_value']}")
|
||||
print(f"移动步数: {result['total_moves']}")
|
||||
print(f"路径长度: {len(self.greedy_path)}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"贪心搜索失败: {e}")
|
||||
return False
|
||||
|
||||
def next_greedy_step(self):
|
||||
"""显示贪心路径的下一步"""
|
||||
if not hasattr(self, 'greedy_path') or not self.greedy_path:
|
||||
return False
|
||||
|
||||
if self.greedy_step < len(self.greedy_path):
|
||||
self.greedy_step += 1
|
||||
if self.greedy_step >= len(self.greedy_path):
|
||||
self.is_greedy_path_complete = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def reset_greedy_path(self):
|
||||
"""重置贪心路径显示"""
|
||||
self.greedy_step = 0
|
||||
self.is_greedy_path_complete = False
|
||||
|
||||
def get_greedy_progress(self):
|
||||
"""获取贪心路径进度信息"""
|
||||
if not hasattr(self, 'greedy_path') or not self.greedy_path:
|
||||
return "贪心路径: 未生成"
|
||||
|
||||
if hasattr(self, 'greedy_result'):
|
||||
result = self.greedy_result
|
||||
return (f"贪心路径: {self.greedy_step}/{len(self.greedy_path)} | "
|
||||
f"资源: {result['resources_count']} | "
|
||||
f"价值: {result['total_value']}")
|
||||
else:
|
||||
return f"贪心路径: {self.greedy_step}/{len(self.greedy_path)}"
|
||||
|
||||
def _draw_greedy_path(self, screen, tile_size):
|
||||
"""绘制贪心算法路径"""
|
||||
if not self.greedy_path:
|
||||
return
|
||||
|
||||
# 绘制已走过的路径
|
||||
for i in range(min(self.greedy_step, len(self.greedy_path))):
|
||||
y, x = self.greedy_path[i]
|
||||
|
||||
# 绘制路径点
|
||||
center = (x * tile_size + tile_size // 2, y * tile_size + tile_size // 2)
|
||||
|
||||
# 起点用绿色圆圈
|
||||
if i == 0:
|
||||
pygame.draw.circle(screen, (0, 255, 0), center, tile_size // 4, 3)
|
||||
# 当前位置用红色圆圈
|
||||
elif i == self.greedy_step - 1:
|
||||
pygame.draw.circle(screen, (255, 0, 0), center, tile_size // 4, 3)
|
||||
# 其他位置用蓝色小圆点
|
||||
else:
|
||||
pygame.draw.circle(screen, (0, 0, 255), center, tile_size // 6)
|
||||
|
||||
# 绘制路径连线
|
||||
if i > 0:
|
||||
prev_y, prev_x = self.greedy_path[i - 1]
|
||||
prev_center = (prev_x * tile_size + tile_size // 2, prev_y * tile_size + tile_size // 2)
|
||||
pygame.draw.line(screen, (100, 100, 255), prev_center, center, 2)
|
||||
|
||||
# 如果有贪心算法结果,绘制收集的资源位置
|
||||
if hasattr(self, 'greedy_result') and self.greedy_result:
|
||||
for resource in self.greedy_result['collected_resources']:
|
||||
pos_x, pos_y = resource['position'] # 注意:贪心算法返回的是(x, y)格式
|
||||
center = (pos_x * tile_size + tile_size // 2, pos_y * tile_size + tile_size // 2)
|
||||
|
||||
# 用金色圆圈标记已收集的资源
|
||||
if resource['value'] > 0:
|
||||
pygame.draw.circle(screen, (255, 215, 0), center, tile_size // 3, 2)
|
||||
else:
|
||||
pygame.draw.circle(screen, (255, 100, 100), center, tile_size // 3, 2)
|
||||
|
||||
# 显示资源价值
|
||||
font = pygame.font.SysFont(None, max(12, tile_size // 4))
|
||||
value_text = font.render(str(resource['value']), True, (255, 255, 255))
|
||||
text_rect = value_text.get_rect(center=center)
|
||||
screen.blit(value_text, text_rect)
|
||||
|
||||
|
337
strict_3x3_greedy.py
Normal file
337
strict_3x3_greedy.py
Normal file
@ -0,0 +1,337 @@
|
||||
import copy
|
||||
from collections import deque
|
||||
|
||||
class Strict3x3GreedyCollector:
|
||||
"""
|
||||
严格的3x3视野贪心资源收集器
|
||||
每次移动时只考虑3x3视野范围内的资源
|
||||
如果视野内没有资源,则随机移动探索
|
||||
"""
|
||||
|
||||
def __init__(self, maze, start_pos=None, end_pos=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()
|
||||
self.explored_positions = set([self.start_pos])
|
||||
|
||||
print(f"严格3x3视野模式")
|
||||
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视野范围内的所有单元格"""
|
||||
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):
|
||||
"""获取当前位置的上下左右四个相邻位置"""
|
||||
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):
|
||||
"""检查是否可以移动到指定位置"""
|
||||
row, col = pos
|
||||
cell = self.maze[row][col]
|
||||
# 不能移动到墙壁
|
||||
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_3x3_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
|
||||
|
||||
# 检查是否可以直接到达(相邻位置)
|
||||
if pos not in self.get_adjacent_cells(self.current_pos):
|
||||
continue
|
||||
|
||||
# 检查是否为资源
|
||||
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_cells(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):
|
||||
"""收集指定位置的资源"""
|
||||
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_strict_3x3_collection(self, max_moves=1000):
|
||||
"""
|
||||
运行严格3x3视野贪心资源收集算法
|
||||
|
||||
Args:
|
||||
max_moves: 最大移动步数,防止无限循环
|
||||
|
||||
Returns:
|
||||
dict: 包含路径、收集的资源等信息
|
||||
"""
|
||||
print("\\n开始严格3x3视野贪心资源收集...")
|
||||
|
||||
moves = 0
|
||||
stuck_count = 0 # 连续无法找到资源的次数
|
||||
max_stuck = 20 # 最大连续无资源次数
|
||||
|
||||
while moves < max_moves and stuck_count < max_stuck:
|
||||
moves += 1
|
||||
|
||||
# 在3x3视野内寻找最佳资源
|
||||
best_resource_pos, best_value = self.find_best_resource_in_3x3_vision()
|
||||
|
||||
if best_resource_pos is not None:
|
||||
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:
|
||||
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:
|
||||
print(f"第{moves}步: 无法进行任何移动,结束收集")
|
||||
break
|
||||
|
||||
if moves >= max_moves:
|
||||
print(f"达到最大移动步数 {max_moves},结束收集")
|
||||
elif stuck_count >= max_stuck:
|
||||
print(f"连续 {max_stuck} 步未找到资源,结束收集")
|
||||
|
||||
print("严格3x3视野资源收集完成!")
|
||||
return self.get_collection_result()
|
||||
|
||||
def get_collection_result(self):
|
||||
"""获取收集结果"""
|
||||
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,
|
||||
'explored_positions': len(self.explored_positions)
|
||||
}
|
||||
|
||||
def print_result_summary(self):
|
||||
"""打印收集结果摘要"""
|
||||
result = self.get_collection_result()
|
||||
|
||||
print("\\n=== 严格3x3视野贪心收集结果摘要 ===")
|
||||
print(f"起始位置: {result['start_pos']}")
|
||||
print(f"最终位置: {result['final_pos']}")
|
||||
print(f"总移动步数: {result['total_moves']}")
|
||||
print(f"探索位置数: {result['explored_positions']}")
|
||||
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']})")
|
||||
|
||||
# 显示路径的关键点
|
||||
path_points = result['path']
|
||||
if len(path_points) <= 10:
|
||||
path_str = ' -> '.join(map(str, path_points))
|
||||
else:
|
||||
path_str = f"{path_points[0]} -> ... -> {path_points[-1]} (共{len(path_points)}个位置)"
|
||||
print(f"\\n移动路径: {path_str}")
|
||||
|
||||
def visualize_path_on_maze(self):
|
||||
"""在迷宫上可视化移动路径"""
|
||||
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 in [r['position'] for r in self.collected_resources]:
|
||||
# 已收集的资源位置
|
||||
visual_maze[row][col] = '*'
|
||||
elif i == len(self.path) - 1:
|
||||
# 最终位置
|
||||
visual_maze[row][col] = 'F'
|
||||
else:
|
||||
# 路径点
|
||||
visual_maze[row][col] = '.'
|
||||
|
||||
return visual_maze
|
||||
|
||||
def print_visual_maze(self):
|
||||
"""打印可视化的迷宫"""
|
||||
visual_maze = self.visualize_path_on_maze()
|
||||
|
||||
print("\\n=== 严格3x3视野路径可视化迷宫 ===")
|
||||
print("S: 起点, F: 终点, *: 已收集资源, .: 路径")
|
||||
for row in visual_maze:
|
||||
print(' '.join(f"{cell:>2}" for cell in row))
|
||||
|
||||
|
||||
def compare_algorithms():
|
||||
"""比较不同算法的效果"""
|
||||
|
||||
# 创建一个更大的示例迷宫
|
||||
demo_maze = [
|
||||
['s', '0', 'g5', '1', 't3', '0', 'g8'],
|
||||
['0', '1', '0', '0', 'g2', '1', '0'],
|
||||
['g3', '0', '1', 't2', '0', '0', 'g6'],
|
||||
['0', 't1', '0', '0', 'g4', '1', '0'],
|
||||
['1', '0', 'g1', '0', '0', '0', 't5'],
|
||||
['0', 'g7', '0', '1', '0', 'g9', '0'],
|
||||
['t4', '0', '0', '0', '1', '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))
|
||||
|
||||
print("\\n" + "="*60)
|
||||
print("严格3x3视野贪心算法:")
|
||||
print("="*60)
|
||||
|
||||
# 运行严格3x3视野算法
|
||||
strict_collector = Strict3x3GreedyCollector(demo_maze)
|
||||
strict_result = strict_collector.run_strict_3x3_collection()
|
||||
strict_collector.print_result_summary()
|
||||
strict_collector.print_visual_maze()
|
||||
|
||||
return strict_collector, strict_result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 运行比较演示
|
||||
strict_collector, strict_result = compare_algorithms()
|
413
tanxin.py
413
tanxin.py
@ -1,8 +1,8 @@
|
||||
import math
|
||||
from maze import *
|
||||
import math
|
||||
|
||||
import math
|
||||
import copy
|
||||
from collections import deque
|
||||
|
||||
|
||||
class GreedyPlayer:
|
||||
@ -173,7 +173,338 @@ class GreedyPlayer:
|
||||
return self.total_reward
|
||||
|
||||
|
||||
class Greedy3x3ResourceCollector:
|
||||
"""
|
||||
基于3x3视野的贪心资源收集器
|
||||
每次移动时选择3x3视野范围内最高价值的资源
|
||||
只能进行上下左右移动
|
||||
"""
|
||||
|
||||
def __init__(self, map_data, start=None, end=None):
|
||||
"""
|
||||
初始化3x3视野贪心资源收集器
|
||||
|
||||
Args:
|
||||
map_data: 迷宫地图,2D列表 (注意:这里是[y][x]格式)
|
||||
start: 起始位置 (x, y),如果为None则自动寻找
|
||||
end: 目标位置 (x, y),如果为None则自动寻找
|
||||
"""
|
||||
self.original_map = copy.deepcopy(map_data)
|
||||
self.map_data = copy.deepcopy(map_data)
|
||||
self.rows = len(map_data)
|
||||
self.cols = len(map_data[0]) if self.rows > 0 else 0
|
||||
|
||||
# 寻找起始位置和目标位置
|
||||
self.start = start or self._find_position('s')
|
||||
self.end = end or self._find_position('e')
|
||||
|
||||
if not self.start:
|
||||
raise ValueError("无法找到起始位置 's'")
|
||||
if not self.end:
|
||||
raise ValueError("无法找到目标位置 'e'")
|
||||
|
||||
self.current_pos = self.start
|
||||
self.path = [self.start]
|
||||
self.collected_resources = []
|
||||
self.total_value = 0
|
||||
self.visited_resources = set()
|
||||
self.explored_positions = set([self.start])
|
||||
|
||||
print(f"3x3视野贪心算法初始化")
|
||||
print(f"起始位置: {self.start}")
|
||||
print(f"目标位置: {self.end}")
|
||||
|
||||
def _find_position(self, target):
|
||||
"""寻找地图中指定字符的位置,返回(x, y)格式"""
|
||||
for y in range(self.rows):
|
||||
for x in range(self.cols):
|
||||
if self.map_data[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.map_data[new_y][new_x]
|
||||
|
||||
return vision
|
||||
|
||||
def get_adjacent_cells(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):
|
||||
"""
|
||||
检查是否可以移动到指定位置
|
||||
|
||||
Args:
|
||||
pos: 目标位置 (x, y)
|
||||
|
||||
Returns:
|
||||
bool: 是否可以移动
|
||||
"""
|
||||
x, y = pos
|
||||
cell = self.map_data[y][x]
|
||||
|
||||
# 不能移动到墙壁
|
||||
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_3x3_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
|
||||
|
||||
# 检查是否可以直接到达(相邻位置)
|
||||
if pos not in self.get_adjacent_cells(self.current_pos):
|
||||
continue
|
||||
|
||||
# 检查是否为资源
|
||||
value = self.evaluate_resource_value(cell)
|
||||
if value > 0 and value > best_value: # 优先选择正价值资源
|
||||
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
|
||||
if pos not in self.get_adjacent_cells(self.current_pos):
|
||||
continue
|
||||
|
||||
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_cells(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):
|
||||
"""
|
||||
收集指定位置的资源
|
||||
|
||||
Args:
|
||||
pos: 资源位置 (x, y)
|
||||
"""
|
||||
x, y = pos
|
||||
cell = self.map_data[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)
|
||||
|
||||
print(f"收集资源: 位置{pos}, 类型{cell}, 价值{value}, 总价值{self.total_value}")
|
||||
|
||||
def run_3x3_greedy_collection(self, max_moves=1000):
|
||||
"""
|
||||
运行3x3视野贪心资源收集算法
|
||||
|
||||
Args:
|
||||
max_moves: 最大移动步数,防止无限循环
|
||||
|
||||
Returns:
|
||||
dict: 包含路径、收集的资源等信息
|
||||
"""
|
||||
print("\\n开始3x3视野贪心资源收集...")
|
||||
|
||||
moves = 0
|
||||
stuck_count = 0 # 连续无法找到资源的次数
|
||||
max_stuck = 20 # 最大连续无资源次数
|
||||
|
||||
while moves < max_moves and stuck_count < max_stuck:
|
||||
moves += 1
|
||||
|
||||
# 在3x3视野内寻找最佳资源
|
||||
best_resource_pos, best_value = self.find_best_resource_in_3x3_vision()
|
||||
|
||||
if best_resource_pos is not None:
|
||||
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:
|
||||
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:
|
||||
print(f"第{moves}步: 无法进行任何移动,结束收集")
|
||||
break
|
||||
|
||||
if moves >= max_moves:
|
||||
print(f"达到最大移动步数 {max_moves},结束收集")
|
||||
elif stuck_count >= max_stuck:
|
||||
print(f"连续 {max_stuck} 步未找到资源,结束收集")
|
||||
|
||||
print("3x3视野资源收集完成!")
|
||||
return self.get_collection_result()
|
||||
|
||||
def get_collection_result(self):
|
||||
"""获取收集结果"""
|
||||
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,
|
||||
'end_pos': self.end,
|
||||
'final_pos': self.current_pos,
|
||||
'explored_positions': len(self.explored_positions)
|
||||
}
|
||||
|
||||
def get_path(self):
|
||||
"""返回路径,转换为(y, x)格式以兼容现有代码"""
|
||||
# 将(x, y)格式的路径转换为(y, x)格式
|
||||
return [(y, x) for (x, y) in self.path]
|
||||
|
||||
def get_total_reward(self):
|
||||
"""返回总收益"""
|
||||
return self.total_value
|
||||
|
||||
def add_path_to_map(self):
|
||||
"""在地图上标记路径"""
|
||||
marked_map = [row.copy() for row in self.map_data]
|
||||
|
||||
# 标记路径点
|
||||
for i, (x, y) in enumerate(self.path):
|
||||
if marked_map[y][x] == 's':
|
||||
marked_map[y][x] = 'S' # 标记起点
|
||||
elif marked_map[y][x] == 'e':
|
||||
marked_map[y][x] = 'E' # 标记终点
|
||||
elif (x, y) in [r['position'] for r in self.collected_resources]:
|
||||
marked_map[y][x] = '*' # 标记已收集资源
|
||||
else:
|
||||
marked_map[y][x] = '.' # 标记路径点
|
||||
|
||||
self.marked_map = marked_map
|
||||
return marked_map
|
||||
|
||||
|
||||
# 使用示例
|
||||
@ -191,19 +522,95 @@ def main():
|
||||
map_data = obj.read_csv()
|
||||
see = MazeGenerator(1,filename ='demo.csv')
|
||||
see.read_from_csv()
|
||||
print("=== 原始迷宫 ===")
|
||||
see.print_maze()
|
||||
|
||||
print("\\n" + "="*60)
|
||||
print("使用传统贪心算法:")
|
||||
print("="*60)
|
||||
player = GreedyPlayer(map_data)
|
||||
player.find_path()
|
||||
see.maze = player.marked_map
|
||||
see.print_maze()
|
||||
print(f"传统贪心算法总收益: {player.get_total_reward()}")
|
||||
|
||||
print("\\n" + "="*60)
|
||||
print("使用3x3视野贪心算法:")
|
||||
print("="*60)
|
||||
# 使用新的3x3视野算法
|
||||
greedy_3x3 = Greedy3x3ResourceCollector(map_data)
|
||||
result = greedy_3x3.run_3x3_greedy_collection()
|
||||
|
||||
# 显示结果
|
||||
see.maze = greedy_3x3.add_path_to_map()
|
||||
see.print_maze()
|
||||
|
||||
print(f"\\n3x3视野算法结果:")
|
||||
print(f" 总移动步数: {result['total_moves']}")
|
||||
print(f" 收集资源数量: {result['resources_count']}")
|
||||
print(f" 资源总价值: {result['total_value']}")
|
||||
print(f" 探索位置数: {result['explored_positions']}")
|
||||
|
||||
print("\\n收集的资源详情:")
|
||||
for i, resource in enumerate(result['collected_resources'], 1):
|
||||
print(f" {i}. 位置{resource['position']}: {resource['type']} (价值: {resource['value']})")
|
||||
|
||||
|
||||
def demo_3x3_greedy():
|
||||
"""演示3x3视野贪心算法"""
|
||||
|
||||
# 创建一个示例迷宫
|
||||
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))
|
||||
|
||||
# 使用3x3视野贪心算法
|
||||
collector = Greedy3x3ResourceCollector(demo_maze)
|
||||
result = collector.run_3x3_greedy_collection()
|
||||
|
||||
# 显示标记后的迷宫
|
||||
marked_maze = collector.add_path_to_map()
|
||||
print("\\n标记路径后的迷宫:")
|
||||
print("S: 起点, E: 终点, *: 已收集资源, .: 路径")
|
||||
for row in marked_maze:
|
||||
print(' '.join(f"{cell:>2}" for cell in row))
|
||||
|
||||
print(f"\\n算法结果:")
|
||||
print(f" 总移动步数: {result['total_moves']}")
|
||||
print(f" 收集资源数量: {result['resources_count']}")
|
||||
print(f" 资源总价值: {result['total_value']}")
|
||||
|
||||
return collector, result
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
# 运行演示
|
||||
print("选择运行模式:")
|
||||
print("1. 完整迷宫生成和算法比较")
|
||||
print("2. 简单3x3视野算法演示")
|
||||
|
||||
choice = input("请输入选择 (1 或 2,默认为 2): ").strip()
|
||||
|
||||
if choice == "1":
|
||||
main()
|
||||
else:
|
||||
demo_3x3_greedy()
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user