测试老师的测试文件

This commit is contained in:
Gary Gan 2025-06-30 14:43:50 +08:00
parent 9dddc9363f
commit f046ba5bbd
13 changed files with 774 additions and 1674 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
__pycache__/ __pycache__/
.venv/ .venv/
.idea/ .idea/
*.csv *.csv
saves/

View File

@ -91,7 +91,7 @@ class SourceCollector:
def outofmap(self,x,y): def outofmap(self,x,y):
return x < 0 or y < 0 or x > self.rowNums or y > self.colNums return x < 0 or y < 0 or x >= self.rowNums or y >= self.colNums
def getlca(self,u, v): def getlca(self,u, v):
def get_path_to_root(node): def get_path_to_root(node):
path = [] path = []
@ -169,7 +169,6 @@ class SourceCollector:
return self.path return self.path
def bfs_path(self, start, end): def bfs_path(self, start, end):
return
"""从start到end的最短路径含首尾""" """从start到end的最短路径含首尾"""
from collections import deque from collections import deque
n, m = self.rowNums, self.colNums n, m = self.rowNums, self.colNums

12
main.py
View File

@ -188,21 +188,23 @@ if __name__ == "__main__":
sample_file = "saves/sample.json" sample_file = "saves/sample.json"
if os.path.exists(sample_file): if os.path.exists(sample_file):
if maze.load_game(sample_file): if maze.load_game(sample_file):
# 加载成功后重新生成路径 # 加载成功后检查是否需要重新生成路径
if maze.generater.maze: if len(maze.full_path) == 0 and maze.generater.maze:
# 只有当没有路径信息时才重新生成
from SourceCollector import SourceCollector from SourceCollector import SourceCollector
maze.source_collector = SourceCollector(maze=maze.generater.maze) maze.source_collector = SourceCollector(maze=maze.generater.maze)
maze.source_collector.run() maze.source_collector.run()
maze.full_path = maze.source_collector.get_path() maze.full_path = maze.source_collector.get_path()
maze.path_step = 0 maze.path_step = 0
maze.is_path_complete = False maze.is_path_complete = False
maze.grid = maze.generater.maze # 重置显示网格 # 不要重置grid保持加载的包含路径的网格
mes4.text = f"已加载 {sample_file} 并生成路径" mes4.text = f"已加载 {sample_file} 并生成路径"
mes4.show() mes4.show()
auto_play = False auto_play = False
else: else:
mes5.text = "加载的迷宫数据无效" mes4.text = f"已加载 {sample_file}"
mes5.show() mes4.show()
auto_play = False
else: else:
mes5.text = f"无法加载 {sample_file}" mes5.text = f"无法加载 {sample_file}"
mes5.show() mes5.show()

View File

@ -191,3 +191,108 @@ saves/
- **新增方法**: `Maze.reset_all_states()` - 统一重置所有状态 - **新增方法**: `Maze.reset_all_states()` - 统一重置所有状态
- **改进逻辑**: 确保历史模式、路径模式、自动播放等状态的正确切换 - **改进逻辑**: 确保历史模式、路径模式、自动播放等状态的正确切换
- **内存管理**: 避免历史数据在多次生成时累积导致内存问题 - **内存管理**: 避免历史数据在多次生成时累积导致内存问题
## 🛡️ 迷宫边界自动修复功能 - **新增安全特性**
### 功能概述
自动检测和修复迷宫文件中边界不完整的问题,确保算法正常运行。
### 问题背景
某些迷宫JSON文件可能存在边界不是墙壁的情况如边界包含起点S、终点E或空格这会导致路径算法报错。
### 自动修复机制
#### 检测规则
系统在加载迷宫时自动检查:
- **上边界**: 第一行是否全是墙壁('#' 或 '1')
- **下边界**: 最后一行是否全是墙壁
- **左边界**: 每行第一列是否全是墙壁
- **右边界**: 每行最后一列是否全是墙壁
#### 修复动作
当检测到边界问题时:
1. **自动添加边界**: 在原迷宫四周添加一圈墙壁('#')
2. **尺寸调整**: 迷宫尺寸从NxN变为(N+2)x(N+2)
3. **坐标调整**: 如果有路径数据,自动调整坐标(+1,+1)
4. **日志输出**: 显示修复过程和结果
#### 示例
```
原始迷宫 (15x15):
["#","#","#","S","#",...] <- 边界有起点S
...
["#","#","#","E","#",...] <- 边界有终点E
修复后迷宫 (17x17):
["#","#","#","#","#",...] <- 全部墙壁
["#","#","#","S","#",...] <- 原内容向内偏移
...
["#","#","#","E","#",...]
["#","#","#","#","#",...] <- 全部墙壁
```
### 支持范围
- ✅ **JSON格式**: 完全支持,包括路径坐标调整
- ✅ **CSV格式**: 完全支持,路径自动适配
- ✅ **路径数据**: 自动调整坐标以适应新边界
- ✅ **兼容性**: 对正常迷宫无影响
### 使用场景
- 📂 **导入外部迷宫**: 安全加载来源不明的迷宫文件
- 🔧 **修复损坏文件**: 自动处理格式不标准的迷宫
- 🛡️ **算法保护**: 防止边界问题导致的程序崩溃
- 🔄 **自动化处理**: 无需手动修改文件,系统自动处理
## 🐛 路径生成边界检查修复 - **重要错误修复**
### 问题描述
当加载边界不完整的迷宫文件(如`maze_15_15_2.json`系统会自动添加边界墙壁迷宫尺寸从15x15变为17x17。但是`SourceCollector`在进行路径搜索时会出现数组越界错误:
```
IndexError: list index out of range
```
### 根本原因
1. **边界检查逻辑错误**: `SourceCollector.outofmap()`方法使用了错误的边界条件(`>` 而不是 `>=`
2. **网格覆盖问题**: 在重新生成路径后,代码错误地将显示网格重置为原始网格,覆盖了包含路径信息的网格
3. **重复路径生成**: 即使已经有路径信息,系统仍然会强制重新生成路径
### 修复内容
#### 1. SourceCollector边界检查修复
```python
# 修复前(错误)
def outofmap(self,x,y):
return x < 0 or y < 0 or x > self.rowNums or y > self.colNums
# 修复后(正确)
def outofmap(self,x,y):
return x < 0 or y < 0 or x >= self.rowNums or y >= self.colNums
```
#### 2. 智能路径生成逻辑
- **条件检查**: 只在`len(maze.full_path) == 0`时才重新生成路径
- **网格保护**: 不再重置显示网格,保持加载的包含路径信息的网格
- **一致性优化**: 在`main.py`和`save_ui.py`中统一处理逻辑
#### 3. 多处修复点
- ✅ **main.py**: Load按钮逻辑优化
- ✅ **save_ui.py**: 存档界面回车键和双击加载逻辑修复
- ✅ **SourceCollector.py**: 边界检查条件修正
### 测试验证
通过全面测试确认修复效果:
- ✅ **边界检查**: 所有边界条件测试通过
- ✅ **小迷宫测试**: 5x5测试迷宫路径生成正常
- ✅ **直接测试**: `SourceCollector`直接加载修复后迷宫正常
- ✅ **完整流程**: `maze.load_game()`完整流程测试通过
- ✅ **路径长度**: 修复后能正确生成15步路径
### 实际效果
对于`maze_15_15_2.json`文件:
- **修复前**: 加载时报`IndexError`,程序崩溃
- **修复后**: 自动边界修复(15x15→17x17)成功生成15步路径程序稳定运行
### 兼容性保证
- ✅ **正常文件**: 对边界完整的迷宫文件无影响
- ✅ **路径保持**: 已有路径信息的文件保持路径不变
- ✅ **格式支持**: JSON和CSV格式都支持边界修复和路径生成

View File

@ -72,15 +72,16 @@ class SaveLoadUI:
if 0 <= self.selected_save < len(self.save_list): if 0 <= self.selected_save < len(self.save_list):
save_file = self.save_list[self.selected_save]['path'] save_file = self.save_list[self.selected_save]['path']
if maze.load_game(save_file): if maze.load_game(save_file):
# 加载成功后重新生成路径 # 加载成功后检查是否需要重新生成路径
if maze.generater.maze: if len(maze.full_path) == 0 and maze.generater.maze:
# 只有当没有路径信息时才重新生成
from SourceCollector import SourceCollector from SourceCollector import SourceCollector
maze.source_collector = SourceCollector(maze=maze.generater.maze) maze.source_collector = SourceCollector(maze=maze.generater.maze)
maze.source_collector.run() maze.source_collector.run()
maze.full_path = maze.source_collector.get_path() maze.full_path = maze.source_collector.get_path()
maze.path_step = 0 maze.path_step = 0
maze.is_path_complete = False maze.is_path_complete = False
maze.grid = maze.generater.maze # 重置显示网格 # 不要重置grid保持加载的包含路径的网格
print(f"已为加载的存档重新生成路径,路径长度: {len(maze.full_path)}") print(f"已为加载的存档重新生成路径,路径长度: {len(maze.full_path)}")
self.show_save_list = False self.show_save_list = False
return "load_success" return "load_success"
@ -120,15 +121,16 @@ class SaveLoadUI:
# 双击加载存档 # 双击加载存档
save_file = self.save_list[clicked_index]['path'] save_file = self.save_list[clicked_index]['path']
if maze.load_game(save_file): if maze.load_game(save_file):
# 加载成功后重新生成路径 # 加载成功后检查是否需要重新生成路径
if maze.generater.maze: if len(maze.full_path) == 0 and maze.generater.maze:
# 只有当没有路径信息时才重新生成
from SourceCollector import SourceCollector from SourceCollector import SourceCollector
maze.source_collector = SourceCollector(maze=maze.generater.maze) maze.source_collector = SourceCollector(maze=maze.generater.maze)
maze.source_collector.run() maze.source_collector.run()
maze.full_path = maze.source_collector.get_path() maze.full_path = maze.source_collector.get_path()
maze.path_step = 0 maze.path_step = 0
maze.is_path_complete = False maze.is_path_complete = False
maze.grid = maze.generater.maze # 重置显示网格 # 不要重置grid保持加载的包含路径的网格
print(f"已为加载的存档重新生成路径,路径长度: {len(maze.full_path)}") print(f"已为加载的存档重新生成路径,路径长度: {len(maze.full_path)}")
self.show_save_list = False self.show_save_list = False
return "load_success" return "load_success"

View File

@ -1,580 +0,0 @@
{
"maze": [
[
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#"
],
[
"#",
" ",
"#",
" ",
" ",
" ",
"#",
" ",
"#",
" ",
" ",
" ",
"#",
" ",
"#",
"#"
],
[
"#",
" ",
" ",
" ",
"#",
"#",
"#",
"T",
"#",
"#",
"#",
"G",
" ",
" ",
"#",
"#"
],
[
"#",
" ",
"#",
" ",
"G",
" ",
"L",
" ",
"#",
" ",
" ",
" ",
"#",
"G",
" ",
"#"
],
[
"#",
" ",
"#",
"#",
" ",
"#",
"#",
"#",
"#",
"#",
" ",
"#",
"#",
"#",
"#",
"#"
],
[
"#",
"S",
"#",
" ",
" ",
" ",
"#",
" ",
"#",
" ",
" ",
" ",
" ",
" ",
"#",
"#"
],
[
"#",
"T",
"#",
"G",
"#",
" ",
" ",
"B",
"#",
" ",
"#",
"G",
"#",
"T",
"#",
"#"
],
[
"#",
" ",
"#",
"G",
"#",
" ",
"#",
" ",
" ",
" ",
"#",
" ",
"#",
" ",
" ",
"#"
],
[
"#",
" ",
"#",
"#",
"#",
" ",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
" ",
"#"
],
[
"#",
" ",
"#",
" ",
" ",
" ",
" ",
"E",
"#",
" ",
" ",
" ",
" ",
" ",
" ",
"#"
],
[
"#",
" ",
"#",
" ",
"#",
" ",
"#",
"#",
"#",
" ",
"#",
"#",
"#",
"#",
"#",
"#"
],
[
"#",
" ",
"#",
" ",
"#",
" ",
"G",
" ",
"#",
" ",
" ",
" ",
" ",
" ",
" ",
"#"
],
[
"#",
" ",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
" ",
"#",
"#",
"#",
"#"
],
[
"#",
" ",
"#",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
"#",
"#"
],
[
"#",
" ",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"L",
" ",
"#"
],
[
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#",
"#"
]
],
"metadata": {
"save_name": "maze_save_20250630_124021",
"save_time": "2025-06-30T12:40:21.179729",
"maze_size": 16,
"path_length": 69
},
"path_data": {
"full_path": [
[
5,
1
],
[
4,
1
],
[
3,
1
],
[
2,
1
],
[
2,
2
],
[
2,
3
],
[
3,
3
],
[
3,
4
],
[
4,
4
],
[
5,
4
],
[
5,
3
],
[
6,
3
],
[
7,
3
],
[
6,
3
],
[
5,
3
],
[
5,
4
],
[
5,
5
],
[
6,
5
],
[
7,
5
],
[
8,
5
],
[
9,
5
],
[
10,
5
],
[
11,
5
],
[
11,
6
],
[
11,
5
],
[
10,
5
],
[
9,
5
],
[
8,
5
],
[
7,
5
],
[
6,
5
],
[
6,
6
],
[
6,
7
],
[
7,
7
],
[
7,
8
],
[
7,
9
],
[
6,
9
],
[
5,
9
],
[
5,
10
],
[
4,
10
],
[
3,
10
],
[
3,
11
],
[
2,
11
],
[
2,
12
],
[
2,
13
],
[
3,
13
],
[
2,
13
],
[
2,
12
],
[
2,
11
],
[
3,
11
],
[
3,
10
],
[
4,
10
],
[
5,
10
],
[
5,
11
],
[
6,
11
],
[
5,
11
],
[
5,
10
],
[
5,
9
],
[
6,
9
],
[
7,
9
],
[
7,
8
],
[
7,
7
],
[
6,
7
],
[
6,
6
],
[
6,
5
],
[
7,
5
],
[
8,
5
],
[
9,
5
],
[
9,
6
],
[
9,
7
]
],
"current_step": 0,
"is_path_complete": false
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,19 @@
{ {
"maze": [ "maze": [
["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"], ["#","#","#","#","#","#","#","#","#","#","#","#","#","#","#"],
["#", "S", "#", " ", "#", " ", "#", " ", "#", " ", " ", " ", " ", " ", "#"], ["#","G","T"," ","T","G","#","G","T"," "," "," ","#"," ","#"],
["#", " ", "#", " ", "#", " ", "#", " ", "#", "#", "#", " ", "#", "#", "#"], ["#","#","#"," ","#","#","#","#","#"," ","#"," ","#"," ","#"],
["#", " ", "#", " ", " ", " ", "#", " ", "#", " ", " ", " ", "#", " ", "#"], ["#"," ","#"," ","#"," ","#","G","#"," ","#"," ","#","B","S"],
["#", " ", "#", " ", "#", "#", "#", " ", "#", " ", "#", "#", "#", " ", "#"], ["#"," ","#"," ","#"," ","#","T","#"," ","#"," ","#"," ","#"],
["#", " ", " ", " ", "#", " ", " ", " ", " ", " ", " ", " ", "#", " ", "#"], ["#"," "," "," "," "," "," "," "," ","T","#"," "," ","L","#"],
["#", "#", "#", " ", "#", " ", "#", "#", "#", " ", "#", "#", "#", " ", "#"], ["#"," ","#"," ","#","#","#","#","#","#","#","#","#"," ","#"],
["#", " ", " ", "T", "G", " ", " ", " ", "#", " ", "L", " ", " ", " ", "#"], ["#"," ","#"," "," "," ","#"," ","#","T","T"," "," "," ","#"],
["#", " ", "#", "#", "#", "#", "#", "#", "#", " ", "#", " ", "#", " ", "#"], ["#"," ","#","#","#","#","#","G","#","#","#"," ","#"," ","#"],
["#", " ", " ", " ", "#", " ", "#", " ", "#", " ", "#", " ", "#", " ", "#"], ["#","T"," "," "," ","G","#"," "," "," "," "," ","#"," ","#"],
["#", "#", "#", "#", "#", " ", "#", " ", "#", "#", "#", "#", "#", " ", "#"], ["#","#","#","#","#","#","#","#","#","#","#","#","#","T","#"],
["#", " ", " ", "G", " ", "G", " ", " ", "#", " ", " ", " ", " ", " ", "#"], ["#","T","#"," "," "," "," "," "," "," ","#"," ","T","T","#"],
["#", " ", "#", "#", "#", " ", "#", " ", "#", "#", "#", " ", "#", "#", "#"], ["#","G","#"," ","#","T","#"," ","#"," ","#"," ","#"," ","#"],
["#", "G", " ", " ", "#", " ", "#", " ", " ", "G", " ", "B", " ", "E", "#"], ["#"," "," "," ","#","G","#"," ","#","G"," "," ","#"," ","#"],
["#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#"] ["#","#","#","#","#","#","#","#","#","#","#","#","#","E","#"]
] ]
} }

View File

@ -5,7 +5,7 @@ from datetime import datetime
from config import DEFAULT_MAZE_FILE from config import DEFAULT_MAZE_FILE
class SimpleSaveManager: class SimpleSaveManager:
"""简化的存档管理器 - 支持JSON和CSV格式的迷宫文件""" """简化的存档管理器 - 支持JSON和CSV格式的迷宫"""
def __init__(self): def __init__(self):
self.save_directory = "saves" self.save_directory = "saves"
@ -130,6 +130,9 @@ class SimpleSaveManager:
# 转换JSON格式到内部格式 # 转换JSON格式到内部格式
internal_maze = self.convert_from_json_format(data['maze']) internal_maze = self.convert_from_json_format(data['maze'])
# 检查并修复迷宫边界
internal_maze, boundary_added = self.ensure_maze_boundaries(internal_maze)
result = { result = {
'original_grid': internal_maze, 'original_grid': internal_maze,
'path_grid': internal_maze, # 对于JSON格式初始时路径网格与原始网格相同 'path_grid': internal_maze, # 对于JSON格式初始时路径网格与原始网格相同
@ -143,9 +146,14 @@ class SimpleSaveManager:
if 'path_data' in data: if 'path_data' in data:
raw_path = data['path_data'].get('full_path', []) raw_path = data['path_data'].get('full_path', [])
# 确保路径数据是元组格式 (JSON会将元组转换为列表) # 确保路径数据是元组格式 (JSON会将元组转换为列表)
result['path_sequence'] = [tuple(pos) if isinstance(pos, list) else pos for pos in raw_path] path_sequence = [tuple(pos) if isinstance(pos, list) else pos for pos in raw_path]
result['path_positions'] = {i+1: tuple(pos) if isinstance(pos, list) else pos
for i, pos in enumerate(result['path_sequence'])} # 如果添加了边界,调整路径坐标
if boundary_added:
path_sequence = self.adjust_path_coordinates(path_sequence, boundary_added)
result['path_sequence'] = path_sequence
result['path_positions'] = {i+1: pos for i, pos in enumerate(path_sequence)}
# 如果有路径,创建包含路径的网格 # 如果有路径,创建包含路径的网格
if result['path_sequence']: if result['path_sequence']:
@ -175,9 +183,16 @@ class SimpleSaveManager:
reader = csv.reader(f) reader = csv.reader(f)
grid = [list(row) for row in reader] grid = [list(row) for row in reader]
# 检查并修复迷宫边界
grid, boundary_added = self.ensure_maze_boundaries(grid)
# 解析路径信息 # 解析路径信息
path_data = self.extract_path_from_grid(grid) path_data = self.extract_path_from_grid(grid)
# 如果添加了边界但有路径数据,需要调整路径坐标
# 注意对于CSV路径信息是从网格中提取的添加边界后坐标已经自动调整了
# 所以这里不需要额外调整
# 创建原始迷宫(移除路径信息) # 创建原始迷宫(移除路径信息)
original_grid = self.create_original_grid(grid) original_grid = self.create_original_grid(grid)
@ -443,9 +458,9 @@ class SimpleSaveManager:
elif cell == 'E': elif cell == 'E':
internal_row.append('e') internal_row.append('e')
elif cell == 'G': elif cell == 'G':
internal_row.append('g10') # 默认金币值 internal_row.append('g30') # 默认金币值
elif cell == 'T': elif cell == 'T':
internal_row.append('t15') # 默认陷阱值 internal_row.append('t20') # 默认陷阱值
elif cell == 'L': elif cell == 'L':
internal_row.append('l20') # 默认机关值 internal_row.append('l20') # 默认机关值
elif cell == 'B': elif cell == 'B':
@ -456,6 +471,105 @@ class SimpleSaveManager:
internal_maze.append(internal_row) internal_maze.append(internal_row)
return internal_maze return internal_maze
def ensure_maze_boundaries(self, maze_grid):
"""
确保迷宫四周都是墙壁如果不是则自动添加边界墙
Args:
maze_grid: 迷宫网格数据
Returns:
tuple: (修复后的迷宫网格, 是否添加了边界)
"""
if not maze_grid or len(maze_grid) == 0:
return maze_grid, False
# 检查是否需要添加边界
needs_boundary = False
height = len(maze_grid)
width = len(maze_grid[0]) if height > 0 else 0
if width == 0:
return maze_grid, False
# 检查四条边是否全是墙壁('#' 或 '1')
# 上边界
for col in range(width):
if maze_grid[0][col] not in ['#', '1']:
needs_boundary = True
break
# 下边界
if not needs_boundary:
for col in range(width):
if maze_grid[height-1][col] not in ['#', '1']:
needs_boundary = True
break
# 左边界
if not needs_boundary:
for row in range(height):
if maze_grid[row][0] not in ['#', '1']:
needs_boundary = True
break
# 右边界
if not needs_boundary:
for row in range(height):
if maze_grid[row][width-1] not in ['#', '1']:
needs_boundary = True
break
if not needs_boundary:
print("迷宫边界检查通过,无需修复")
return maze_grid, False
print("检测到迷宫边界不完整,自动添加边界墙壁...")
# 创建新的迷宫,四周加上墙壁
new_height = height + 2
new_width = width + 2
new_maze = []
# 添加上边界
new_maze.append(['#'] * new_width)
# 添加中间行(左右加墙)
for row in maze_grid:
new_row = ['#'] + row + ['#']
new_maze.append(new_row)
# 添加下边界
new_maze.append(['#'] * new_width)
print(f"边界修复完成:{width}x{height} -> {new_width}x{new_height}")
return new_maze, True
def adjust_path_coordinates(self, path_sequence, boundary_added):
"""
当添加边界后调整路径坐标
Args:
path_sequence: 原始路径序列
boundary_added: 是否添加了边界
Returns:
list: 调整后的路径序列
"""
if not boundary_added or not path_sequence:
return path_sequence
# 所有坐标向右下偏移1个单位
adjusted_path = []
for pos in path_sequence:
if isinstance(pos, (list, tuple)) and len(pos) == 2:
adjusted_path.append((pos[0] + 1, pos[1] + 1))
else:
adjusted_path.append(pos) # 保持原样(可能是错误数据)
print(f"路径坐标已调整,共 {len(adjusted_path)} 个点")
return adjusted_path
# 全局简化存档管理器实例 # 全局简化存档管理器实例
simple_save_manager = SimpleSaveManager() simple_save_manager = SimpleSaveManager()

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
主程序边界修复功能测试指南
"""
print("=== 主程序边界修复功能测试 ===")
print()
print("此测试将启动主程序来验证边界修复功能。")
print()
print("测试步骤:")
print("1. 启动程序后,点击 [Load] 按钮")
print("2. 程序会尝试加载 saves/sample.json")
print(" 如果不存在,会打开存档选择界面")
print("3. 在存档列表中选择 'maze_15_15_2.json'")
print("4. 观察控制台输出,应该看到边界修复信息")
print("5. 验证迷宫能正常显示且四周有墙壁")
print("6. 确认没有程序错误或崩溃")
print()
print("预期结果:")
print("- 控制台显示:'检测到迷宫边界不完整,自动添加边界墙壁...'")
print("- 控制台显示:'边界修复完成15x15 -> 17x17'")
print("- 迷宫正常显示,四周都是墙壁")
print("- 程序运行稳定,没有错误")
print()
print("可以测试的文件:")
print("- maze_15_15_2.json (已知边界问题)")
print("- test_no_boundary.json (测试创建的无边界文件)")
print("- 其他正常的JSON文件 (验证不影响正常文件)")
print()
input("按 Enter 键启动程序进行测试...")
try:
import main
except KeyboardInterrupt:
print("\n测试完成,程序已退出")
except Exception as e:
print(f"\n程序运行出现错误: {str(e)}")
print("请检查边界修复功能的实现")

View File

@ -0,0 +1,205 @@
#!/usr/bin/env python3
"""
测试迷宫边界自动修复功能
验证当迷宫四周不是墙时能自动添加边界
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from simple_save_manager import simple_save_manager
from maze import Maze
import json
def test_boundary_repair():
"""测试边界修复功能"""
print("=== 测试迷宫边界自动修复功能 ===")
# 测试加载有问题边界的JSON文件
test_file = "saves/maze_15_15_2.json"
if not os.path.exists(test_file):
print(f"❌ 测试文件 {test_file} 不存在")
return False
print(f"加载测试文件: {test_file}")
# 先查看原始文件内容
with open(test_file, 'r', encoding='utf-8') as f:
original_data = json.load(f)
original_maze = original_data['maze']
print(f"原始迷宫尺寸: {len(original_maze)}x{len(original_maze[0])}")
# 检查原始边界
height = len(original_maze)
width = len(original_maze[0])
print("原始边界检查:")
print(f" 上边界: {original_maze[0]}")
print(f" 下边界: {original_maze[height-1]}")
print(f" 左边界: {[row[0] for row in original_maze]}")
print(f" 右边界: {[row[width-1] for row in original_maze]}")
# 使用simple_save_manager加载
load_data = simple_save_manager.load_maze_from_file(test_file)
if load_data is None:
print("❌ 加载失败")
return False
# 检查修复后的迷宫
repaired_maze = load_data['original_grid']
print(f"修复后迷宫尺寸: {len(repaired_maze)}x{len(repaired_maze[0])}")
# 验证边界是否都是墙
new_height = len(repaired_maze)
new_width = len(repaired_maze[0])
boundary_ok = True
# 检查上下边界
for col in range(new_width):
if repaired_maze[0][col] not in ['#', '1']:
print(f"❌ 上边界第{col}列不是墙: {repaired_maze[0][col]}")
boundary_ok = False
if repaired_maze[new_height-1][col] not in ['#', '1']:
print(f"❌ 下边界第{col}列不是墙: {repaired_maze[new_height-1][col]}")
boundary_ok = False
# 检查左右边界
for row in range(new_height):
if repaired_maze[row][0] not in ['#', '1']:
print(f"❌ 左边界第{row}行不是墙: {repaired_maze[row][0]}")
boundary_ok = False
if repaired_maze[row][new_width-1] not in ['#', '1']:
print(f"❌ 右边界第{row}行不是墙: {repaired_maze[row][new_width-1]}")
boundary_ok = False
if boundary_ok:
print("✅ 边界修复成功,所有边界都是墙壁")
else:
print("❌ 边界修复失败")
return False
return True
def test_maze_loading_with_repair():
"""测试在Maze类中加载带有边界问题的迷宫"""
print("\n=== 测试Maze类加载边界修复 ===")
maze = Maze(wall_size=30, maze_size=600, file_name="test.csv")
test_file = "saves/maze_15_15_2.json"
if not os.path.exists(test_file):
print(f"❌ 测试文件 {test_file} 不存在")
return False
# 加载迷宫
result = maze.load_game(test_file)
if not result:
print("❌ Maze加载失败")
return False
# 检查加载后的迷宫是否正常
if len(maze.grid) == 0:
print("❌ 加载后迷宫网格为空")
return False
# 验证边界
height = len(maze.grid)
width = len(maze.grid[0])
print(f"Maze加载后尺寸: {width}x{height}")
# 简单检查四个角是否是墙
corners = [
maze.grid[0][0], maze.grid[0][width-1],
maze.grid[height-1][0], maze.grid[height-1][width-1]
]
if all(corner in ['#', '1'] for corner in corners):
print("✅ Maze加载成功边界正常")
return True
else:
print(f"❌ Maze加载后边界有问题四个角: {corners}")
return False
def test_create_test_file_without_boundary():
"""创建一个没有边界的测试文件"""
print("\n=== 创建测试用的无边界迷宫文件 ===")
# 创建一个中间没有边界的迷宫
test_maze = [
[" ", "S", " ", " ", " "],
[" ", "#", " ", "#", " "],
[" ", " ", " ", "#", " "],
[" ", "#", " ", " ", " "],
[" ", " ", " ", "E", " "]
]
test_data = {
"maze": test_maze,
"metadata": {
"name": "无边界测试迷宫",
"test": True
}
}
test_file = "saves/test_no_boundary.json"
with open(test_file, 'w', encoding='utf-8') as f:
json.dump(test_data, f, indent=2, ensure_ascii=False)
print(f"创建测试文件: {test_file}")
# 测试加载这个文件
load_data = simple_save_manager.load_maze_from_file(test_file)
if load_data is None:
print("❌ 加载自创建的测试文件失败")
return False
repaired_maze = load_data['original_grid']
print(f"原始: 5x5 -> 修复后: {len(repaired_maze[0])}x{len(repaired_maze)}")
# 打印修复后的迷宫
print("修复后的迷宫:")
for row in repaired_maze:
print(''.join(row))
return True
def main():
print("开始测试迷宫边界自动修复功能...")
tests = [
test_boundary_repair,
test_maze_loading_with_repair,
test_create_test_file_without_boundary
]
passed = 0
total = len(tests)
for test in tests:
try:
if test():
passed += 1
else:
print(f"❌ 测试 {test.__name__} 失败")
except Exception as e:
print(f"❌ 测试 {test.__name__} 出现异常: {str(e)}")
import traceback
traceback.print_exc()
print(f"\n=== 测试结果 ===")
print(f"通过: {passed}/{total}")
if passed == total:
print("🎉 所有边界修复功能测试通过!")
return True
else:
print("❌ 部分测试失败,请检查相关功能")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""
边界修复和路径生成完整功能测试指南
验证所有相关修复是否正确工作
"""
print("=== 边界修复和路径生成完整测试指南 ===")
print()
print("此测试将启动主程序验证以下功能:")
print()
print("🛡️ 边界自动修复功能:")
print("1. 系统自动检测迷宫边界问题")
print("2. 自动添加边界墙壁(15x15→17x17)")
print("3. 路径坐标自动调整")
print()
print("🎯 路径生成修复:")
print("1. SourceCollector边界检查正确")
print("2. 不会出现数组越界错误")
print("3. 能成功生成完整路径")
print()
print("测试步骤:")
print("1. 启动程序")
print("2. 点击 [Load] 按钮")
print("3. 程序会自动加载 saves/sample.json (已复制maze_15_15_2.json)")
print("4. 观察控制台输出,应该看到:")
print(" - '检测到迷宫边界不完整,自动添加边界墙壁...'")
print(" - '边界修复完成15x15 -> 17x17'")
print(" - '已加载 saves/sample.json'")
print("5. 验证迷宫正常显示,没有程序错误")
print("6. 尝试路径演示功能(下一步、自动播放等)")
print()
print("可选的额外测试:")
print("- 按Ctrl+L打开存档界面加载maze_15_15_2.json")
print("- 测试双击加载功能")
print("- 验证历史迭代功能正常工作")
print()
print("预期结果:")
print("✅ 没有IndexError或其他错误")
print("✅ 迷宫正常显示且四周有墙壁")
print("✅ 路径演示功能正常工作")
print("✅ 控制台显示正确的修复信息")
print()
print("注意事项:")
print("- 如果sample.json不存在系统会打开存档选择界面")
print("- 可以手动选择maze_15_15_2.json进行测试")
print("- 边界修复是自动且透明的,用户无需手动操作")
print()
input("按 Enter 键启动程序进行完整测试...")
try:
import main
except KeyboardInterrupt:
print("\n测试完成,程序已退出")
print()
print("如果程序运行正常且没有错误,说明所有修复都工作正常!")
except Exception as e:
print(f"\n程序运行出现错误: {str(e)}")
print("请检查错误信息并参考修复文档")

View File

@ -0,0 +1,210 @@
#!/usr/bin/env python3
"""
测试边界修复后的路径生成功能
验证修复边界后SourceCollector能正常工作
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from maze import Maze
from SourceCollector import SourceCollector
import traceback
def test_source_collector_with_boundary_fix():
"""测试边界修复后SourceCollector的路径生成"""
print("=== 测试边界修复后路径生成 ===")
maze = Maze(wall_size=30, maze_size=600, file_name="test.csv")
# 加载有边界问题的文件
test_file = "saves/maze_15_15_2.json"
if not os.path.exists(test_file):
print(f"❌ 测试文件 {test_file} 不存在")
return False
print(f"加载测试文件: {test_file}")
try:
# 使用maze.load_game加载会自动修复边界
result = maze.load_game(test_file)
if not result:
print("❌ 迷宫加载失败")
return False
print(f"✅ 迷宫加载成功")
print(f"修复后迷宫尺寸: {len(maze.generater.maze)}x{len(maze.generater.maze[0])}")
print(f"显示网格尺寸: {len(maze.grid)}x{len(maze.grid[0])}")
# 检查是否有路径信息
if len(maze.full_path) > 0:
print(f"已有路径信息,长度: {len(maze.full_path)}")
return True
# 如果没有路径信息,尝试生成
print("没有路径信息,尝试重新生成...")
# 使用修复后的迷宫创建SourceCollector
source_collector = SourceCollector(maze=maze.generater.maze)
print(f"SourceCollector创建成功迷宫尺寸: {source_collector.rowNums}x{source_collector.colNums}")
# 检查起点和终点
if source_collector.start_pos is None:
print("❌ 没有找到起点")
return False
if source_collector.end_pos is None:
print("❌ 没有找到终点")
return False
print(f"起点: {source_collector.start_pos}")
print(f"终点: {source_collector.end_pos}")
# 尝试运行路径搜索
source_collector.run()
path = source_collector.get_path()
if path and len(path) > 0:
print(f"✅ 路径生成成功,长度: {len(path)}")
print(f"起始几步: {path[:5] if len(path) >= 5 else path}")
return True
else:
print("❌ 路径生成失败,没有找到路径")
return False
except Exception as e:
print(f"❌ 测试过程中出现异常: {str(e)}")
traceback.print_exc()
return False
def test_boundary_check_in_source_collector():
"""测试SourceCollector的边界检查功能"""
print("\n=== 测试SourceCollector边界检查 ===")
# 创建一个小的测试迷宫
test_maze = [
['1', '1', '1', '1', '1'],
['1', 's', '0', '0', '1'],
['1', '0', '1', '0', '1'],
['1', '0', '0', 'e', '1'],
['1', '1', '1', '1', '1']
]
try:
source_collector = SourceCollector(maze=test_maze)
print(f"测试迷宫尺寸: {source_collector.rowNums}x{source_collector.colNums}")
print(f"起点: {source_collector.start_pos}")
print(f"终点: {source_collector.end_pos}")
# 测试边界检查
test_cases = [
(-1, 0), # 左边界外
(0, -1), # 上边界外
(5, 2), # 下边界外
(2, 5), # 右边界外
(0, 0), # 左上角(边界内)
(4, 4), # 右下角(边界内)
(2, 2), # 中心位置
]
print("边界检查测试:")
for x, y in test_cases:
is_out = source_collector.outofmap(x, y)
expected = x < 0 or y < 0 or x >= 5 or y >= 5
status = "" if is_out == expected else ""
print(f" {status} ({x},{y}): {'边界外' if is_out else '边界内'}")
# 运行路径搜索
source_collector.run()
path = source_collector.get_path()
if path and len(path) > 0:
print(f"✅ 小迷宫路径生成成功,长度: {len(path)}")
return True
else:
print("❌ 小迷宫路径生成失败")
return False
except Exception as e:
print(f"❌ 小迷宫测试异常: {str(e)}")
traceback.print_exc()
return False
def test_direct_source_collector():
"""直接测试SourceCollector加载修复后的迷宫"""
print("\n=== 直接测试SourceCollector ===")
from simple_save_manager import simple_save_manager
test_file = "saves/maze_15_15_2.json"
if not os.path.exists(test_file):
print(f"❌ 测试文件 {test_file} 不存在")
return False
try:
# 直接使用simple_save_manager加载
load_data = simple_save_manager.load_maze_from_file(test_file)
if load_data is None:
print("❌ 文件加载失败")
return False
original_grid = load_data['original_grid']
print(f"加载的迷宫尺寸: {len(original_grid)}x{len(original_grid[0])}")
# 直接创建SourceCollector
source_collector = SourceCollector(maze=original_grid)
print(f"SourceCollector尺寸: {source_collector.rowNums}x{source_collector.colNums}")
print(f"起点: {source_collector.start_pos}")
print(f"终点: {source_collector.end_pos}")
# 运行路径搜索
source_collector.run()
path = source_collector.get_path()
if path and len(path) > 0:
print(f"✅ 直接测试路径生成成功,长度: {len(path)}")
return True
else:
print("❌ 直接测试路径生成失败")
return False
except Exception as e:
print(f"❌ 直接测试异常: {str(e)}")
traceback.print_exc()
return False
def main():
print("开始测试边界修复后的路径生成功能...")
tests = [
test_boundary_check_in_source_collector,
test_direct_source_collector,
test_source_collector_with_boundary_fix
]
passed = 0
total = len(tests)
for test in tests:
try:
if test():
passed += 1
else:
print(f"❌ 测试 {test.__name__} 失败")
except Exception as e:
print(f"❌ 测试 {test.__name__} 出现异常: {str(e)}")
print(f"\n=== 测试结果 ===")
print(f"通过: {passed}/{total}")
if passed == total:
print("🎉 所有路径生成修复测试通过!")
return True
else:
print("❌ 部分测试失败,请检查相关功能")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)