摘要

SE(状态估计)会维护一条“减员时间线”:每个兵堆(一方的一种生物)在每次读到数量时记录一次,相邻读数之差就是减员。问题是:在一段训练录像(10 月 10 日 01:39)里,有一批兵堆在战斗中途被整堆消灭,从行动条(屏幕顶部按出手顺序排列的生物卡片)上消失了,又恰好没读到 Logs 战斗日志里的“被摧毁”行。于是时间线一直停在最后一个读数,直到结算画面才补 0——观世者、太阳圣盾晚了约 20 分钟。

本实验加了一条规则:当一个兵堆在若干次“完整读取”的行动条上都不再出现,就补一个条件性的 0 读数,并标明“已离开行动条,条件推断”。关键约束是绝不能把活着的兵堆判死。结果:01:39 局 10 堆得到这种终局读数,全部是真的消灭;结算对照从 2 行一致变为 12 行一致;在大量人为制造的“认错”扰动下,活堆被判死 0 次。

要回答的问题

兵堆离开行动条时,能否给出一个不会误杀活堆的条件性终局读数?什么样的行动条读取才足以说明“某堆不在了”?

数据与来源

  • 两段用户选定的训练/开发录像(10 月 10 日 16:57、01:39)已有的行动条标注和保存的 App 请求;没有打开冻结或留出录像,保存请求只读。
  • 行动条标注由模型目视给出(模型目视核对),不是用户审核。下面只报计数。

方法

先看行动条的事实。 行动条每张卡宽 108 像素、间距 110.7,两个回合之间有一个分隔。读取器只读当前回合(组 0)和下一回合(组 1)。统计标注发现:

16:57(79 个有行动条的时刻) 01:39(117 个时刻)
组 0–1 共 12 张且有分隔(行动条被占满) 45 次,全部看不到组 2 45 次,全部看不到组 2
组 0–1 ≤11 张且有分隔(下一回合在条内结束) 0 次 69 次,全部能看到组 2
活着的堆不在组 0–1 里(堆·时刻) 186/1046,全部在占满的时刻 25/781,全部在 12 张的时刻
“≤11 张”时刻里活堆不在下一回合 — 0

结论:12 张 + 一个分隔就会占满行动条,下一回合可能延伸到屏幕外;但如果组 0–1 不到 12 张且读到分隔,下一回合整组都在条内,所有活着的堆都会出现在下一回合里。等待只在当前回合内重排,召唤物出现在下一回合,都不影响这一点。16:57 那局一直有 12 堆以上,从来没有这样的读取。

“完整读取”的条件:

  1. 读到当前回合和下一回合(恰好有分隔);
  2. 下一回合在条内结束:最后一张卡后面再放一张卡仍不超过 2031 像素(等价于组 0–1 ≤11 张),或者读到了组 2;
  3. 每张卡都有兵种和能对应到一方的颜色;同一回合里没有重复的(颜色, 兵种);
  4. 当前回合剩下的堆都在下一回合里(被窗口挡住或扫描截短时这条会不成立)。

判为离开: 某堆在最后一次出现之后,有 K=3 次完整读取都没有它,之后任何截图都不再出现它;它在行动条上至少出现过 SEEN=3 张截图;最后一次读数大于 0;之后没有“被摧毁”日志。满足时在第 3 次完整读取处加一个 0,减员区间是“上一次读到它 → 这次读取”。SE 每次都从整段历史重算,所以以后再读到它,这个 0 自然撤回。

结算画面: 先按不含这些 0 的读数对应结算卡片;如果对应上的卡片显示这堆活到了最后,就不加它的 0。留下的 0 让结算行从“缺终点”变为“一致”,并标明这一致依赖推断。

K 和 SEEN 怎么定。 真实数据里 K=1、2、3 判出的堆完全相同;K=4 时麒麟丢掉(它死后到结算只有 3 次完整读取)。SEEN=0 会多判 2 个从没上过行动条的“幻影堆”(数量牌身体候选认错兵种造成)。真实数据分不出 K,于是对 01:39 读取器的 117 个输出逐个人为制造错误、每个前缀重放一遍(相当于实时 SE 在那一帧的结论):

设置 单卡认错兵种(512 种) 同一堆连续两次认错(499) 扫描在下一回合中途断掉(237)
K=1, SEEN=3 100 种出误判 139 42
K=2, SEEN=1 435(幻影) 445 0
K=2, SEEN=2 0 445 0
K=2, SEEN=3 0 71 0
K=3, SEEN=3(采用) 0 0 0
K=3, SEEN=4 0 0 0

读取器在 2071 张标注卡上兵种 0 错,所以采用能扛住同一堆连续两次认错的最小设置 K=3、SEEN=3。

设置

在保存请求上跑完整 SE,与改动前源码的输出逐字节比较。为避免工作目录不同导致头像参考路径不同、改变我方阵营判断,比较时把该路径固定为主仓库路径(不固定时结论相同)。

结果

01:39 局(554 帧,72 次完整读取): 10 堆得到离开行动条的终局读数,全部是真的消灭(结算参考都是 0,0 都放在标注最后一次看到它之后)。

兵堆 最后读数(画面秒) 0 放在(画面秒) 标注:最后看到 / 第一次不见
敌方观世者 551.8 1010.1 476.0 / 559.0
敌方太阳圣盾 551.8 1010.1 476.0 / 559.0
敌方圣殿狮鹫 785.5 1010.1 773.5 / 804.0
敌方驯鹰师 990.4 1123.3 1005.5 / 1010.5
敌方神化者 1101.0 1129.0 1115.0 / 1124.0
我方水泽精灵 1094.3 1129.0 1096.5 / 1103.5
我方羊人 1204.2 1210.9 1201.0 / 1214.5
敌方织光者 1206.8 1350.8 1329.5 / 1338.0
我方判官 1639.3 1696.3 1653.0 / 1659.0
我方麒麟 1777.4 1795.9 1784.0 / 标注到此为止

结算对照:改动前一致 2、缺终点 11、无法对应 1;改动后一致 12、缺终点 1、无法对应 1。剩下的缺终点是被结束战斗的最后一击打死的修道院长。原问题中“中途离开行动条的 8 堆”全部补上。整份 SE 结果只有减员部分不同。织光者有一段时间数量“1”一直没读出,但卡片一直在,所以没有被提前判死。

16:57 局(261 帧): 0 次完整读取,没有离开行动条的终局;整份 SE 结果与改动前逐字节相同。结算仍是一致 7、缺终点 6(都是最后一击打死的)、无法对应 1。

逐前缀重放(实时 SE 每一帧会给出的结论): 01:39 的保存请求、标注转成的读取、读取器输出三种序列,最终判消灭 10/11/11,误判、0 放在死亡之前、撤回全部为 0;16:57 三种序列都是 0 次完整读取。

审阅后的修正: 原版把 0 放在第一次完整读取上;外部审阅指出,如果一次认错恰好落在死亡之前的完整读取上,0 就会放在它还活着的帧上。在保存请求上逐卡制造认错(537 种)和连续两次认错(525 种)重放:

版本 单次认错:0 放在死亡之前 / 活堆被判死 连续两次认错:同左
0 放在第一次(审阅前) 3 / 0 4 / 0
0 放在第 3 次(现在) 0 / 0 0 / 0

审阅者报告的 3 例在旧版本上原样复现,改后为 0。同时修正了结算逻辑:原来误判的 0 会让结算行变成“不一致”、结算读数被丢掉,错的 0 永久留下。

测试与兼容: 新增 14 个 SE 测试(包括审阅后先写、在旧代码上失败的 3 个)和 2 个 App 测试。审阅后相关 140 个测试通过;整个 SE 测试集 3284 通过、52 跳过、1 预期失败、3 失败——这 3 个在改动前的源码上同样失败(工作目录缺数据文件),与本改动无关。App 中带这种推断的减员显示“已离开行动条,条件推断”;没有这种情况时输出与改动前逐字节相同。

失败与负结果

  • 第一版把 0 放在第一次完整读取,在扰动下会把 0 放到死亡之前(3–4 例),已改。
  • 早死的兵堆(场上还有 12 堆以上时)0 会放得很晚:观世者、太阳圣盾晚 451 秒,圣殿狮鹫晚 206 秒,只有区间起点是准的;其他堆比第一次不见晚 −4 到 +113 秒。
  • 死后到战斗结束不足 3 次完整读取的兵堆拿不到这个 0,只能交给结算画面。

局限

  • 只有一局有完整读取(10 堆);计数来自模型目视标注,不是准确率。
  • 兵种被连续 3 次以上认错,或有让活堆暂时离开行动条的效果(控制、隐身、暂时离场),会误判;扰动重放假设认错相互独立,而状态染色、升级形态这类认错可能连续出现。
  • 跳过回合的状态(如睡眠、石化、眩晕、致盲等 7 种)下行动条是否仍列出该堆,录像中没有核实;持续多回合的效果可能跨过 3 次完整读取。
  • 读取器扫描停在下一回合最后一张卡上时,与“下一回合在条内结束”看起来一样,只靠“当前回合 ⊆ 下一回合”挡;用“看到第二个分隔”做条件需要先改视觉模块输出,没改。
  • 召唤物到时消失也会离开行动条,会得到这个 0 并计入减员(这两局没出现)。
  • 行动条几何常量只适用于 2560×1440 原生布局。App 还不显示减员的前提说明和结算行。

结论与下一步

“完整读取的行动条连续 3 次看不到 + 至少上过 3 次行动条”这条规则,在可用数据和大量扰动下都没有误杀活堆,并把中途消灭的兵堆从“结算才补 0”提前到战斗中。下一步可考虑让视觉模块把回合分隔信息传给 SE,用“看到第二个分隔”加强完整性判断,并在录像中核实跳过回合状态下的行动条表现。