摘要
在《英雄无敌:上古纪元》的战斗中,每个兵堆的数量会因攻击而减少。项目的思路是:在两次行动之间读每堆的数量(行动条卡片、数量牌、面板),状态估计(SE)把同一堆相邻两次读数之间的下降记为一段减员区间。另一方面,战斗日志(Logs)的伤害行写着受击前的数量和死亡数,例如“骑兵(27)受到了 472 伤害。死亡单位:5”。
外部审阅建议做一个第一版样本:减员与日志的条件关联,要同时包括“明确可关联”“多种原因”“缺时间证据”的例子。本实验按兵种和数量链把两者对齐,并加了一个时间检查,专门寻找“数量对得上、时间却不可能”的反例。
在一段训练录像(10 月 10 日 16:57)的几次 App 离线回放上:信息页读得最全的一次(e2e-13)中,减员区间 24 段由一行日志直接解释、1 段需要多行、2 段由“被摧毁”行解释、9 段没有日志;时间检查中死亡行 28 行一致、1 行读数不足,已匹配区间 27 个一致,没有找到时间矛盾。故意把开始时刻挪后 5 秒,就出现 6 行矛盾——说明检查是灵敏的。所有关联都是有条件的,不是认证,只在一局上成立。
要回答的问题
SE 记下的减员区间,能否用日志的死亡行一步步解释?解释的时间是否可能?日志里有、读数里没有的情况有哪些?
数据与来源
- 一段用户选定的训练录像(10 月 10 日 16:57)的多次 App 离线视频回放(e2e-06、e2e-07、e2e-11、e2e-13 是项目内部给每次端到端回放的编号)。回放结果是临时数据。
- 日志名称用 SE 自己的显示名精确对到兵种 ID。
方法
区间匹配。 在保存的 SE 请求上重跑 SE(放开每堆只保留最近 24 次读数的上限)。对每个减员区间(同一堆 before→after),找该兵种的日志死亡行,看能否从 before 一步步走到 after:
- DIRECT:恰好一行日志走完,这段减员就是那一下的死亡数。
- MULTI_HIT:要连着几行才走完(一段区间里挨了几下:连锁或范围法术、反击、两次行动),净减员解释得通,但不能归给某一次攻击。
- DESTROYED_LINE:降到 0,而这个 0 只来自日志的“被摧毁”行。
- NO_LOG:找不到能走完的链。
关联只按兵种和数量序列,不按时间。
时间检查。 截图和行动条读数都有录像时间;日志时钟是本地时间,录像开始时刻取自录像文件名,所以一行日志的录像时间 = 时钟 − 开始时刻。时钟只到秒,开始时刻与第一帧也可能差约 1 秒,容差取 ±2 秒。
- 逐行检查(不依赖区间匹配):该行之前(至少 2 秒)这堆最后一次读数不应低于日志的受击前数量;之后(至少 2 秒)第一次读数不应高于受击后数量,除非中间有回升。
- 区间检查:已匹配区间用到的日志行,应落在两次读数的录像时间之间。
回升(第三轮新增)。 日志治疗行带复活数(“复活单位:1”),把该堆往上走:REVIVE_DIRECT / REVIVE_MULTI / NO_LOG。从 0 开始的回升,若有“X(70) 被召唤了”且数量相等,记为 SUMMONED。
攻击预览对照。 实时读到的攻击预览给出目标的击杀范围和伤害范围;如果玩家随后攻击了这个目标,20 秒内该目标的日志伤害行应落在范围内。匹配要求兵种对上、时间换算一致、攻击方也对上(预览的攻击方线索——行动条第一张卡——必须是那一秒日志中某次攻击的攻击者;范围攻击只写第一个目标,所以按秒匹配)。
设置
部分回放在用户玩游戏时以 1 核低优先级运行。
结果
减员区间:
| 回放 | 区间数 | DIRECT | MULTI_HIT | DESTROYED_LINE | NO_LOG | 日志死亡行用上 |
|---|---|---|---|---|---|---|
| e2e-06 | 30 | 13 | 2 | — | 15 | 20/21 |
| e2e-07(行动条修复后) | 32 | 12 | 2 | — | 18 | 20/21 |
| e2e-13(信息页读得更全) | 36 | 24 | 1 | 2 | 9 | 28/29 |
例子:
- 明确可关联:敌方骑兵 27→22 对应日志“骑兵(27)…死亡单位:5”。同一秒里剑士、圣殿狮鹫、织光者、羽蛇也各对上一行——看起来是一次行动打了多个目标(未核实),但每个目标的减员仍能分别关联。
- 多种原因:敌方神化者 7→1 要 4 行日志(7−1、6−2、4−2、2−1);我方巫妖 55→8 要同一秒的 4 行(各 11–12 只)。
- 缺时间证据:敌方剑士 147→101、101→79、79→40,妖精巨龙 24→4 等:这些时间段没有读到日志(战斗中日志截图本来就稀少)。
- 日志有、读数没有:神化者(1) 死亡 1——整堆被消灭后卡片和数量牌都消失,不会读到 0,所以没有区间。之后改为把日志“被摧毁”行当作降到 0,重跑 e2e-07 后这一行变为 DIRECT。
时间检查:
| 回放 | 死亡行逐行 | 已匹配区间 |
|---|---|---|
| e2e-07 | 21 一致 | 15 一致 |
| e2e-13 | 28 一致、1 读数不足 | 27 一致(含回升) |
有的区间很窄:我方修道院长 13→10 的两次读数在 914.8–916.4 秒,日志行换算为 915 秒;巫妖 8→7 在 457.0–461.2 秒,日志行为 460 秒。这也说明“日志时钟 = 录像开始 + 录像时间”的换算误差在 1–2 秒内。
灵敏度对照(故意把开始时刻挪后):
| 挪后 | 矛盾的日志行 | 矛盾的区间 |
|---|---|---|
| 5 秒 | 6 | 3 |
| 30 秒 | 11 | 8 |
另外核对了“下一回合的卡片数量是否最新”:e2e-07 的 66 次行动条读数中,同一堆在当前回合和下一回合各出现一次的共 108 对,数量全部一致。
回升(e2e-13,8 段): REVIVE_DIRECT 1(我方巫妖 7→8 对应“复活单位:1”);SUMMONED 1(星之子 0→70 对应“星之子(70)被召唤了”);NO_LOG 6(骷髅 325→331、331→336,巫妖 3→4,死亡商人 49→50,不死宠物 128→130,星之子 0→74)——多半是亡灵复活类效果或第三次召唤,这些时刻没读到日志;也可能是读错,没有核对原图。
攻击预览对照:
| 回放 | 预览 | 结论 |
|---|---|---|
| e2e-11 | 3 个(深渊使者打羽蛇、骑兵等) | 那一秒的伤害来自星之子的范围攻击,攻击者不同,正确地不比较 |
| e2e-11 | 星之子打羽蛇 18,伤害 431–647 | 日志实际 516 伤害、死 5:在范围内 |
| e2e-13 | 不死宠物打羽蛇(13),伤害 334–557、击杀 3–6(两次预览) | 日志 547 伤害、死 6:都在范围内 |
| e2e-13 | 圣骑兵打羽蛇(2),伤害 125–168、击杀 2–2 | 日志 115 伤害、死 2:低于下限,但整堆被消灭,日志只记剩余生命,标为“封顶”,与预览一致 |
e2e-13 有 21 个带目标兵种的预览,3 个能和随后的日志对上;另 4 个那一秒的伤害来自别的攻击者,不比较;其余时段没有日志。
失败与负结果
- 预览读错被接受。 e2e-11 一个预览的击杀行原文读成“4-67”,被当成 4–67 的范围接受;多半是“4-6”多了一个字符。已修:击杀上限超过目标数量(18)的预览不再读取。在 83 个已保存预览上检查,只去掉 2 个,都是坏读数(“956 / 818”和“5-75”,目标都是 18)。
- 没有找到任何“数量对上、时间不可能”的真实反例(这本身是一个结果,但样本只有一局)。
- 回升的 6 段 NO_LOG 没有核对原图,原因不明。
局限
- 只有一局、一段录像。DIRECT 是按数量链精确吻合定义的,本身不会出现“数量对不上”的反例。
- 时间对齐依赖录像文件名的开始时刻,只适用于离线录像;实时模式需改用采集时的本地时钟。
- 没读到日志的整堆消灭仍然只是读数停止。
- 生产 SE 当时还没消费这些关联。
结论与下一步
在这一局上,减员区间大多可以被日志死亡行有条件地解释,时间检查没有发现矛盾且对错位很灵敏;主要缺口是很多时段根本没读到日志。日志读得越全(信息页旁路读取更多),NO_LOG 越少。下一步是在更多局上找真实的矛盾样本、用实时本地时钟替代文件名时刻,并让生产 SE 消费这些条件关联。圣骑兵打羽蛇那一例还给出“两只羽蛇剩余生命合计 115”,可以作为血条实验的参考样本(需查羽蛇单只生命上限)。
Comments