显示生成地图的历史记录

This commit is contained in:
Gary Gan 2025-06-30 13:14:34 +08:00
parent 2d9e17fa59
commit e577e286e4
10 changed files with 1741 additions and 18 deletions

View File

@ -145,7 +145,6 @@ class SourceCollector:
# 距离=曼哈顿距离 # 距离=曼哈顿距离
dist = abs(child.pos[0] - sn.pos[0]) + abs(child.pos[1] - sn.pos[1]) dist = abs(child.pos[0] - sn.pos[0]) + abs(child.pos[1] - sn.pos[1])
# 金币优先,陷阱次之 # 金币优先,陷阱次之
print(dist)
if self.maze[child.pos[0]][child.pos[1]].startswith('g'): if self.maze[child.pos[0]][child.pos[1]].startswith('g'):
return (0, dist) # 金币优先,距离近优先 return (0, dist) # 金币优先,距离近优先
elif self.maze[child.pos[0]][child.pos[1]].startswith('t'): elif self.maze[child.pos[0]][child.pos[1]].startswith('t'):

View File

@ -55,8 +55,15 @@ def get_button_positions(maze_display_size=MAZE_SIZE):
'next_step_button': (control_panel_x, 200), 'next_step_button': (control_panel_x, 200),
'reset_path_button': (control_panel_x + 120, 200), 'reset_path_button': (control_panel_x + 120, 200),
'auto_play_button': (control_panel_x + 250, 200), 'auto_play_button': (control_panel_x + 250, 200),
'progress_text': (control_panel_x, 270), # 历史迭代控制按钮
'hint_text': (control_panel_x, 300), 'history_prev_button': (control_panel_x, 260),
'shortcut_text': (control_panel_x, 330), 'history_next_button': (control_panel_x + 120, 260),
'save_list_area': (control_panel_x, 350, 400, 200) # x, y, width, height 'history_auto_button': (control_panel_x + 250, 260),
'history_toggle_button': (control_panel_x + 380, 260),
# 文本显示位置
'progress_text': (control_panel_x, 320),
'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, 200) # x, y, width, height
} }

113
main.py
View File

@ -47,13 +47,23 @@ def create_buttons(button_positions):
button_reset_path = Button(pygame.rect.Rect(*button_positions['reset_path_button'], *BUTTON_CONTROL_SIZE), None) 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_auto_play = Button(pygame.rect.Rect(*button_positions['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)
button_history_auto = Button(pygame.rect.Rect(*button_positions['history_auto_button'], *BUTTON_CONTROL_SIZE), None)
button_history_toggle = Button(pygame.rect.Rect(*button_positions['history_toggle_button'], *BUTTON_CONTROL_SIZE), None)
return { return {
'start': button_start, 'start': button_start,
'save': button_save, 'save': button_save,
'load': button_load, 'load': button_load,
'next_step': button_next_step, 'next_step': button_next_step,
'reset_path': button_reset_path, 'reset_path': button_reset_path,
'auto_play': button_auto_play 'auto_play': button_auto_play,
'history_prev': button_history_prev,
'history_next': button_history_next,
'history_auto': button_history_auto,
'history_toggle': button_history_toggle
} }
def update_save_ui_positions(save_ui, button_positions): def update_save_ui_positions(save_ui, button_positions):
@ -89,6 +99,11 @@ if __name__ == "__main__":
auto_play_timer = 0 auto_play_timer = 0
auto_play_interval = AUTO_PLAY_INTERVAL auto_play_interval = AUTO_PLAY_INTERVAL
# 历史迭代控制变量
history_auto_play = False
history_auto_timer = 0
history_auto_interval = AUTO_PLAY_INTERVAL // 2 # 历史播放速度稍快一些
# 当前显示尺寸跟踪 # 当前显示尺寸跟踪
current_display_size = MAZE_SIZE current_display_size = MAZE_SIZE
@ -106,13 +121,21 @@ if __name__ == "__main__":
print(f"UI布局已更新迷宫显示尺寸: {current_display_size}") print(f"UI布局已更新迷宫显示尺寸: {current_display_size}")
# 自动播放逻辑 # 自动播放逻辑
if auto_play and len(maze.full_path) > 0: if auto_play and len(maze.full_path) > 0 and not maze.show_history:
auto_play_timer += 1 auto_play_timer += 1
if auto_play_timer >= auto_play_interval: if auto_play_timer >= auto_play_interval:
if not maze.next_path_step(): if not maze.next_path_step():
auto_play = False # 路径播放完成后停止自动播放 auto_play = False # 路径播放完成后停止自动播放
auto_play_timer = 0 auto_play_timer = 0
# 历史迭代自动播放逻辑
if history_auto_play and len(maze.history_mazes) > 0 and maze.show_history:
history_auto_timer += 1
if history_auto_timer >= history_auto_interval:
if not maze.next_history_step():
history_auto_play = False # 历史播放完成后停止自动播放
history_auto_timer = 0
for event in pygame.event.get(): for event in pygame.event.get():
# 首先让存档界面处理事件 # 首先让存档界面处理事件
save_result = save_ui.handle_event(event, maze) save_result = save_ui.handle_event(event, maze)
@ -132,10 +155,20 @@ if __name__ == "__main__":
buttons['next_step'].handle_event(event=event) buttons['next_step'].handle_event(event=event)
buttons['reset_path'].handle_event(event=event) buttons['reset_path'].handle_event(event=event)
buttons['auto_play'].handle_event(event=event) buttons['auto_play'].handle_event(event=event)
# 历史迭代控制按钮
buttons['history_prev'].handle_event(event=event)
buttons['history_next'].handle_event(event=event)
buttons['history_auto'].handle_event(event=event)
buttons['history_toggle'].handle_event(event=event)
if buttons['start'].pressed == True: if buttons['start'].pressed == True:
maze.generate() maze.generate()
auto_play = False # 生成新迷宫时停止自动播放 auto_play = False # 生成新迷宫时停止自动播放
history_auto_play = False # 停止历史播放
auto_play_timer = 0 # 重置计时器
history_auto_timer = 0 # 重置历史计时器
print("已重置所有播放状态")
if buttons['save'].pressed == True: if buttons['save'].pressed == True:
if len(maze.grid) == 0: if len(maze.grid) == 0:
@ -179,27 +212,56 @@ if __name__ == "__main__":
save_ui.toggle_save_list() save_ui.toggle_save_list()
# 路径控制 # 路径控制
if buttons['next_step'].pressed == True and len(maze.full_path) > 0: if buttons['next_step'].pressed == True and len(maze.full_path) > 0 and not maze.show_history:
maze.next_path_step() maze.next_path_step()
if buttons['reset_path'].pressed == True and len(maze.full_path) > 0: if buttons['reset_path'].pressed == True and len(maze.full_path) > 0 and not maze.show_history:
maze.reset_path() maze.reset_path()
auto_play = False auto_play = False
if buttons['auto_play'].pressed == True and len(maze.full_path) > 0: if buttons['auto_play'].pressed == True and len(maze.full_path) > 0 and not maze.show_history:
auto_play = not auto_play auto_play = not auto_play
auto_play_timer = 0 auto_play_timer = 0
# 历史迭代控制
if buttons['history_prev'].pressed == True and len(maze.history_mazes) > 0 and maze.show_history:
maze.prev_history_step()
if buttons['history_next'].pressed == True and len(maze.history_mazes) > 0 and maze.show_history:
maze.next_history_step()
if buttons['history_auto'].pressed == True and len(maze.history_mazes) > 0 and maze.show_history:
history_auto_play = not history_auto_play
history_auto_timer = 0
if buttons['history_toggle'].pressed == True and len(maze.history_mazes) > 0:
maze.toggle_history_mode()
auto_play = False # 切换模式时停止路径播放
history_auto_play = False # 停止历史播放
# 键盘控制 # 键盘控制
if event.type == pygame.KEYDOWN: if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(maze.full_path) > 0: if event.key == pygame.K_SPACE and len(maze.full_path) > 0 and not maze.show_history:
maze.next_path_step() maze.next_path_step()
elif event.key == pygame.K_r and len(maze.full_path) > 0: elif event.key == pygame.K_r and len(maze.full_path) > 0 and not maze.show_history:
maze.reset_path() maze.reset_path()
auto_play = False auto_play = False
elif event.key == pygame.K_a and len(maze.full_path) > 0: elif event.key == pygame.K_a and len(maze.full_path) > 0 and not maze.show_history:
auto_play = not auto_play auto_play = not auto_play
auto_play_timer = 0 auto_play_timer = 0
# 历史迭代快捷键
elif event.key == pygame.K_LEFT and len(maze.history_mazes) > 0 and maze.show_history:
maze.prev_history_step()
elif event.key == pygame.K_RIGHT and len(maze.history_mazes) > 0 and maze.show_history:
maze.next_history_step()
elif event.key == pygame.K_h and len(maze.history_mazes) > 0:
maze.toggle_history_mode()
auto_play = False
history_auto_play = False
elif event.key == pygame.K_p and len(maze.history_mazes) > 0 and maze.show_history:
history_auto_play = not history_auto_play
history_auto_timer = 0
# 保存快捷键
elif event.key == pygame.K_s and pygame.key.get_pressed()[pygame.K_LCTRL]: elif event.key == pygame.K_s and pygame.key.get_pressed()[pygame.K_LCTRL]:
# Ctrl+S 保存包含路径的JSON # Ctrl+S 保存包含路径的JSON
if len(maze.grid) > 0: if len(maze.grid) > 0:
@ -228,8 +290,8 @@ if __name__ == "__main__":
buttons['save'].draw(screen=screen) buttons['save'].draw(screen=screen)
buttons['load'].draw(screen=screen) buttons['load'].draw(screen=screen)
# 绘制路径控制按钮 # 绘制路径控制按钮(仅在有路径且非历史模式时显示)
if len(maze.full_path) > 0: if len(maze.full_path) > 0 and not maze.show_history:
# 绘制按钮背景 # 绘制按钮背景
pygame.draw.rect(screen, COLOR_GRAY, buttons['next_step'].rect) pygame.draw.rect(screen, COLOR_GRAY, buttons['next_step'].rect)
pygame.draw.rect(screen, COLOR_GRAY, buttons['reset_path'].rect) pygame.draw.rect(screen, COLOR_GRAY, buttons['reset_path'].rect)
@ -248,10 +310,39 @@ if __name__ == "__main__":
progress_text = textFont.render(f"路径进度: {maze.path_step}/{len(maze.full_path)}", True, COLOR_BLACK) progress_text = textFont.render(f"路径进度: {maze.path_step}/{len(maze.full_path)}", True, COLOR_BLACK)
screen.blit(progress_text, button_positions['progress_text']) screen.blit(progress_text, button_positions['progress_text'])
# 绘制历史迭代控制按钮(仅在有历史且为历史模式时显示)
if len(maze.history_mazes) > 0 and maze.show_history:
# 绘制按钮背景
pygame.draw.rect(screen, COLOR_GRAY, buttons['history_prev'].rect)
pygame.draw.rect(screen, COLOR_GRAY, buttons['history_next'].rect)
pygame.draw.rect(screen, COLOR_GREEN if history_auto_play else COLOR_GRAY, buttons['history_auto'].rect)
# 绘制按钮文字
prev_text = textFont.render("上一步", True, COLOR_BLACK)
next_text = textFont.render("下一步", True, COLOR_BLACK)
auto_text = textFont.render("自动播放" if not history_auto_play else "停止", True, COLOR_BLACK)
screen.blit(prev_text, (buttons['history_prev'].rect.x + 10, buttons['history_prev'].rect.y + 15))
screen.blit(next_text, (buttons['history_next'].rect.x + 10, buttons['history_next'].rect.y + 15))
screen.blit(auto_text, (buttons['history_auto'].rect.x + 5, buttons['history_auto'].rect.y + 15))
# 显示历史进度信息
history_progress_text = textFont.render(f"生成进度: {maze.history_step}/{len(maze.history_mazes)}", True, COLOR_BLACK)
screen.blit(history_progress_text, button_positions['history_progress_text'])
# 绘制历史模式切换按钮(仅在有历史时显示)
if len(maze.history_mazes) > 0:
pygame.draw.rect(screen, COLOR_GOLD if maze.show_history else COLOR_GRAY, buttons['history_toggle'].rect)
toggle_text = textFont.render("历史模式" if not maze.show_history else "路径模式", True, COLOR_BLACK)
screen.blit(toggle_text, (buttons['history_toggle'].rect.x + 5, buttons['history_toggle'].rect.y + 15))
# 显示操作提示 # 显示操作提示
if len(maze.full_path) > 0: 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键: 自动播放", True, COLOR_LIGHT_GRAY)
screen.blit(hint_text, button_positions['hint_text']) 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'])
# 显示快捷键提示 # 显示快捷键提示
shortcut_text = textFont.render("Ctrl+S: 保存JSON | Shift+S: 保存CSV | Ctrl+L: 读档", True, COLOR_LIGHT_GRAY) shortcut_text = textFont.render("Ctrl+S: 保存JSON | Shift+S: 保存CSV | Ctrl+L: 读档", True, COLOR_LIGHT_GRAY)

83
maze.py
View File

@ -23,6 +23,13 @@ class Maze:
self.path_step = 0 # 当前显示到路径的第几步 self.path_step = 0 # 当前显示到路径的第几步
self.full_path = [] # 完整路径 self.full_path = [] # 完整路径
self.is_path_complete = False # 路径是否完全显示 self.is_path_complete = False # 路径是否完全显示
# 历史迭代展示相关
self.history_mazes = [] # 迷宫生成历史
self.history_step = 0 # 当前历史步骤
self.show_history = False # 是否正在展示历史
self.history_auto_play = False # 历史自动播放
self.history_timer = 0 # 历史播放计时器
def update_display_size(self): def update_display_size(self):
"""根据当前迷宫大小更新显示尺寸""" """根据当前迷宫大小更新显示尺寸"""
@ -46,16 +53,28 @@ class Maze:
def generate(self): def generate(self):
# 重置所有状态
self.reset_all_states()
# 生成新迷宫
seed = int(time.time() * 1000) % (2**32) seed = int(time.time() * 1000) % (2**32)
self.generater.generate(seed=seed) self.generater.generate(seed=seed)
# 获取生成历史
self.history_mazes = self.generater.get_history_mazes()
# 生成路径
self.source_collector = SourceCollector(maze=self.generater.maze) self.source_collector = SourceCollector(maze=self.generater.maze)
self.source_collector.run() self.source_collector.run()
self.full_path = self.source_collector.get_path() self.full_path = self.source_collector.get_path()
self.path_step = 0
self.is_path_complete = False # 设置显示状态
self.grid = self.generater.maze # 使用原始迷宫数据 self.grid = self.generater.maze # 使用原始迷宫数据
self.update_display_size() # 更新显示尺寸 self.update_display_size() # 更新显示尺寸
print(f"路径长度: {len(self.full_path)}") print(f"路径长度: {len(self.full_path)}")
print(f"生成历史步数: {len(self.history_mazes)}")
print("新迷宫生成完成")
def next_path_step(self): def next_path_step(self):
"""显示路径的下一步""" """显示路径的下一步"""
@ -130,6 +149,11 @@ class Maze:
self.grid = load_data['path_grid'] self.grid = load_data['path_grid']
self.update_display_size() # 更新显示尺寸 self.update_display_size() # 更新显示尺寸
# 读档时不展示历史迭代(清空历史数据)
self.history_mazes = []
self.history_step = 0
self.show_history = False
file_format = load_data.get('format', '未知') file_format = load_data.get('format', '未知')
print(f"成功加载游戏状态 ({file_format}格式),路径长度: {len(self.full_path)}") print(f"成功加载游戏状态 ({file_format}格式),路径长度: {len(self.full_path)}")
print(f"当前显示完整路径") print(f"当前显示完整路径")
@ -241,3 +265,58 @@ class Maze:
# 绘制迷宫边界线(动态位置) # 绘制迷宫边界线(动态位置)
pygame.draw.line(screen, (0, 0, 0), (self.actual_display_size, 0), (self.actual_display_size, self.actual_display_size), 3) pygame.draw.line(screen, (0, 0, 0), (self.actual_display_size, 0), (self.actual_display_size, self.actual_display_size), 3)
def toggle_history_mode(self):
"""切换历史展示模式"""
if len(self.history_mazes) > 0:
self.show_history = not self.show_history
if self.show_history:
# 切换到历史模式,显示当前历史步骤
self.update_grid_with_history()
else:
# 切换到路径模式,显示当前路径步骤
self.update_grid_with_path()
print(f"切换到{'历史' if self.show_history else '路径'}模式")
def next_history_step(self):
"""显示历史的下一步"""
if self.history_step < len(self.history_mazes) - 1:
self.history_step += 1
self.update_grid_with_history()
return True
return False
def prev_history_step(self):
"""显示历史的上一步"""
if self.history_step > 0:
self.history_step -= 1
self.update_grid_with_history()
return True
return False
def update_grid_with_history(self):
"""根据当前历史步数更新网格显示"""
if not self.history_mazes or self.history_step >= len(self.history_mazes):
return
# 显示指定历史步骤的迷宫状态
self.grid = [row[:] for row in self.history_mazes[self.history_step]] # 深拷贝
def reset_all_states(self):
"""重置所有状态(用于生成新迷宫时)"""
# 历史相关状态
self.history_mazes = []
self.history_step = 0
self.show_history = False
self.history_auto_play = False
self.history_timer = 0
# 路径相关状态
self.path_step = 0
self.is_path_complete = False
self.full_path = []
# 显示相关状态
self.grid = []
print("所有状态已重置")

View File

@ -174,6 +174,10 @@ class MazeGenerator:
def generate(self, seed=None, boss_count=1, traps_range=(3, 8), def generate(self, seed=None, boss_count=1, traps_range=(3, 8),
mechanisms_range=(2, 6), skill_traps=5): mechanisms_range=(2, 6), skill_traps=5):
"""生成迷宫主方法""" """生成迷宫主方法"""
# 清除之前的历史记录
self.history_mazes = []
self.special_elements = []
random.seed(seed or random.randint(0, 1000)) random.seed(seed or random.randint(0, 1000))
self.initialize_maze() self.initialize_maze()
self.create_maze(1, 1, self.size - 2, self.size - 2) self.create_maze(1, 1, self.size - 2, self.size - 2)

View File

@ -144,3 +144,50 @@ saves/
- **智能缩放算法**: 根据地图大小自动选择最佳显示参数 - **智能缩放算法**: 根据地图大小自动选择最佳显示参数
现在您的迷宫游戏完全支持您要求的JSON存档格式 现在您的迷宫游戏完全支持您要求的JSON存档格式
## 🔄 历史迭代展示功能 - **全新功能**
### 功能概述
在随机生成迷宫时,系统会记录每一步生成过程,用户可以回放查看迷宫的构建历史。
### 操作说明
#### 历史模式切换
- **按钮**: `历史模式` / `路径模式` 切换按钮
- **快捷键**: `H`
- **功能**: 在历史展示模式和路径展示模式之间切换
#### 历史控制按钮 (仅在历史模式下显示)
- **上一步**: 查看上一个生成步骤
- **下一步**: 查看下一个生成步骤
- **自动播放**: 自动播放生成历史动画
- **快捷键**:
- `←` 左箭头: 历史上一步
- `→` 右箭头: 历史下一步
- `P` 键: 历史自动播放切换
#### 重要特性
1. **生成时记录**: 只有随机生成的迷宫才有历史记录
2. **读档时无历史**: 从文件加载的迷宫不展示历史过程
3. **状态隔离**: 每次生成新迷宫时会清除之前的历史数据
4. **双模式**: 支持历史演示和路径演示两种独立模式
### 使用场景
- 🎓 **教学演示**: 展示迷宫生成算法的工作过程
- 🔍 **调试分析**: 了解递归分割算法的每个步骤
- 🎮 **娱乐观赏**: 观看迷宫"生长"的动画效果
## 🔧 修复内容
### 多次生成迷宫的状态重置修复
- **问题**: 连续点击Start按钮时之前的历史数据没有正确清除
- **修复**:
- 在 `MazeGenerator.generate()` 中添加历史数据清除
- 在 `Maze.generate()` 中使用 `reset_all_states()` 方法
- 确保每次生成新迷宫时所有相关状态都被正确重置
- **验证**: 通过专门的测试脚本确保多次生成不会有数据累加问题
### 状态管理优化
- **新增方法**: `Maze.reset_all_states()` - 统一重置所有状态
- **改进逻辑**: 确保历史模式、路径模式、自动播放等状态的正确切换
- **内存管理**: 避免历史数据在多次生成时累积导致内存问题

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""
测试历史迭代展示功能
验证生成过程的历史记录和展示功能
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from maze_generator import MazeGenerator
from maze import Maze
import time
def test_history_generation():
"""测试迷宫生成历史记录功能"""
print("=== 测试迷宫生成历史记录 ===")
generator = MazeGenerator(size=21, filename="test.csv", name="测试迷宫")
generator.generate(seed=12345)
history = generator.get_history_mazes()
print(f"历史步数: {len(history)}")
if len(history) == 0:
print("❌ 历史记录为空")
return False
# 验证历史记录的每一步都是有效的迷宫
for i, maze_state in enumerate(history):
if len(maze_state) != 21 or len(maze_state[0]) != 21:
print(f"❌ 历史步骤 {i} 尺寸错误: {len(maze_state)}x{len(maze_state[0])}")
return False
print(f"✅ 历史记录验证通过,共 {len(history)}")
return True
def test_maze_history_methods():
"""测试Maze类的历史展示方法"""
print("\n=== 测试Maze历史展示方法 ===")
maze = Maze(wall_size=30, maze_size=630, file_name="test.csv")
maze.generate()
# 验证历史数据
if len(maze.history_mazes) == 0:
print("❌ 生成后历史数据为空")
return False
print(f"历史步数: {len(maze.history_mazes)}")
print(f"初始历史步骤: {maze.history_step}")
print(f"初始展示模式: {'历史' if maze.show_history else '路径'}")
# 测试历史步骤控制
original_step = maze.history_step
# 测试下一步
result = maze.next_history_step()
if result and maze.history_step == original_step + 1:
print("✅ next_history_step 正常工作")
else:
print(f"❌ next_history_step 失败,步骤: {original_step} -> {maze.history_step}")
return False
# 测试上一步
result = maze.prev_history_step()
if result and maze.history_step == original_step:
print("✅ prev_history_step 正常工作")
else:
print(f"❌ prev_history_step 失败,步骤: {maze.history_step}")
return False
# 测试模式切换
original_mode = maze.show_history
maze.toggle_history_mode()
if maze.show_history != original_mode:
print("✅ toggle_history_mode 正常工作")
else:
print("❌ toggle_history_mode 失败")
return False
# 切换回原模式
maze.toggle_history_mode()
return True
def test_load_without_history():
"""测试加载存档时不展示历史"""
print("\n=== 测试加载存档时历史处理 ===")
# 先生成一个迷宫并保存
maze1 = Maze(wall_size=30, maze_size=600, file_name="test.csv")
maze1.generate()
if len(maze1.history_mazes) == 0:
print("❌ 生成的迷宫没有历史数据")
return False
print(f"生成迷宫的历史步数: {len(maze1.history_mazes)}")
# 保存迷宫
save_result = maze1.save_game(format_type="json")
if not save_result:
print("❌ 保存迷宫失败")
return False
# 创建新的迷宫实例并加载
maze2 = Maze(wall_size=30, maze_size=600, file_name="test.csv")
# 假设有一个保存的文件
import glob
json_files = glob.glob("saves/*.json")
if not json_files:
print("❌ 没有找到保存的JSON文件")
return False
load_result = maze2.load_game(json_files[0])
if not load_result:
print("❌ 加载迷宫失败")
return False
# 验证加载后历史数据被清空
if len(maze2.history_mazes) == 0 and not maze2.show_history:
print("✅ 加载存档后历史数据正确清空")
return True
else:
print(f"❌ 加载存档后历史数据未正确清空: {len(maze2.history_mazes)} 步, 展示模式: {maze2.show_history}")
return False
def test_history_boundary_conditions():
"""测试历史展示的边界条件"""
print("\n=== 测试历史展示边界条件 ===")
maze = Maze(wall_size=30, maze_size=600, file_name="test.csv")
maze.generate()
if len(maze.history_mazes) == 0:
print("❌ 没有历史数据进行测试")
return False
# 测试超出上限
maze.history_step = len(maze.history_mazes) - 1
result = maze.next_history_step()
if not result:
print("✅ 历史步骤上限控制正常")
else:
print("❌ 历史步骤上限控制失败")
return False
# 测试超出下限
maze.history_step = 0
result = maze.prev_history_step()
if not result:
print("✅ 历史步骤下限控制正常")
else:
print("❌ 历史步骤下限控制失败")
return False
return True
def main():
print("开始测试历史迭代展示功能...")
tests = [
test_history_generation,
test_maze_history_methods,
test_load_without_history,
test_history_boundary_conditions
]
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)

203
tests/test_history_reset.py Normal file
View File

@ -0,0 +1,203 @@
#!/usr/bin/env python3
"""
测试多次生成迷宫时历史数据重置功能
验证连续生成迷宫时不会有历史数据混乱
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from maze import Maze
import time
def test_multiple_generation():
"""测试多次生成迷宫时历史数据重置"""
print("=== 测试多次生成迷宫历史重置 ===")
maze = Maze(wall_size=30, maze_size=600, file_name="test.csv")
# 第一次生成迷宫
print("\n--- 第一次生成迷宫 ---")
maze.generate()
first_history_count = len(maze.history_mazes)
first_path_count = len(maze.full_path)
print(f"第一次生成 - 历史步数: {first_history_count}, 路径长度: {first_path_count}")
if first_history_count == 0:
print("❌ 第一次生成后没有历史数据")
return False
# 验证初始状态
if maze.history_step != 0 or maze.show_history != False or maze.path_step != 0:
print(f"❌ 第一次生成后状态不正确: history_step={maze.history_step}, show_history={maze.show_history}, path_step={maze.path_step}")
return False
# 切换到历史模式并前进几步
maze.toggle_history_mode()
maze.next_history_step()
maze.next_history_step()
print(f"历史模式前进后 - history_step: {maze.history_step}, show_history: {maze.show_history}")
# 第二次生成迷宫
print("\n--- 第二次生成迷宫 ---")
maze.generate()
second_history_count = len(maze.history_mazes)
second_path_count = len(maze.full_path)
print(f"第二次生成 - 历史步数: {second_history_count}, 路径长度: {second_path_count}")
# 验证状态重置
if maze.history_step != 0:
print(f"❌ 第二次生成后history_step未重置: {maze.history_step}")
return False
if maze.show_history != False:
print(f"❌ 第二次生成后show_history未重置: {maze.show_history}")
return False
if maze.path_step != 0:
print(f"❌ 第二次生成后path_step未重置: {maze.path_step}")
return False
if second_history_count == 0:
print("❌ 第二次生成后没有新的历史数据")
return False
# 验证历史数据是全新的(长度可能不同)
if second_history_count == first_history_count:
# 如果长度相同,检查内容是否不同
if maze.history_mazes[0] == maze.history_mazes[0]: # 比较第一步
print("⚠️ 两次生成的历史数据第一步相同(可能是随机种子问题,但功能正常)")
print(f"✅ 第二次生成后所有状态正确重置")
# 第三次生成以确保一致性
print("\n--- 第三次生成迷宫 ---")
# 先改变一些状态
maze.toggle_history_mode()
maze.next_history_step()
maze.next_path_step()
maze.generate()
third_history_count = len(maze.history_mazes)
third_path_count = len(maze.full_path)
print(f"第三次生成 - 历史步数: {third_history_count}, 路径长度: {third_path_count}")
# 再次验证状态重置
if maze.history_step != 0 or maze.show_history != False or maze.path_step != 0:
print(f"❌ 第三次生成后状态未正确重置")
return False
print("✅ 第三次生成后状态也正确重置")
return True
def test_maze_generator_reset():
"""测试MazeGenerator的历史重置"""
print("\n=== 测试MazeGenerator历史重置 ===")
from maze_generator import MazeGenerator
generator = MazeGenerator(size=21, filename="test.csv", name="测试")
# 第一次生成
generator.generate(seed=12345)
first_history = len(generator.get_history_mazes())
first_elements = len(generator.special_elements)
print(f"第一次生成 - 历史: {first_history}, 特殊元素: {first_elements}")
# 第二次生成
generator.generate(seed=54321)
second_history = len(generator.get_history_mazes())
second_elements = len(generator.special_elements)
print(f"第二次生成 - 历史: {second_history}, 特殊元素: {second_elements}")
if first_history == 0 or second_history == 0:
print("❌ 生成器历史数据为空")
return False
# 验证特殊元素也被重置
if second_elements == 0:
print("❌ 第二次生成后特殊元素为空")
return False
print("✅ MazeGenerator历史和特殊元素正确重置")
return True
def test_state_isolation():
"""测试不同迷宫实例之间的状态隔离"""
print("\n=== 测试迷宫实例状态隔离 ===")
# 创建两个迷宫实例
maze1 = Maze(wall_size=30, maze_size=600, file_name="test1.csv")
maze2 = Maze(wall_size=30, maze_size=600, file_name="test2.csv")
# 生成第一个迷宫
maze1.generate()
history1 = len(maze1.history_mazes)
# 修改第一个迷宫的状态
maze1.toggle_history_mode()
maze1.next_history_step()
# 生成第二个迷宫
maze2.generate()
history2 = len(maze2.history_mazes)
# 验证第二个迷宫的状态是独立的
if maze2.show_history != False or maze2.history_step != 0:
print(f"❌ 第二个迷宫状态被第一个影响: show_history={maze2.show_history}, history_step={maze2.history_step}")
return False
# 验证第一个迷宫状态没变
if maze1.show_history != True or maze1.history_step == 0:
print(f"❌ 第一个迷宫状态意外改变: show_history={maze1.show_history}, history_step={maze1.history_step}")
return False
print(f"✅ 两个迷宫实例状态正确隔离 (历史: {history1}, {history2})")
return True
def main():
print("开始测试多次生成迷宫时历史数据重置...")
tests = [
test_multiple_generation,
test_maze_generator_reset,
test_state_isolation
]
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)

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""
快速测试主程序的Start按钮多次点击功能
这个脚本模拟用户快速点击Start按钮的情况
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
print("=== Start按钮多次点击测试 ===")
print()
print("此测试将启动主程序。请按以下步骤测试:")
print()
print("1. 程序启动后,点击 [Start] 按钮生成第一个迷宫")
print("2. 观察历史步数和路径长度信息")
print("3. 点击 [历史模式] 按钮,进入历史展示模式")
print("4. 使用历史控制按钮前进几步")
print("5. 再次点击 [Start] 按钮生成第二个迷宫")
print("6. 验证:")
print(" - 历史步数应该是新的(不是之前的累加)")
print(" - 应该自动切换回路径模式")
print(" - 历史步骤应该重置为0")
print(" - 所有播放状态应该停止")
print("7. 可以重复步骤1-6多次验证")
print()
print("预期结果:")
print("- 每次点击Start后控制台会显示'所有状态已重置'")
print("- 每次生成的历史步数是独立的新数据")
print("- 不会出现历史数据累加或状态混乱")
print("- UI应该正确显示当前模式和步数")
print()
input("按 Enter 键启动程序进行测试...")
try:
import main
except KeyboardInterrupt:
print("\n测试完成,程序已退出")
except Exception as e:
print(f"\n程序运行出现错误: {str(e)}")
print("请检查相关代码和依赖")