Files
bettergi-scripts-list/repo/js/AutoLeyLineOutcrop/generate_data_format.py
214-hanyan 5f5249b348 识别体力与树脂数量 (#981)
* 识别体力与树脂数量

* 璃月6-奥藏山

* update repo.json

* 地图追踪 星银矿石 (#1025)

* Add files via upload

* 自动修复 JSON 格式和版本号 [ci skip]

* Delete repo/pathing/矿物/星银矿石/desktop.ini

* Add files via upload

---------

Co-authored-by: GitHub Actions Bot <actions@github.com>

* Update main.js (#1024)

手动终止夹断

* update repo.json

* 6.7 富Abpro (#1022)

* Add files via upload

* Add files via upload

* Delete repo/js/AutoArtifactsPro/assets/ArtifactsPath/A路线/01普通/000【激活程序】稻妻大炮.json

* Delete repo/js/AutoArtifactsPro/assets/ArtifactsPath/A路线/01普通/404须弥-天臂池七天神像4.json

* Delete repo/js/AutoArtifactsPro/assets/ArtifactsPath/A路线/01普通/601纳塔-流泉之众4.json

* Delete repo/js/AutoArtifactsPro/assets/ArtifactsPath/A路线/01普通/602纳塔-悬木人声望2.json

* Delete repo/js/AutoArtifactsPro/assets/ArtifactsPath/A路线/01普通/603纳塔-花羽会西2.json

* Add files via upload

* update repo.json

* `七圣召唤七日历练`: 修复牌币已满时卡在出战界面的问题 (#1017)

* update repo.json

* js:狗粮重置版1.2更新 (#1026)

* update repo.json

* fix: 修复部分情况下未找到图标直接结束

* temp

* add: 璃月7

* feat: 新的数据结构

* add: 合并代码,功能待实现

---------

Co-authored-by: 寒烟 <2841974482@qq.com>
Co-authored-by: physligl <181079228+physligl@users.noreply.github.com>
Co-authored-by: Tooltingsu <143606015+Tooltingsu@users.noreply.github.com>
Co-authored-by: GitHub Actions Bot <actions@github.com>
Co-authored-by: JJMdzh <jjjjedyx@qq.com>
Co-authored-by: 汐 <121607261+jiegedabaobei@users.noreply.github.com>
Co-authored-by: Patrick-Ze <19711799+Patrick-Ze@users.noreply.github.com>
Co-authored-by: mno <718135749@qq.com>
Co-authored-by: 秋云 <physligl@gmail.com>
2025-06-09 06:13:27 +08:00

860 lines
40 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.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
import sys
import re
def format_coord(num):
return round(float(num), 2)
def calculate_distance(x1, y1, x2, y2):
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
# 定义区域排序顺序
REGION_ORDER = {
"蒙德": 1,
"璃月": 2,
"稻妻": 3,
"须弥": 4,
"枫丹": 5,
"纳塔": 6,
"未知区域": 99 # 未知区域放最后
}
def get_region_sort_key(region_name):
"""获取区域的排序键值,用于排序"""
# 从完整区域名称(如"枫丹1-1")中提取基本区域名称(如"枫丹"
base_region = re.match(r"^([^0-9]+)", region_name)
if base_region:
base_region = base_region.group(1)
return REGION_ORDER.get(base_region, 99)
return 99
def normalize_region_name(region_name, region_num, route_num, route_sub_num=None):
"""规范化区域名称,确保命名一致性
例如:
- 标准格式: 蒙德3, 奔狼领, 2 -> 蒙德3-2
- 特殊格式: 蒙德2, 清泉镇, 4, 1 -> 蒙德2-4-1
"""
if route_sub_num is not None:
# 特殊格式
return f"{region_name}{region_num}-{route_num}-{route_sub_num}"
else:
# 标准格式
return f"{region_name}{region_num}-{route_num}"
def is_same_region_base(region1, region2):
"""检查两个区域名称是否属于同一基本区域
例如,"蒙德2-4-1""蒙德2-4-2"属于同一基本区域"蒙德2-4"
"""
# 提取区域名称的基本部分(例如从"蒙德2-4-1"提取"蒙德2-4"
base_region1 = re.match(r"^([^-]+-\d+)", region1)
base_region2 = re.match(r"^([^-]+-\d+)", region2)
return (base_region1 and base_region2 and
base_region1.group(1) == base_region2.group(1))
def parse_region_area_number(filename):
"""从文件名解析区域、地区和编号
支持两种格式:
1. 标准格式: 蒙德3-奔狼领-2.json -> ("蒙德", 3, "奔狼领", 2)
2. 特殊格式: 蒙德2-清泉镇-4-1.json -> ("蒙德", 2, "清泉镇", 4, 1)
"""
# 先尝试匹配特殊格式(带有额外连字符的格式)
special_pattern = r"^([^0-9]+)(\d+)-(.+)-(\d+)-(\d+(?:\.\d+)?)\.json$"
match = re.match(special_pattern, filename)
if match:
region_name = match.group(1)
region_num = int(match.group(2))
area = match.group(3)
route_num = int(match.group(4))
route_sub_num = int(match.group(5))
return region_name, region_num, area, route_num, route_sub_num
# 如果不是特殊格式,尝试匹配标准格式
standard_pattern = r"^([^0-9]+)(\d+)-(.+)-(\d+(?:\.\d+)?)\.json$"
match = re.match(standard_pattern, filename)
if match:
region_name = match.group(1)
region_num = int(match.group(2))
area = match.group(3)
route_num = int(match.group(4))
return region_name, region_num, area, route_num
# 如果都不匹配,返回默认值
print(f"警告:无法解析文件名 {filename}")
return None, None, None, None
def generate_new_data_structure_from_pathing():
"""直接从assets/pathing目录读取文件生成新的数据结构"""
# 获取脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))
pathing_dir = os.path.join(script_dir, "assets", "pathing")
target_dir = os.path.join(pathing_dir, "target")
# 检查目录是否存在
if not os.path.exists(pathing_dir):
print(f"错误:找不到路径目录 {pathing_dir}")
return None
# 初始化新数据结构,分开存储 blossom 和 teleport
new_data = {
"teleports": [], # 传送点节点
"blossoms": [], # 地脉花节点
"edges": [], # 边集合
"indexes": {
"edgesBySource": {},
"edgesByTarget": {}
}
}
# 创建独立的ID计数器和节点映射
next_teleport_id = 1 # 传送点专用ID计数器
next_blossom_id = 1000 # 地脉花专用ID计数器
teleport_nodes = {} # 按坐标存储传送点节点 (x, y) -> node_id
target_nodes = {} # 按坐标存储目标点节点 (x, y) -> node_id
# 创建文件路径映射
file_paths = {}
# 第一遍:读取所有路径文件并创建节点
print("第一遍:读取路径文件并创建节点...")
for root, _, files in os.walk(pathing_dir):
for file in sorted(files):
# 跳过非JSON文件和重运行文件
if not file.endswith('.json') or 'rerun' in file or 'rerun' in root:
continue
# 跳过target目录
if "target" in root.split(os.path.sep):
continue
file_path = os.path.join(root, file)
try:
with open(file_path, 'r', encoding='utf-8') as f:
path_data = json.load(f)
# 记录文件路径
relative_path = os.path.relpath(file_path, script_dir)
relative_path = relative_path.replace("\\", "/")
file_paths[file] = relative_path
# 检查文件是否有position数据
if "positions" not in path_data or not path_data["positions"]:
continue
# 获取第一个位置点(通常是传送点)
first_pos = path_data["positions"][0]
if "type" in first_pos and first_pos["type"] == "teleport":
x = format_coord(first_pos["x"])
y = format_coord(first_pos["y"]) # 解析区域信息
result = parse_region_area_number(file)
if len(result) == 5: # 特殊格式
region_name, region_num, _, _, _ = result
else: # 标准格式或无法解析
region_name, region_num, _, _ = result
# 传送点仅显示区域名称,不显示编号
region = f"{region_name}" if region_name else "未知区域"
# 检查是否已存在相同坐标的传送点
existing_node = False
for coord, node_id in teleport_nodes.items():
if calculate_distance(coord[0], coord[1], x, y) < 10: # 将阈值从50降低到10
existing_node = True
break
if not existing_node: # 创建新的传送点节点
teleport_node = {
"id": next_teleport_id,
"region": region,
"position": {"x": x, "y": y}
}
new_data["teleports"].append(teleport_node)
teleport_nodes[(x, y)] = next_teleport_id
next_teleport_id += 1
print(f" 创建传送点: ID={teleport_node['id']}, 区域={region}, 坐标=({x}, {y})")
except Exception as e:
print(f" 警告:处理文件 {file} 时出错: {e}")
# 第二遍读取target目录文件并创建目标节点
print("\n第二遍读取target文件并创建目标节点...")
for file in sorted(os.listdir(target_dir)):
if not file.endswith('.json'):
continue
file_path = os.path.join(target_dir, file)
try:
with open(file_path, 'r', encoding='utf-8') as f:
target_data = json.load(f)
# 检查文件是否有position数据
if "positions" not in target_data or not target_data["positions"]:
continue
# 获取第一个位置点(通常是目标点)
target_pos = target_data["positions"][0]
x = format_coord(target_pos["x"])
y = format_coord(target_pos["y"])
result = parse_region_area_number(file)
if len(result) == 5: # 特殊格式
region_name, region_num, area, route_num, route_sub_num = result
# 使用规范化函数来生成区域名
region = normalize_region_name(region_name, region_num, route_num, route_sub_num)
else: # 标准格式或无法解析
region_name, region_num, area, route_num = result
# 使用规范化函数来生成区域名
region = normalize_region_name(region_name, region_num, route_num) if region_name and region_num and route_num else "未知区域" # 检查是否已存在相同坐标的目标点和相同区域名
existing_node = False
existing_node_id = None
for coord, node_id in target_nodes.items():
if calculate_distance(coord[0], coord[1], x, y) < 10: # 阈值为10
# 找到这个节点,检查它的区域是否与当前区域相同
for blossom in new_data["blossoms"]:
if blossom["id"] == node_id:
# 检查区域名完全相同
if blossom["region"] == region:
existing_node = True
existing_node_id = node_id
break
# 检查区域名基本部分是否相同(如"蒙德2-4"和"蒙德2-4-2"
# 提取区域名称的基本部分(例如从"蒙德2-4-1"提取"蒙德2-4"
current_base_region = re.match(r"^([^-]+-\d+)", region)
existing_base_region = re.match(r"^([^-]+-\d+)", blossom["region"])
if (current_base_region and existing_base_region and
current_base_region.group(1) == existing_base_region.group(1)):
print(f" 注意: 坐标 ({x}, {y}) 与已存在节点 '{blossom['region']}' 区域基本部分相同,视为同一节点")
existing_node = True
existing_node_id = node_id
break
if not existing_node:
print(f" 注意: 坐标 ({x}, {y}) 附近有另一个区域的节点,但将创建新节点")
if not existing_node:
# 创建新的目标点节点
target_node = {
"id": next_blossom_id,
"region": region,
"position": {"x": x, "y": y}
}
new_data["blossoms"].append(target_node)
target_nodes[(x, y)] = next_blossom_id
next_blossom_id += 1
print(f" 创建目标点: ID={target_node['id']}, 区域={region}, 坐标=({x}, {y})")
except Exception as e:
print(f" 警告:处理目标文件 {file} 时出错: {e}")
# 第三遍:创建边和索引
print("\n第三遍:创建边和索引...")
for file in sorted(os.listdir(pathing_dir)):
if not file.endswith('.json') or 'rerun' in file:
continue
# 跳过target和rerun目录中的文件
if file not in file_paths:
continue
# 解析文件名
result = parse_region_area_number(file)
if len(result) == 5: # 特殊格式
region_name, region_num, area, route_num, route_sub_num = result
else: # 标准格式
region_name, region_num, area, route_num = result
route_sub_num = None
if not region_name or not region_num or not area or not route_num:
continue
# 构建对应的target文件名
target_file = file
# 检查target文件是否存在
target_path = os.path.join(target_dir, target_file)
if not os.path.exists(target_path):
print(f" 警告:找不到对应的目标文件 {target_file}")
continue
try:
# 读取路径文件获取源传送点
file_path = os.path.join(pathing_dir, file)
with open(file_path, 'r', encoding='utf-8') as f:
path_data = json.load(f)
# 读取目标文件获取目标点
with open(target_path, 'r', encoding='utf-8') as f:
target_data = json.load(f)
# 获取传送点坐标
if "positions" in path_data and path_data["positions"]:
first_pos = path_data["positions"][0]
source_x = format_coord(first_pos["x"])
source_y = format_coord(first_pos["y"])
# 获取目标点坐标
if "positions" in target_data and target_data["positions"]:
target_pos = target_data["positions"][0]
target_x = format_coord(target_pos["x"])
target_y = format_coord(target_pos["y"]) # 查找源节点ID
source_id = None
for coord, node_id in teleport_nodes.items():
if calculate_distance(coord[0], coord[1], source_x, source_y) < 10: # 将阈值从50降低到10
source_id = node_id
break
# 查找目标节点ID
target_id = None
for coord, node_id in target_nodes.items():
if calculate_distance(coord[0], coord[1], target_x, target_y) < 10: # 将阈值从50降低到10
target_id = node_id
break
# 如果找到了源节点和目标节点,创建边
if source_id and target_id: # 添加边
edge = {
"source": source_id,
"target": target_id,
"route": file_paths[file],
# 保存原始位置信息用于在排序后更新ID稍后会删除
"sourcePosition": {
"x": source_x,
"y": source_y
},
"targetPosition": {
"x": target_x,
"y": target_y
}
}
new_data["edges"].append(edge)
# 更新索引
if str(source_id) not in new_data["indexes"]["edgesBySource"]:
new_data["indexes"]["edgesBySource"][str(source_id)] = []
new_data["indexes"]["edgesBySource"][str(source_id)].append(target_id)
if str(target_id) not in new_data["indexes"]["edgesByTarget"]:
new_data["indexes"]["edgesByTarget"][str(target_id)] = []
new_data["indexes"]["edgesByTarget"][str(target_id)].append(source_id)
print(f" 创建边: {source_id} -> {target_id}, 路径={file_paths[file]}")
except Exception as e:
print(f" 警告:处理边关系时出错 {file}: {e}") # 检查每个目标点是否至少有一条有向边
print("\n检查目标点的连通性...")
orphaned_targets = []
for blossom in new_data["blossoms"]:
target_id = blossom["id"]
# 检查是否有边指向此目标点
has_edge = False
for edge in new_data["edges"]:
if edge["target"] == target_id:
has_edge = True
break
if not has_edge:
orphaned_targets.append(blossom)
print(f" 警告: 目标点 ID={target_id}, 区域={blossom['region']}, 坐标=({blossom['position']['x']}, {blossom['position']['y']}) 没有入边")
# 处理没有边的目标点 - 尝试使用连续编号的路径
if orphaned_targets:
print(f"\n尝试为 {len(orphaned_targets)} 个孤立目标点寻找连续路径...")
# 先按区域分组目标点
region_targets = {}
for orphan in orphaned_targets:
region = orphan["region"]
if region not in region_targets:
region_targets[region] = []
region_targets[region].append(orphan)
# 然后按区域处理
for region, targets in region_targets.items():
print(f"\n处理区域 {region}{len(targets)} 个孤立目标点...")
# 获取该区域的所有边
region_edges = []
for edge in new_data["edges"]:
# 找到起点对应的传送点
source_teleport = None
for teleport in new_data["teleports"]:
if teleport["id"] == edge["source"]:
source_teleport = teleport
break
if source_teleport and source_teleport["region"] == region:
region_edges.append(edge)
if not region_edges:
print(f" 区域 {region} 没有现有路径,无法连接孤立目标点")
continue
# 从每条边的路径中提取区域和编号
route_info = []
for edge in region_edges:
route = edge["route"]
file_name = os.path.basename(route)
result = parse_region_area_number(file_name)
if len(result) == 5: # 特殊格式
region_name, region_num, area, route_num, route_sub_num = result
else: # 标准格式
region_name, region_num, area, route_num = result
route_sub_num = None
if region_name and region_num and area and route_num:
info = {
"edge": edge,
"region_name": region_name,
"region_num": region_num,
"area": area,
"route_num": route_num,
"file_name": file_name
}
if route_sub_num is not None:
info["route_sub_num"] = route_sub_num
route_info.append(info)
# 按区域和地区分组
area_routes = {}
for info in route_info:
key = f"{info['region_name']}{info['region_num']}-{info['area']}"
if key not in area_routes:
area_routes[key] = []
area_routes[key].append(info)
# 对每个地区内的路线按编号排序
for key, routes in area_routes.items():
routes.sort(key=lambda x: x["route_num"])
# 查找区域内每个孤立目标点附近的路径
for orphan in targets:
print(f" 处理目标点 ID={orphan['id']}, 坐标=({orphan['position']['x']}, {orphan['position']['y']})")
# 找到最近的传送点
nearest_teleport = None
min_distance = float('inf')
for teleport in new_data["teleports"]:
if teleport["region"] == orphan["region"]:
distance = calculate_distance(
teleport["position"]["x"], teleport["position"]["y"],
orphan["position"]["x"], orphan["position"]["y"]
)
if distance < min_distance:
min_distance = distance
nearest_teleport = teleport
if not nearest_teleport:
print(f" 未找到区域 {orphan['region']} 内的传送点")
continue
# 查找以这个传送点为起点的所有路径
teleport_routes = []
for key, routes in area_routes.items():
for info in routes:
if info["edge"]["source"] == nearest_teleport["id"]:
teleport_routes.append(info)
if not teleport_routes:
print(f" 未找到以传送点 ID={nearest_teleport['id']} 为起点的路径")
continue
# 按路线编号排序
teleport_routes.sort(key=lambda x: x["route_num"])
# 找到编号最大的路径
last_route = teleport_routes[-1]
next_num = last_route["route_num"] + 1
print(f" 找到传送点 ID={nearest_teleport['id']} 的最后一条路径: {last_route['file_name']}")
# 检查是否是特殊格式路径
if "-" in last_route['area']:
# 特殊格式路径(如"清泉镇-4"
area_parts = last_route['area'].split("-")
if len(area_parts) == 2:
print(f" 建议手动创建新路径: {last_route['region_name']}{last_route['region_num']}-{area_parts[0]}-{area_parts[1]}-{next_num}.json")
else:
print(f" 建议手动创建新路径: {last_route['region_name']}{last_route['region_num']}-{last_route['area']}-{next_num}.json")
else:
# 标准格式路径
print(f" 建议手动创建新路径: {last_route['region_name']}{last_route['region_num']}-{last_route['area']}-{next_num}.json")
print(f" 从传送点 ({nearest_teleport['position']['x']}, {nearest_teleport['position']['y']}) 到目标点 ({orphan['position']['x']}, {orphan['position']['y']})")
# 按区域排序传送点和地脉花
print("\n按区域对节点进行排序...")
# 对传送点按区域排序
new_data["teleports"] = sorted(new_data["teleports"], key=lambda x: get_region_sort_key(x["region"]))
# 对地脉花按区域排序
new_data["blossoms"] = sorted(new_data["blossoms"], key=lambda x: get_region_sort_key(x["region"]))
# 更新排序后的ID可选
for i, teleport in enumerate(new_data["teleports"]):
teleport["id"] = i + 1
for i, blossom in enumerate(new_data["blossoms"]):
blossom["id"] = i + 1000
# 更新边的引用
for edge in new_data["edges"]:
# 查找新的source ID
for teleport in new_data["teleports"]:
if calculate_distance(teleport["position"]["x"], teleport["position"]["y"],
edge["sourcePosition"]["x"], edge["sourcePosition"]["y"]) < 10:
edge["source"] = teleport["id"]
break
# 查找新的target ID
for blossom in new_data["blossoms"]:
if calculate_distance(blossom["position"]["x"], blossom["position"]["y"],
edge["targetPosition"]["x"], edge["targetPosition"]["y"]) < 10:
edge["target"] = blossom["id"]
break
# 在更新ID后删除位置信息
print("\n删除边数据中的位置信息...")
for edge in new_data["edges"]:
if "sourcePosition" in edge:
del edge["sourcePosition"]
if "targetPosition" in edge:
del edge["targetPosition"]
# 按照target的顺序排列edges
print("\n按照目标节点(target)的顺序排列边...")
new_data["edges"] = sorted(new_data["edges"], key=lambda x: x["target"])
# 创建节点到节点的顺序边
sequential_edges_count = create_sequential_edges(new_data)
# 重新排序所有边(包括新的顺序边)
print("\n重新排序所有边...")
new_data["edges"] = sorted(new_data["edges"], key=lambda x: (x.get("type", "teleport"), x["target"]))
# 重建索引
new_data["indexes"] = {
"edgesBySource": {},
"edgesByTarget": {}
}
for edge in new_data["edges"]:
source_id = edge["source"]
target_id = edge["target"]
if str(source_id) not in new_data["indexes"]["edgesBySource"]:
new_data["indexes"]["edgesBySource"][str(source_id)] = []
new_data["indexes"]["edgesBySource"][str(source_id)].append(target_id)
if str(target_id) not in new_data["indexes"]["edgesByTarget"]:
new_data["indexes"]["edgesByTarget"][str(target_id)] = []
new_data["indexes"]["edgesByTarget"][str(target_id)].append(source_id)
# 保存新数据结构
output_file = os.path.join(script_dir, "LeyLineOutcropData.json")
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(new_data, f, ensure_ascii=False, indent=2)
print(f"\n已生成新的数据结构: {output_file}")
print(f"传送点数量: {len(new_data['teleports'])}")
print(f"地脉花数量: {len(new_data['blossoms'])}")
print(f"总节点数量: {len(new_data['teleports']) + len(new_data['blossoms'])}")
print(f"传送点到地脉花边数量: {len([e for e in new_data['edges'] if e.get('type', 'teleport') == 'teleport'])}")
print(f"节点间顺序边数量: {sequential_edges_count}")
print(f"总边数量: {len(new_data['edges'])}")
print(f"区域排序顺序: {', '.join([k for k, v in sorted(REGION_ORDER.items(), key=lambda item: item[1]) if v < 99])}")
# 报告孤立目标点
remaining_orphans = 0
orphaned_blossoms = []
for blossom in new_data["blossoms"]:
target_id = blossom["id"]
has_edge = False
for edge in new_data["edges"]:
if edge["target"] == target_id:
has_edge = True
break
if not has_edge:
remaining_orphans += 1
orphaned_blossoms.append(blossom)
if remaining_orphans > 0:
print(f"\n注意: 仍有 {remaining_orphans} 个目标点没有入边")
print("这些目标点按区域排序如下:")
# 按区域分组展示孤立目标点
orphaned_by_region = {}
for orphan in orphaned_blossoms:
region = orphan["region"]
base_region = re.match(r"^([^0-9]+)", region)
if base_region:
base_region = base_region.group(1)
if base_region not in orphaned_by_region:
orphaned_by_region[base_region] = []
orphaned_by_region[base_region].append(orphan)
# 按照指定顺序显示区域
for region_name, _ in sorted(REGION_ORDER.items(), key=lambda item: item[1]):
if region_name in orphaned_by_region:
print(f"\n {region_name}区域的孤立目标点:")
for orphan in orphaned_by_region[region_name]:
print(f" ID={orphan['id']}, 区域={orphan['region']}, 坐标=({orphan['position']['x']}, {orphan['position']['y']})")
print("\n请按照之前的建议手动创建连续编号的路径文件")
else:
print("\n✓ 所有目标点都至少有一条入边")
return new_data
def create_sequential_edges(new_data):
"""创建节点到节点的顺序边,实现正确的分支逻辑
正确的分支规则:
1. 主路线到分支: 蒙德2-3 → 蒙德2-4-1, 蒙德2-4-2
2. 分支到同序号分支: 蒙德2-4-1 → 蒙德2-5-1 (优先) → 蒙德2-5 (备选) → 终点
3. 分支到同序号分支: 蒙德2-4-2 → 蒙德2-5-2 (优先) → 蒙德2-5 (备选) → 终点
4. 分支内部不连接: 蒙德2-4-1 和 蒙德2-4-2 之间不相互连接
5. 主路线到主路线: 当没有分支时的直接连接
基于实际路径文件查找对应的路线
"""
print("\n创建节点到节点的顺序边...")
script_dir = os.path.dirname(os.path.abspath(__file__))
pathing_dir = os.path.join(script_dir, "assets", "pathing")
# 按基本区域分组地脉花节点(区域名+区域编号,如"蒙德2"
region_groups = {}
for blossom in new_data["blossoms"]:
region = blossom["region"]
parts = region.split("-")
if len(parts) >= 2:
# 提取基本区域名:区域名+区域编号(如"蒙德2"
import re
match = re.match(r'^([^0-9]+)(\d+)', parts[0])
if match:
region_name = match.group(1) # 如 "蒙德"
region_num = match.group(2) # 如 "2"
base_region = region_name + region_num # 如 "蒙德2"
if base_region not in region_groups:
region_groups[base_region] = []
region_groups[base_region].append(blossom)
# 创建地脉花节点的映射region -> blossom
region_to_blossom = {}
for blossom in new_data["blossoms"]:
region_to_blossom[blossom["region"]] = blossom
# 收集所有存在的路径文件
available_routes = {}
for root, _, files in os.walk(pathing_dir):
for file in sorted(files):
if not file.endswith('.json') or 'rerun' in file or 'rerun' in root:
continue
if "target" in root.split(os.path.sep):
continue
relative_path = os.path.relpath(os.path.join(root, file), script_dir)
relative_path = relative_path.replace("\\", "/")
available_routes[file] = relative_path
sequential_edges = []
# 为每个区域创建顺序边
for base_region, blossoms in region_groups.items():
print(f"\n处理区域: {base_region}")
# 将节点分为主路线和分支路线
main_routes = {} # {route_num: blossom}
branch_routes = {} # {route_num: {branch_num: blossom}}
for blossom in blossoms:
region = blossom["region"]
parts = region.split("-")
if len(parts) == 2: # 主路线格式:"蒙德2-3"
try:
route_num = int(parts[1])
main_routes[route_num] = blossom
print(f" 主路线: {region} (路线{route_num})")
except ValueError:
print(f" 警告:无法解析主路线编号: {region}")
elif len(parts) == 3: # 分支路线格式:"蒙德2-4-1"
try:
route_num = int(parts[1])
branch_num = int(parts[2])
if route_num not in branch_routes:
branch_routes[route_num] = {}
branch_routes[route_num][branch_num] = blossom
print(f" 分支路线: {region} (路线{route_num}, 分支{branch_num})")
except ValueError:
print(f" 警告:无法解析分支路线编号: {region}")
print(f" 找到 {len(main_routes)} 个主路线,{len(branch_routes)} 个分支组")
# 辅助函数:查找路径文件
def find_route_file(source_region, target_region):
# 从目标区域推断文件名
result = None
print(f" 查找路径文件: {source_region}{target_region}")
for blossom in new_data["blossoms"]:
if blossom["region"] == target_region:
# 尝试通过目标区域构造文件名
parts = target_region.split("-")
print(f" 目标区域部分: {parts}")
if len(parts) == 2: # 主路线
# 例如: 蒙德2-3 -> 蒙德2-xxx-3.json
pattern = f"-{parts[1]}.json"
print(f" 主路线模式: {pattern}")
for filename in available_routes.keys():
if pattern in filename and parts[0] in filename:
result = available_routes[filename]
print(f" 找到匹配文件: {filename} -> {result}")
break
elif len(parts) == 3: # 分支路线
# 例如: 蒙德2-4-1 -> 蒙德2-xxx-4-1.json
pattern = f"-{parts[1]}-{parts[2]}.json"
print(f" 分支路线模式: {pattern}")
for filename in available_routes.keys():
if pattern in filename and parts[0] in filename:
result = available_routes[filename]
print(f" 找到匹配文件: {filename} -> {result}")
break
if not result:
print(f" 警告:未找到匹配的路径文件")
print(f" 可用文件: {list(available_routes.keys())[:10]}...") # 只显示前10个
break
return result# 1. 创建主路线到分支路线的连接
for main_route_num, main_blossom in main_routes.items():
# 找到下一个路线号,看是否有分支
next_route_num = main_route_num + 1
if next_route_num in branch_routes:
# 连接到下一个路线号的所有分支
for branch_num, branch_blossom in branch_routes[next_route_num].items():
route_file = find_route_file(main_blossom["region"], branch_blossom["region"])
if route_file:
edge = {
"source": main_blossom["id"],
"target": branch_blossom["id"],
"route": route_file
}
sequential_edges.append(edge)
print(f" 主路线到分支: {main_blossom['region']}{branch_blossom['region']}")
# 2. 创建分支到下一个分支的连接(同序号优先)
for route_num, branches in branch_routes.items():
next_route_num = route_num + 1
for branch_num, branch_blossom in branches.items():
# 优先连接到同序号的下一个分支
target_found = False
# 第一优先级:同序号分支 (蒙德2-4-1 → 蒙德2-5-1)
if next_route_num in branch_routes and branch_num in branch_routes[next_route_num]:
target_blossom = branch_routes[next_route_num][branch_num]
route_file = find_route_file(branch_blossom["region"], target_blossom["region"])
if route_file:
edge = {
"source": branch_blossom["id"],
"target": target_blossom["id"],
"route": route_file
}
sequential_edges.append(edge)
print(f" 分支到同序号分支: {branch_blossom['region']}{target_blossom['region']}")
target_found = True
# 第二优先级:主路线 (蒙德2-4-1 → 蒙德2-5)
if not target_found and next_route_num in main_routes:
target_blossom = main_routes[next_route_num]
route_file = find_route_file(branch_blossom["region"], target_blossom["region"])
if route_file:
edge = {
"source": branch_blossom["id"],
"target": target_blossom["id"],
"route": route_file
}
sequential_edges.append(edge)
print(f" 分支到主路线: {branch_blossom['region']}{target_blossom['region']}")
target_found = True
# 如果没有找到目标,则为路线终点
if not target_found:
print(f" 分支终点: {branch_blossom['region']} (无下一个目标)")
# 3. 创建主路线到主路线的连接(当没有分支时)
sorted_main_routes = sorted(main_routes.keys())
for i in range(len(sorted_main_routes) - 1):
current_route = sorted_main_routes[i]
next_route = sorted_main_routes[i + 1]
# 只有在下一个路线没有分支时,才创建主路线到主路线的连接
if next_route not in branch_routes:
source_blossom = main_routes[current_route]
target_blossom = main_routes[next_route]
route_file = find_route_file(source_blossom["region"], target_blossom["region"])
if route_file:
edge = {
"source": source_blossom["id"],
"target": target_blossom["id"],
"route": route_file
}
sequential_edges.append(edge)
print(f" 主路线连接: {source_blossom['region']}{target_blossom['region']}")
# 将新的顺序边添加到数据中
new_data["edges"].extend(sequential_edges)
print(f"\n总共创建了 {len(sequential_edges)} 条顺序边")
return len(sequential_edges)
def test_filename_parsing():
"""测试文件名解析功能,确保能正确处理各种格式"""
test_files = [
"蒙德1-风啸山岭-1.json", # 标准格式
"璃月3-轻策庄-2.json", # 标准格式
"蒙德2-清泉镇-4-1.json", # 特殊格式(双连字符数字)
"须弥2-须弥城-3-2.json", # 特殊格式
"纳塔1-区域-5.5.json" # 小数点路线编号
]
print("测试文件名解析结果:")
for filename in test_files:
result = parse_region_area_number(filename)
if len(result) == 5: # 特殊格式
region_name, region_num, area, route_num, route_sub_num = result
print(f"文件: {filename} (特殊格式)")
print(f" 区域名称: {region_name}")
print(f" 区域编号: {region_num}")
print(f" 地区: {area}")
print(f" 路线编号: {route_num}")
print(f" 路线子编号: {route_sub_num}")
else: # 标准格式
region_name, region_num, area, route_num = result
print(f"文件: {filename} (标准格式)")
print(f" 区域名称: {region_name}")
print(f" 区域编号: {region_num}")
print(f" 地区: {area}")
print(f" 路线编号: {route_num}")
# 测试格式化逻辑
if region_name and region_num and route_num:
if len(result) == 5: # 特殊格式
route_sub_num = result[4]
# 特殊格式显示为: 蒙德2-5-1 (区域名-区域编号-路线编号-路线子编号)
formatted = f"{region_name}{region_num}-{int(route_num)}-{int(route_sub_num)}"
else: # 标准格式
# 标准格式显示为: 枫丹1-1 (区域名-区域编号-路线编号)
formatted = f"{region_name}{region_num}-{int(route_num)}"
print(f" 格式化区域: {formatted}")
else:
print(f" 解析失败")
print("")
if __name__ == "__main__":
# 测试文件名解析
if len(sys.argv) > 1 and sys.argv[1] == "--test":
test_filename_parsing()
else:
generate_new_data_structure_from_pathing()