附录 A 叙事规格字段表、条件文法与数据集索引
《叙事策划与叙事工艺》卷一《叙事结构与可执行规格》附录 A:把全卷 16 章 48 节散落的叙事规格九段字段、嵌套数组条件文法与十一条整数不变量汇成索引表,给出卷内文件命名约定、S/P/W 三层完整复现命令与排错顺序,并附一段 Python 与 TypeScript 逐位一致的跨语言状态摘要,作为「文本是规格的渲染」的可验证落点。
category
《叙事策划与叙事工艺》卷一《叙事结构与可执行规格》附录 A:把全卷 16 章 48 节散落的叙事规格九段字段、嵌套数组条件文法与十一条整数不变量汇成索引表,给出卷内文件命名约定、S/P/W 三层完整复现命令与排错顺序,并附一段 Python 与 TypeScript 逐位一致的跨语言状态摘要,作为「文本是规格的渲染」的可验证落点。
闭包检验问三件事:条件引用的名字是否都声明过、是否都在某条可达路径上被写过、每个条件位点是否都在至少一个可达状态上取真。S 层脚本重跑一次完整枚举给出报告:52 个条件位点全部取真过,死条件 0 个;另附敏感性自检,证明检验器对注入的静态与动态缺陷都会报警。
三类状态(flag 布尔 18 个、好感度整数 4 个、物品 9 个)与四个效果算子的写入域一一对应:set 只写 flag、add 只写好感度、grant 与 revoke 只写物品。S 层脚本逐条校验越域并统计每个变量的被写次数,实测 138 条写入全部落在域内,revoke 一次未被使用。
条件是嵌套数组写成的表达式树:三种叶子(旗标 / 好感度比较 / 物品持有)与三种组合(and / or / not)构成完整文法。本节给出文法表,并用 node --test 逐条验证六种形式的正例与负例。实测全规格 58 个条件节点,实际用到 5 种形式——or 声明了却一次没用。
一个选项是假选择,当且仅当它不改变任何状态,且与其他选项在终局可达集上不可区分。判据写死在脚本里,不按结果调参。本节用 S 层脚本对《雾港夜航》的 115 个选项逐个判定:空效果选项 16 个,其中 12 个仍判真后果,真正判为假选择的只有 4 个。
宽度是一个节点同时可选的选项数,深度是从起点到终局走过的边数。本节用 S 层脚本量出《雾港夜航》的平均宽度 2.67、最大宽度 5,并用两条口径量深度:全部 450208471680 条结构路径的长度只取 22/25/28/31 四个值,而采样 20000 次的均值是 25.41 步。
分支拓扑把对话图读成三种原语:分叉是一出多、汇聚是多入一、并行是两条互不可达的去向。本节用 S 层脚本对 48 个节点统计出度与入度,找出全部 9 个分叉点与 8 个汇聚点,再用支配点算法分离出 4 个「所有路径必经」的强制汇流点,最后落出一张 48 行的拓扑表。
带条件的边是顺序约束:lighthouse_base 到 tide_cave 要先有 knows_tide_rule。本节把 5 条约束折成一张表,做两项判定——环检测(DFS 三色法加 Kahn 拓扑序,实测无环)与「不可达的解锁条件」(钥匙会不会锁在门后,实测 0 条),并输出约束表 CSV。
把带条件的边当作「可能通」后,场景图上的 BFS 给出结构可达性:14 个场景全部可达,但 5 个场景(counting_house、watch_post、tide_cave、harbor_office、drowned_bell)的入口边全部带条件,可达性完全取决于状态。本节给出入度、出度、最少跳数与最早出现幕四列。
场景图把 14 个场景写成一张图:节点带 enter_when,16 条边里 11 条无条件、5 条带条件。本节做结构校验(每条边两端都在 nodes 里)与邻接表,并用纯 xml.etree 出一张按幕分列的场景图 SVG;其中 5 个场景只有带条件的入口边,可达性完全取决于状态。
比例检验把「三段差不多长」「后面更紧张」这类印象换成整数:各幕拍数 5/6/5 折成千分比 312/375/312,张力均值 2000/3666/4000‰,峰值位置落在第 4、10、13/14 拍。本节给出可跑的 S 层脚本与纯 xml.etree 的各幕张力分布 SVG,并断言第三幕峰值不低于前两幕。
节拍表把结构写成一行一拍的 beat 序列,于是「顺序」变成可校验的约束:act 必须单调不减、scene 必须存在于 scene_graph、节点所属幕必须与节拍所属幕一致、每个场景节点至少被一拍覆盖。本节用可跑的 S 层脚本逐条校验并打印《雾港夜航》的 16 行节拍表。
三幕、五幕与起承转合不是三种故事,而是对同一份 beats[].act 的三套分段规则:三幕按 act 直接分组得 3 段,五幕把首尾两幕各对半切得 5 段,起承转合把第二幕对半切得 4 段。本节用可跑的 S 层脚本把《雾港夜航》16 个节拍映射到三种模型,逐条对比分段边界。
乐观上界只说明「够得到」,不等于「走得到」。本节真的跑两万条采样路径,逐条记录六个角色的好感度峰值,看它是否越过 stages 对应的三个门限。结果是 15/18 可达、3 条不可达(全部落在林与孩身上);更耐读的是「可达」内部的落差——砚的 trust 只有 4‰ 的路径走到,沈的有 112‰。
弧光的每一段要对到一个好感度门限上。本节把《雾港夜航》六个角色按 cold/warm/trust 三门限做对齐,用「乐观最早跨越节拍」当上界:连把正向选项全选一遍都没能在声明转折节拍前越过门限的,就一定是错位。18 条里查出 4 条错位——砚的阶段①落后 4 拍,林与孩的 trust 门在乐观路径上都够不到。
弧光在规格里就是两个数组:三个 stages 阶段名,加三个 beats 转折节拍号。本节把《雾港夜航》六个角色的弧光写成阶段表,并用 S 层脚本校验三阶段、三节拍号、严格递增、落在 1..16 的范围内;顺带暴露 b12 与 b16 被两个角色同时声明为转折点的结构拥挤。
关系有两副面孔:一副是矩阵里静态的不对称,一副是沿路径动态的变化。本节用自实现 MINSTD 采样 20000 条路径,输出 4 个好感度变量的「初始值 → 终局值」分布表,断言整数不变量残差为 0,并统计出 15 对关系里 13 对不对称、2 对差距达到 20。
故事里谁对谁是什么态度,规格里只有派系立场这一层。本节把 6 个角色之间的关系写成 6×6 整数矩阵,校验形状、值域与对角线,再用派系立场推出先验做一致性交叉检查:30 个非对角格里 2 个偏离先验,15 对里有 13 对不对称,而派系立场本身却完全对称。
目标、恐惧、秘密在叙事规格里都是自由文本,机器读不懂。本节给出一层可校验的锚点表,把每个字段锚到具体的场景、flag 与条件,再用 S 层脚本回规格做交叉引用检查:30 个字段锚点里 21 个可检查,并定位出 18 个 flag 里 7 个从不参与任何条件。
设定不是一次倒完的:lore[].reveal_flag 把「揭示时机」写成状态,某条设定何时被玩家知道,取决于它的 flag 在哪一步被置 1。本节沿 20000 条采样路径统计 6 条 lore 的首次揭示位置分布,并用纯 xml.etree 出一张暴露节奏 SVG——网格给每条 lore 落在哪一夜,折线给平均已揭示条数。