maze_python/simple_save_manager.py

462 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import csv
import json
import os
from datetime import datetime
from config import DEFAULT_MAZE_FILE
class SimpleSaveManager:
"""简化的存档管理器 - 支持JSON和CSV格式的迷宫文件"""
def __init__(self):
self.save_directory = "saves"
self.ensure_save_directory()
def ensure_save_directory(self):
"""确保存档目录存在"""
if not os.path.exists(self.save_directory):
os.makedirs(self.save_directory)
def save_maze_with_path(self, maze_instance, save_name=None, format_type="json"):
"""
保存包含路径信息的迷宫到文件
Args:
maze_instance: Maze类的实例
save_name: 存档名称如果为None则使用时间戳
format_type: 文件格式 "json""csv"
Returns:
str: 保存的文件路径
"""
if save_name is None:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
save_name = f"maze_save_{timestamp}"
# 根据格式类型确定文件扩展名
if format_type.lower() == "json":
if not save_name.endswith('.json'):
save_name += '.json'
return self._save_maze_json(maze_instance, save_name)
else:
if not save_name.endswith('.csv'):
save_name += '.csv'
return self._save_maze_csv(maze_instance, save_name)
def create_path_grid(self, maze_instance):
"""
创建包含路径信息的网格
Args:
maze_instance: Maze类的实例
Returns:
list: 包含路径信息的二维网格
"""
if not maze_instance.generater.maze or not maze_instance.full_path:
return maze_instance.generater.maze if maze_instance.generater.maze else []
# 从原始迷宫开始
path_grid = [row[:] for row in maze_instance.generater.maze] # 深拷贝
# 将完整路径信息添加到网格中
for idx, (y, x) in enumerate(maze_instance.full_path):
current_cell = path_grid[y][x]
path_info = f"p{idx + 1}" # 路径编号从1开始
if current_cell.startswith('s'):
# 起点:保留起点标记,但也添加路径信息
path_grid[y][x] = f"s{path_info}"
elif current_cell.startswith('e'):
# 终点:保留终点标记,但也添加路径信息
path_grid[y][x] = f"e{path_info}"
elif current_cell.startswith('g'):
# 金币g10p31 格式
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('t'):
# 陷阱t19p31 格式
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('l'):
# 机关l24p31 格式
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('b'):
# bossb92p31 格式
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell == '0':
# 空地直接是p31
path_grid[y][x] = path_info
else:
# 其他情况也添加路径信息
path_grid[y][x] = f"{current_cell}{path_info}"
return path_grid
def load_maze_from_file(self, file_path):
"""
从文件加载迷宫,自动检测文件格式
Args:
file_path: 文件路径
Returns:
dict: 包含迷宫数据和路径信息的字典
"""
if file_path.endswith('.json'):
return self.load_maze_from_json(file_path)
elif file_path.endswith('.csv'):
return self.load_maze_from_csv(file_path)
else:
print(f"不支持的文件格式: {file_path}")
return None
def load_maze_from_json(self, json_file):
"""
从JSON文件加载迷宫
Args:
json_file: JSON文件路径
Returns:
dict: 包含迷宫数据和路径信息的字典
"""
try:
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
# 检查数据结构
if 'maze' not in data:
print("JSON文件格式错误缺少maze字段")
return None
# 转换JSON格式到内部格式
internal_maze = self.convert_from_json_format(data['maze'])
result = {
'original_grid': internal_maze,
'path_grid': internal_maze, # 对于JSON格式初始时路径网格与原始网格相同
'path_sequence': [],
'path_positions': {},
'metadata': data.get('metadata', {}),
'format': 'json'
}
# 如果有路径数据,也加载路径信息
if 'path_data' in data:
raw_path = data['path_data'].get('full_path', [])
# 确保路径数据是元组格式 (JSON会将元组转换为列表)
result['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 result['path_sequence']:
result['path_grid'] = self.create_path_grid_from_data(internal_maze, result['path_sequence'])
print(f"成功从 {os.path.abspath(json_file)} 加载迷宫")
if result['path_sequence']:
print(f"路径长度: {len(result['path_sequence'])}")
return result
except Exception as e:
print(f"JSON加载失败: {str(e)}")
return None
def load_maze_from_csv(self, csv_file):
"""
从CSV文件加载迷宫解析路径信息
Args:
csv_file: CSV文件路径
Returns:
dict: 包含迷宫数据和路径信息的字典
"""
try:
with open(csv_file, 'r', newline='', encoding='utf-8') as f:
reader = csv.reader(f)
grid = [list(row) for row in reader]
# 解析路径信息
path_data = self.extract_path_from_grid(grid)
# 创建原始迷宫(移除路径信息)
original_grid = self.create_original_grid(grid)
result = {
'original_grid': original_grid,
'path_grid': grid,
'path_sequence': path_data['path_sequence'],
'path_positions': path_data['path_positions'],
'format': 'csv'
}
print(f"成功从 {os.path.abspath(csv_file)} 加载迷宫")
print(f"路径长度: {len(path_data['path_sequence'])}")
return result
except Exception as e:
print(f"CSV加载失败: {str(e)}")
return None
def create_path_grid_from_data(self, original_grid, path_sequence):
"""从原始网格和路径序列创建包含路径信息的网格"""
path_grid = [row[:] for row in original_grid] # 深拷贝
for idx, (y, x) in enumerate(path_sequence):
if y >= len(path_grid) or x >= len(path_grid[0]):
continue
current_cell = path_grid[y][x]
path_info = f"p{idx + 1}" # 路径编号从1开始
if current_cell.startswith('s'):
path_grid[y][x] = f"s{path_info}"
elif current_cell.startswith('e'):
path_grid[y][x] = f"e{path_info}"
elif current_cell.startswith('g'):
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('t'):
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('l'):
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell.startswith('b'):
path_grid[y][x] = f"{current_cell}{path_info}"
elif current_cell == '0':
path_grid[y][x] = path_info
else:
path_grid[y][x] = f"{current_cell}{path_info}"
return path_grid
def extract_path_from_grid(self, grid):
"""从网格中提取路径信息"""
path_positions = {} # {step_number: (y, x)}
for y in range(len(grid)):
for x in range(len(grid[y])):
cell = grid[y][x]
# 查找所有路径信息 p数字
import re
# 使用正则表达式找到所有p后跟数字的模式
path_matches = re.findall(r'p(\d+)', cell)
for path_match in path_matches:
try:
step_number = int(path_match)
path_positions[step_number] = (y, x)
except ValueError:
continue
# 按步数排序创建路径序列
path_sequence = []
for step in sorted(path_positions.keys()):
path_sequence.append(path_positions[step])
return {
'path_sequence': path_sequence,
'path_positions': path_positions
}
def create_original_grid(self, path_grid):
"""从包含路径的网格创建原始迷宫网格"""
original_grid = []
for row in path_grid:
original_row = []
for cell in row:
# 移除路径信息,恢复原始状态
if 'p' in cell:
p_index = cell.find('p')
original_cell = cell[:p_index] if p_index > 0 else '0'
else:
original_cell = cell
original_row.append(original_cell)
original_grid.append(original_row)
return original_grid
def get_save_list(self):
"""获取所有存档文件列表支持JSON和CSV格式"""
saves = []
if os.path.exists(self.save_directory):
for filename in os.listdir(self.save_directory):
if filename.endswith('.csv') or filename.endswith('.json'):
file_path = os.path.join(self.save_directory, filename)
try:
stat = os.stat(file_path)
# 确定文件格式
file_format = 'json' if filename.endswith('.json') else 'csv'
# 移除扩展名作为名称
name = filename.replace('.json', '').replace('.csv', '')
saves.append({
'filename': filename,
'path': file_path,
'name': name,
'save_time': datetime.fromtimestamp(stat.st_mtime).isoformat(),
'size': stat.st_size,
'format': file_format
})
except:
continue
return sorted(saves, key=lambda x: x['save_time'], reverse=True)
def delete_save(self, save_file):
"""删除存档文件"""
try:
if os.path.exists(save_file):
os.remove(save_file)
print(f"存档已删除: {save_file}")
return True
except Exception as e:
print(f"删除失败: {str(e)}")
return False
def _save_maze_json(self, maze_instance, save_name):
"""保存迷宫为JSON格式"""
save_file = os.path.join(self.save_directory, save_name)
try:
# 转换迷宫格式
json_maze = self.convert_to_json_format(maze_instance)
# 创建保存数据结构
save_data = {
"maze": json_maze,
"metadata": {
"save_name": save_name.replace('.json', ''),
"save_time": datetime.now().isoformat(),
"maze_size": maze_instance.size,
"path_length": len(maze_instance.full_path) if maze_instance.full_path else 0
}
}
# 如果有路径信息,也保存路径
if maze_instance.full_path:
save_data["path_data"] = {
"full_path": maze_instance.full_path,
"current_step": maze_instance.path_step,
"is_path_complete": maze_instance.is_path_complete
}
# 保存为JSON文件
with open(save_file, 'w', encoding='utf-8') as f:
json.dump(save_data, f, indent=2, ensure_ascii=False)
print(f"迷宫已保存至: {os.path.abspath(save_file)}")
return save_file
except Exception as e:
print(f"JSON保存失败: {str(e)}")
return None
def _save_maze_csv(self, maze_instance, save_name):
"""保存迷宫为CSV格式原有功能"""
save_file = os.path.join(self.save_directory, save_name)
try:
# 生成包含路径信息的网格
path_grid = self.create_path_grid(maze_instance)
# 保存到CSV文件
with open(save_file, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
for row in path_grid:
writer.writerow(row)
print(f"迷宫已保存至: {os.path.abspath(save_file)}")
return save_file
except Exception as e:
print(f"CSV保存失败: {str(e)}")
return None
def convert_to_json_format(self, maze_instance):
"""
将内部迷宫格式转换为JSON格式
内部格式 -> JSON格式:
'1' -> '#' (墙壁)
'0' -> ' ' (通路)
's' -> 'S' (起点)
'e' -> 'E' (终点)
'g数字' -> 'G' (金币)
't数字' -> 'T' (陷阱)
'l数字' -> 'L' (机关)
'b数字' -> 'B' (BOSS)
"""
if not maze_instance.generater.maze:
return []
json_maze = []
for row in maze_instance.generater.maze:
json_row = []
for cell in row:
cell_str = str(cell)
if cell_str == '1':
json_row.append('#')
elif cell_str == '0':
json_row.append(' ')
elif cell_str == 's':
json_row.append('S')
elif cell_str == 'e':
json_row.append('E')
elif cell_str.startswith('g'):
json_row.append('G')
elif cell_str.startswith('t'):
json_row.append('T')
elif cell_str.startswith('l'):
json_row.append('L')
elif cell_str.startswith('b'):
json_row.append('B')
else:
# 未知类型,默认为通路
json_row.append(' ')
json_maze.append(json_row)
return json_maze
def convert_from_json_format(self, json_maze):
"""
将JSON格式转换为内部迷宫格式
JSON格式 -> 内部格式:
'#' -> '1' (墙壁)
' ' -> '0' (通路)
'S' -> 's' (起点)
'E' -> 'e' (终点)
'G' -> 'g10' (金币默认值10)
'T' -> 't15' (陷阱默认值15)
'L' -> 'l20' (机关默认值20)
'B' -> 'b50' (BOSS默认值50)
"""
internal_maze = []
for row in json_maze:
internal_row = []
for cell in row:
if cell == '#':
internal_row.append('1')
elif cell == ' ':
internal_row.append('0')
elif cell == 'S':
internal_row.append('s')
elif cell == 'E':
internal_row.append('e')
elif cell == 'G':
internal_row.append('g10') # 默认金币值
elif cell == 'T':
internal_row.append('t15') # 默认陷阱值
elif cell == 'L':
internal_row.append('l20') # 默认机关值
elif cell == 'B':
internal_row.append('b50') # 默认BOSS值
else:
# 未知类型,默认为通路
internal_row.append('0')
internal_maze.append(internal_row)
return internal_maze
# 全局简化存档管理器实例
simple_save_manager = SimpleSaveManager()