Files
GameOfMoon/Documentation/mindmap/analyze_end_nodes.py
Rocky 93400900c0 添加DSL引擎迁移和验证功能
- 新增最终验证脚本和迁移测试脚本,确保DSL引擎的完整性和功能
- 实现故事模块的音频配置、角色定义和情感故事模块
- 迁移现有故事数据到新的DSL格式,支持动态内容和条件导航
- 更新主题和UI组件,确保一致的黑色背景和暗色主题
- 添加音频管理器和性能监控工具,提升游戏体验和调试能力
2025-09-10 17:36:55 +08:00

115 lines
3.4 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 python3
# -*- coding: utf-8 -*-
import argparse
import os
import re
from typing import Dict, List, Tuple
NODE_RE = re.compile(r'^\s*@node\s+(?P<id>[A-Za-z0-9_]+)\s*$')
TITLE_RE = re.compile(r'^\s*@title\s+"(?P<title>.*)"\s*$')
CHOICE_RE = re.compile(r'^\s*choice_\d+\s*:\s*"(?P<label>.*?)"\s*->\s*(?P<target>[A-Za-z0-9_]+)')
ENDING_ID_PREFIXES = (
'ending_',
)
ENDING_TITLE_KEYWORDS = (
'结局', '最终', '终极', '拯救', '守护', '和谐', '文明', '宽恕', '宇宙', '完美'
)
def parse_story(path: str) -> Tuple[Dict[str, str], Dict[str, List[Tuple[str, str]]]]:
with open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()
nodes: Dict[str, str] = {}
edges: Dict[str, List[Tuple[str, str]]] = {}
current_id: str = ''
i = 0
n = len(lines)
while i < n:
line = lines[i].rstrip('\n')
m_node = NODE_RE.match(line)
if m_node:
current_id = m_node.group('id')
if current_id not in nodes:
nodes[current_id] = current_id
if current_id not in edges:
edges[current_id] = []
j = i + 1
while j < n:
l2 = lines[j].rstrip('\n')
if NODE_RE.match(l2):
break
m_title = TITLE_RE.match(l2)
if m_title:
title = m_title.group('title').strip()
if title:
nodes[current_id] = title
m_choice = CHOICE_RE.match(l2)
if m_choice:
label = m_choice.group('label').strip()
target = m_choice.group('target').strip()
edges.setdefault(current_id, []).append((label, target))
j += 1
i = j
continue
i += 1
return nodes, edges
def is_ending(node_id: str, title: str) -> bool:
if any(node_id.startswith(p) for p in ENDING_ID_PREFIXES):
return True
return any(k in (title or '') for k in ENDING_TITLE_KEYWORDS)
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--input', required=True)
ap.add_argument('--output', required=True)
args = ap.parse_args()
nodes, edges = parse_story(args.input)
# Compute out-degree
outdeg = {nid: len(edges.get(nid, [])) for nid in nodes.keys()}
leaf_nodes = [nid for nid, deg in outdeg.items() if deg == 0]
endings = []
non_endings = []
for nid in sorted(leaf_nodes):
title = nodes.get(nid, '')
(endings if is_ending(nid, title) else non_endings).append((nid, title))
os.makedirs(os.path.dirname(args.output), exist_ok=True)
with open(args.output, 'w', encoding='utf-8') as f:
f.write('# 无后续(无 choices节点清单\n\n')
f.write(f'- 总节点数: {len(nodes)}\n')
f.write(f'- 无后续节点数: {len(leaf_nodes)}\n')
f.write(f'- 结局型: {len(endings)}\n')
f.write(f'- 可能未接续: {len(non_endings)}\n\n')
f.write('## 结局型Leaf Endings\n')
for nid, title in endings:
f.write(f'- {title} | id: `{nid}`\n')
f.write('\n')
f.write('## 可能未接续(需人工确认是否应有后续)\n')
for nid, title in non_endings:
f.write(f'- {title} | id: `{nid}`\n')
print(f"Wrote report to {args.output}. Endings={len(endings)} NonEndings={len(non_endings)}")
if __name__ == '__main__':
main()