merge: 验收读数重测批(A+B 掷点测量修复)落籍——分支 acceptance-rerun-20260919 六笔(初稿/根因修正/B 案 R3 混淆派生/A 案 unique 种子模式/07⑨ 试玩指引/rebase 重构);判读报告 production/qa/acceptance-rerun-20260919.md(真人批缺位待补 k 系数);台账 92-95(原分支内 84-87 与并行会话撞号重编);快照节双会话共存已对账
This commit is contained in:
commit
4708940b7e
8 files changed
+257
-24
No files matched your search
+21
-2
@@ -61,9 +61,11 @@
|
|||||||
|
|
||||||
弃图率 / 每轮刷新率随试玩日志采集;预警阈值须有基线读数才能定(2026-09-18 拍板:现在定是拍脑袋)——随验收读数重测批出基线,数字与调参联动复核。挖掘期当场刷新无结算发生,两读数均不影响对账。
|
弃图率 / 每轮刷新率随试玩日志采集;预警阈值须有基线读数才能定(2026-09-18 拍板:现在定是拍脑袋)——随验收读数重测批出基线,数字与调参联动复核。挖掘期当场刷新无结算发生,两读数均不影响对账。
|
||||||
|
|
||||||
### ⑧ 旗行为基线监控(插旗不可逆批 2026-09-19 落地后的行为监控;原「提案评估前置采集」使命随提案转正终结)
|
**基线已采(2026-09-19 验收重测批,读数详见 [判读报告](../../production/qa/acceptance-rerun-20260919.md))**:MC 完美档弃图 ~0.1 次/局量级(L1 基线格 0.23 / L2 0.03)、normal 档零弃图(模拟画像不主动刷新);每轮刷新率 ≤0.6%。阈值数字仍归调参批。两读数已固化进 `log_analysis.py` 关卡级统计列(分析器随批升级)。
|
||||||
|
|
||||||
原口径(2026-09-19 上午拍板):本项为插旗不可逆提案的 Alpha 评估前置采集——同日用户在真人试玩中确认"不能挖旗格"违背设定,**提案全套提前落地**(禁拔旗 + 挖旗格兑付改判,战斗结算 v0.18 四情况表;登记原文见 2026-09-18 台账 72 与 git 历史 06 清单条目)。评估使命终结,本项转为一律机制的真人行为监控(与 ⑥⑦ 同形状,纯日志侧采集零新增埋点)。
|
|
||||||
|
### ⑧ 旗行为基线监控(插旗不可逆批 2026-09-19 落地后的行为监控;原「提案评估前置采集」使命随提案转正终结)
|
||||||
|
26-09-19 上午拍板):本项为插旗不可逆提案的 Alpha 评估前置采集——同日用户在真人试玩中确认"不能挖旗格"违背设定,**提案全套提前落地**(禁拔旗 + 挖旗格兑付改判,战斗结算 v0.18 四情况表;登记原文见 2026-09-18 台账 72 与 git 历史 06 清单条目)。评估使命终结,本项转为一律机制的真人行为监控(与 ⑥⑦ 同形状,纯日志侧采集零新增埋点)。
|
||||||
|
|
||||||
- **观测什么**(读数全部可由现役 JSONL 日志推导——动作行含 flag_place/被拒 dig、结算步流含 flag_hit/flag_miss 判定行〔带格坐标〕与 reward_ineffective 作废行;flag_pull 动作行与同轮插撤、拔旗次数两读数随拔旗退役作废删除):① 误旗率 = flag_miss 判定行 ÷ flag_place 动作行(判定时点口径细节随首批读数钉死);② 挖旗格直挖率 = 插旗格直接挖开数 ÷ flag_place 动作行(原「被拒后路径分布」三路径随挖旗格放行消失);③ 四情况触发分布(①标中留判 / ②雷格直挖 / ③标空留判 / ④安全格直挖零奖励——④占比是核心读数)。
|
- **观测什么**(读数全部可由现役 JSONL 日志推导——动作行含 flag_place/被拒 dig、结算步流含 flag_hit/flag_miss 判定行〔带格坐标〕与 reward_ineffective 作废行;flag_pull 动作行与同轮插撤、拔旗次数两读数随拔旗退役作废删除):① 误旗率 = flag_miss 判定行 ÷ flag_place 动作行(判定时点口径细节随首批读数钉死);② 挖旗格直挖率 = 插旗格直接挖开数 ÷ flag_place 动作行(原「被拒后路径分布」三路径随挖旗格放行消失);③ 四情况触发分布(①标中留判 / ②雷格直挖 / ③标空留判 / ④安全格直挖零奖励——④占比是核心读数)。
|
||||||
- **语义锚(2026-09-19 落地实测锁定,smoke_all `_smoke_flag_irreversible_quadrants` 断言在案)**:插旗安全格直挖 = 零惩罚零奖励(正向兑付作废、作废归因行恰一次、标空不判);插旗雷格直挖 = 只受挖雷一层惩罚(mine_hit 照常)、标中不发;不挖留判 = 标中/标空照常;flag_pull 出目录拒绝、重复插旗 flag_present 拒绝。
|
- **语义锚(2026-09-19 落地实测锁定,smoke_all `_smoke_flag_irreversible_quadrants` 断言在案)**:插旗安全格直挖 = 零惩罚零奖励(正向兑付作废、作废归因行恰一次、标空不判);插旗雷格直挖 = 只受挖雷一层惩罚(mine_hit 照常)、标中不发;不挖留判 = 标中/标空照常;flag_pull 出目录拒绝、重复插旗 flag_present 拒绝。
|
||||||
@@ -71,6 +73,23 @@
|
|||||||
- **红灯信号**:误旗后放弃纠错占比异常高(直挖免费但④零奖励仍可能劝退纠错——玩家改绕路不挖)或④触发后局部推进明显迟滞(零奖励力度过狠的体验证据)——红灯仅作曲线调参批输入,**不在试玩现场改机制**。
|
- **红灯信号**:误旗后放弃纠错占比异常高(直挖免费但④零奖励仍可能劝退纠错——玩家改绕路不挖)或④触发后局部推进明显迟滞(零奖励力度过狠的体验证据)——红灯仅作曲线调参批输入,**不在试玩现场改机制**。
|
||||||
- **结论回流**:读数 → 曲线调参批复核情况④零奖励力度与旗价目;提案已转正,无后续评估义务。
|
- **结论回流**:读数 → 曲线调参批复核情况④零奖励力度与旗价目;提案已转正,无后续评估义务。
|
||||||
|
|
||||||
|
### ⑨ 真人批试玩指引(验收重测批修正锚,2026-09-19 立项——照此单试玩即可)
|
||||||
|
|
||||||
|
**怎么玩**:开始界面前把天赋加成清零(基线档 = atk+0%/hp+0%,即"零永久天赋"原始状态),然后正常打 3–5 局。种子不用记——日志按局自动落盘,事后由分析工具取数。打第一关还是两关都行,通关与否都有效。
|
||||||
|
|
||||||
|
**局中留意什么**(对号入座 ①–⑧;不用刻意记数,体感即可):
|
||||||
|
1. **Boss 战节奏**(①,最高优先):打不打得动、拖了几轮、恢复点够不够用;
|
||||||
|
2. **削弱后的承伤**(②):吃削弱那几轮挨打是不是明显变疼;
|
||||||
|
3. **增伤手感**(③):增益期伤害是不是"明显变高但不爆炸";
|
||||||
|
4. **乏力可感知性**(④):踩雷后下一轮输出下降感不感觉得到;
|
||||||
|
5. **失衡归因**(⑤):标错旗之后挨打变疼,能不能猜到"为什么";
|
||||||
|
6. **刷新冲动**(⑦基线复核):有没有"想换一张图"的时刻?觉得刷新 1 行动点贵不贵?
|
||||||
|
7. **速杀自察**(⑥):打完战斗时图上是不是还剩大半没挖(跳过棋盘直接杀敌的冲动多不多)。
|
||||||
|
|
||||||
|
**局后随手记**(一句话即可,事后对日志):每局大概掉了多少血 / 有没有整轮一点血没掉的轮次 / 通关与否 / 有没有"这局特别顺/特别倒霉"的体感(种子体感核对用)。
|
||||||
|
|
||||||
|
**结果回流**:日志取数 → 真人修正系数 k(真人整关承伤中位 ÷ 模拟完美档中位,预警线 k<0.3)并入[判读报告](../../production/qa/acceptance-rerun-20260919.md)终稿;①–⑤ 体感按各条目的回流位分流。
|
||||||
|
|
||||||
## 验收读数重测批义务(给下一批的输入,非手工项)
|
## 验收读数重测批义务(给下一批的输入,非手工项)
|
||||||
|
|
||||||
- **Boss 战必须单独出列**(硬化行为变化——旧 Boss 承伤 84.8% 等读数全部作废)。
|
- **Boss 战必须单独出列**(硬化行为变化——旧 Boss 承伤 84.8% 等读数全部作废)。
|
||||||
|
|||||||
@@ -34,14 +34,15 @@ entities:
|
|||||||
attributes:
|
attributes:
|
||||||
variables: [SALT_s, master_seed, scope]
|
variables: [SALT_s, master_seed, scope]
|
||||||
output_range: "[0, 2^63)"
|
output_range: "[0, 2^63)"
|
||||||
golden_vectors: 见《数据配置》Formulas-R2 向量表(7 常量:board_gen m=42 scope0-3 · reward_roll m=42 scope0=7422916049646135537 · encounter m=42 scope0=1061841193803499209 · armor_roll m=42 scope0=4806095330042243845——2026-09-16 护甲等级掷点批 armor_roll 增流补向量 · behavior_roll m=42 scope0=426657203655691839——2026-09-16 敌人技能池批 behavior_roll 增流补向量)
|
golden_vectors: 见《数据配置》Formulas-R3 向量表(8 常量——2026-09-19 掷点测量修复批 B 案 R2→R3 改版全量重登记,Python 参考实现逐位交叉验证:board_gen m=42 scope0=8672514112661456564 / scope1=8834291164406037215 / scope2=7714373262647006282 / scope3=1280102845971471347 · reward_roll m=42 scope0=8363815839763232861 · encounter m=42 scope0=5906263231575069166 · armor_roll m=42 scope0=1459964581993244806 · behavior_roll m=42 scope0=1791557311233092846;R2 旧向量随批作废)
|
||||||
salt_board_gen: 0xA0761D6478BD642F
|
salt_board_gen: 0xA0761D6478BD642F
|
||||||
salt_reward_roll: 0xE7037ED1A0B428DB
|
salt_reward_roll: 0xE7037ED1A0B428DB
|
||||||
salt_encounter: 0x8EBC6AF09C88C6E3(2026-09-14 encounter 增流——互异奇常数 ≠ 乘数)
|
salt_encounter: 0x8EBC6AF09C88C6E3(2026-09-14 encounter 增流——互异奇常数 ≠ 乘数)
|
||||||
salt_armor_roll: 0xC2B2AE3D27D4EB2F(2026-09-16 armor_roll 增流——互异奇常数 ≠ 乘数)
|
salt_armor_roll: 0xC2B2AE3D27D4EB2F(2026-09-16 armor_roll 增流——互异奇常数 ≠ 乘数)
|
||||||
salt_behavior_roll: 0x85EBCA7758C24E15(2026-09-16 behavior_roll 增流——互异奇常数 ≠ 乘数)
|
salt_behavior_roll: 0x85EBCA7758C24E15(2026-09-16 behavior_roll 增流——互异奇常数 ≠ 乘数)
|
||||||
multiplier: 0x9E3779B97F4A7C15
|
multiplier: 0x9E3779B97F4A7C15
|
||||||
impl_spec: wrap64=二补数自然回绕;禁 float 中间量、禁对中间量用 %、禁"主动修复溢出";常量用分段表达式书写;掩码收尾
|
finalizer_mix: splitmix64 finalizer 变体(2026-09-19 B 案新增——derive = mix64(SALT XOR wrap64(master + scope×GOLDEN));乘数 0xBF58476D1CE4E5B9 / 0x94D049BB133111EB、加数同 GOLDEN_RATIO;全程 63 位掩码;动机=窄种子窗×短局复用会把裸派生种子头部窗口的面值彩票放大进聚合统计,混淆使任何窄种子窗表现如随机抽样)
|
||||||
|
impl_spec: wrap64=二补数自然回绕;禁 float 中间量、禁对中间量用 %、禁"主动修复溢出";常量用分段表达式书写;掩码收尾;mix64 内全程 OUT_MASK 63 位掩码(有符号 int64 算术移位在 63 位正值域与逻辑移位逐位一致——参考实现对齐关键)
|
||||||
reproducibility_claim: 同冒险内同流各 scope 无碰撞 + 跨版本恒定(不做跨 master_seed 全局单射声明)
|
reproducibility_claim: 同冒险内同流各 scope 无碰撞 + 跨版本恒定(不做跨 master_seed 全局单射声明)
|
||||||
master_seed_int64_min: 致命(abs 恒等回绕→与 0 静默别名)
|
master_seed_int64_min: 致命(abs 恒等回绕→与 0 静默别名)
|
||||||
set_master_seed_precondition: 仅全流计数器全零时受理(5 流——2026-09-14 数据配置 漂移批口径 + 2026-09-16 护甲等级掷点批 armor_roll 增流 + 同日敌人技能池批 behavior_roll 增流)
|
set_master_seed_precondition: 仅全流计数器全零时受理(5 流——2026-09-14 数据配置 漂移批口径 + 2026-09-16 护甲等级掷点批 armor_roll 增流 + 同日敌人技能池批 behavior_roll 增流)
|
||||||
@@ -799,3 +800,10 @@ entities:
|
|||||||
# 保守地板缺口收窄 L1≈24/L2≈45〔u=1〕;护栏 B 连带越线披露归调参批三选一);
|
# 保守地板缺口收窄 L1≈24/L2≈45〔u=1〕;护栏 B 连带越线披露归调参批三选一);
|
||||||
# ② 重算入口 tools/clear_dominance_audit.py + 实测板形探针 smoke/board_stat_probe.gd 入 rerun_obligation;
|
# ② 重算入口 tools/clear_dominance_audit.py + 实测板形探针 smoke/board_stat_probe.gd 入 rerun_obligation;
|
||||||
# ③ 06 清单「清图支配性保守地板缺口」条目随回执销项(解决即移除——常设重跑义务留本条目)。
|
# ③ 06 清单「清图支配性保守地板缺口」条目随回执销项(解决即移除——常设重跑义务留本条目)。
|
||||||
|
# 批(掷点测量修复批 B 案 2026-09-19)——rng_service.stream_seed_derivation R2→R3 改版(用户拍板 B 案):
|
||||||
|
# derive = mix64(SALT XOR wrap64(master + scope×GOLDEN)),splitmix64 finalizer 变体终末混淆(乘数
|
||||||
|
# 0xBF58476D1CE4E5B9/0x94D049BB133111EB、加数同 GOLDEN_RATIO、全程 63 位掩码);动机=验收重测批实证
|
||||||
|
# 「连续 30 种子×头部 scope 窗口×40 局复用」把裸派生种子的面值彩票放大 40 倍进聚合统计(18 点 +57%),
|
||||||
|
# 混淆使任何窄种子窗表现如随机抽样(改版后同窗 χ²=13.9 达标);黄金向量 8 常量全量重登记(Python 参考
|
||||||
|
# 实现逐位交叉验证)、R2 旧向量作废;逐 scope 复放语义/计数器契约/存档快照契约不变;冒烟 316 项 0 失败
|
||||||
|
# (含 1 条条件断言因新序列不再触发,317→316 良性);同种子历史坐标随批作废(重测义务=验收批阶段一重跑)。
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
# 验收读数重测批——判读报告(初稿,真人位留空)
|
||||||
|
|
||||||
|
- **日期**:2026-09-19
|
||||||
|
- **口径依据**:`docs/acceptance-ap6-ac.md` v1.0(定稿判读规则全文照搬执行)
|
||||||
|
- **被测构建**:master @ d236d9f(技能池新效应词汇批后;乘区接线+削弱续时+甲效换装+充能退役+rider 五次数值行为变更叠加后的首次全量重测)
|
||||||
|
- **执行环境**:独立 worktree `D:\code\g-plan2-acceptance-rerun`(分支 `acceptance-rerun-20260919`)——绕开主工作区并行会话未提交改动
|
||||||
|
- **数据源状态**:① 模拟批 ✅ 完成(两关 × N=30 × 种子 4200+30 × 策略 both,共 1200 局)② 日志批 ✅ 完成 ③ **真人批 ⬜ 缺位**(3–5 局基线档待用户补跑,k 系数待并入)——按口径「三数据源全部跑完再判读」,本报告全部结论为**初稿**,终稿待真人批合入
|
||||||
|
- **前置验证**:worktree 冒烟 317 项 0 失败(run_smoke 三闸全过)✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ 核心发现:窄种子窗 × 复用放大——掷点统计失真(本批最重要产出;2026-09-19 深勘后根因已修正定稿)
|
||||||
|
|
||||||
|
**一句话**:d20 掷点流的派生公式本身是均匀的,但「30 个连续种子 × 每局只消费头部 ~17~40 个 scope × 每种子被复用 ~40 局」的组合,把头部窗口自身的面值彩票放大 ~40 倍灌进全部聚合统计——验收的档位分布/EV gate 读数因此失真。**修正记录**:本报告首稿曾定性为"派生种子首输出缺陷、真实玩家体验受损",经 2000 种子全局对照与跨步种子对照推翻——公式无恙、玩家单局影响≈机会涨落水平,真实受害者是测量有效性。
|
||||||
|
|
||||||
|
### 证据链(可复现,探针脚本形态见附录)
|
||||||
|
|
||||||
|
1. **逐位比对**:种子 4227 首局前 23 个日志掷点与 `rng.open_stream("armor_roll")` 逐 scope 首输出序列**完全一致**——日志掷点 = 派生种子首输出,无其他变换。
|
||||||
|
2. **逐种子失真**:真实日志按种子聚合 18 点数 0→131(种子 4211 = 0、4227 = 120);二项分布下 n≈700 的 σ≈6,此散布远超抽样涨落——复用放大实锤(每局重吃同一种子的头部窗口,窗口彩票 ×40)。
|
||||||
|
3. **全局均匀对照**:2000 个跨步种子 × 头部 31 scope 等权聚合,χ²=22.8(19df 95% 临界 30.1)——**派生公式全局无偏**;splitmix 混淆版同样干净(χ²=23.5),混淆不解决本问题(问题不在公式)。
|
||||||
|
4. **窗口彩票对照**:MC 实际窗口(连续 30 种子 × 头部 41 scope)18 点 +35% 集中在高权重头部;同规模跨步种子窗口 χ²=26 正常——特定窗口运气 × 复用 = 失真。
|
||||||
|
5. **真实消费模式复现**:按「30 种子 × 40 局 × 每局 8~31 掷」聚合,复现 18 点 +57%(1876/23822)的日志签名。
|
||||||
|
6. **排除项**:纯随机种子首输出均匀(4 万次最大偏差 2.7σ)——引擎 PCG 本体无恙。
|
||||||
|
|
||||||
|
### 影响面评估(修正后)
|
||||||
|
|
||||||
|
- **玩家单局体验:≈无**。一局只有 ~17~40 次掷点,即使种子头部窗口有偏,也与普通骰子运气无法区分(17 次均匀掷点本身就有 ±10pp 级涨落)。**首稿"玩家体验随种子漂移"的说法降级为理论可能性**(只有在单局掷点数大幅增长的未来内容里才可能被感知)。
|
||||||
|
- **测量有效性:实害**。验收掷点面(档位分布/EV/nat20)与任何基于这 30 个种子的聚合统计,都被窗口彩票 ×40 放大污染——本批阶段一两个 gate FAIL 由此归因,不能算到机制或数值头上。**同构隐患**:五条流(board_gen/reward_roll/encounter/armor_roll/behavior_roll)共享此消费模式,窄种子窗 + 短消费窗 + 复用的分析面都会中招。
|
||||||
|
- **潜在陷阱(非现行故障)**:若未来种子外露(种子分享玩法)或单局掷点数大增,窄窗彩票从测量问题升级为体验问题。
|
||||||
|
|
||||||
|
### 修复方向(三案,均已评估;探针级验证见附录)
|
||||||
|
|
||||||
|
- **方案 A(推荐,零游戏代码)**:掷点统计面改用宽种子带——如 4200 起步长 7919 取 ≥100 个种子(保留 4200–4229 子段则历史坐标仍可比),窗口彩票按 1/√种子数摊平;实现 = MC 工具加一档「掷点扫描批」参数。承伤/通关率等压力读数同理受益。
|
||||||
|
- **方案 B(可选加固,一处小改)**:`rng_service.gd` 派生前对 master 做一次非线性混淆(如 splitmix64 finalizer)——任何窄种子窗表现如随机抽样,根治"连续小整数种子"陷阱。逐 scope 回放语义不变;代价 = 黄金向量重登记 + 冒烟回归。全局均匀性已被证明,此案是防御性投资,不紧急。
|
||||||
|
- **方案 C(用户提案:真随机 + 逐次记录)**:技术上可行但代价不成比例——存档序列化快照契约(master_seed)、反事实重算工具(analyze_playtest 依赖确定性重模拟)、逐次可回放语义全部重做,记录文件随局数无限增长;而它解决的问题 A/B 已以小得多的代价覆盖。不推荐,除非未来设计转向"非确定性掷点"价值观。
|
||||||
|
- **共性注记**:无论何案,单局 17~40 掷的"运气窗"本身(某局恰好 18 点多)是骰子本性,修复对象是"系统性放大"而非"运气存在"。
|
||||||
|
|
||||||
|
### B 案落地结果(2026-09-19 用户拍板 B 案,同日实施收口)
|
||||||
|
|
||||||
|
- **实现**:`rng_service.gd` R2→R3——derive = mix64(SALT XOR wrap64(master + scope×GOLDEN)),splitmix64 finalizer 变体(乘数 0xBF58476D1CE4E5B9 / 0x94D049BB133111EB、加数同 GOLDEN_RATIO);**全程 63 位掩码**(有符号 int64 算术移位在正值域与逻辑移位逐位一致——与 Python 参考实现对齐的关键)。逐 scope 复放语义/计数器契约/存档快照契约不变。
|
||||||
|
- **黄金向量**:8 常量全量重登记(冒烟 R3 向量断言 + registry stream_seed_derivation 条目 + Formulas-R3 指向),Python 参考实现与 GDScript 实现逐位交叉验证一致;R2 旧向量作废。
|
||||||
|
- **冒烟**:316 项 0 失败三闸全过(317→316 = 一条"探针首掷恰好暴击才触发"的条件断言在新序列下不触发,良性)。
|
||||||
|
- **R3 版模拟批重跑(1200 局)验证**:
|
||||||
|
- 18 点异常**消失**(1740→846,期望 1010,残差回落到 30 种子窗口彩票的理论噪声带 ≈2σ_eff);
|
||||||
|
- nat20 暴击率 5.92%(带内 PASS);主角→敌全额率 100% PASS;
|
||||||
|
- **敌→主角 EV 减免 25.6% 仍高于理论 21.25%——但现在是干净读数**:档位分布 ×0.25 档 16.6%(理论 10%)、全额 50.0%(理论 55%),指向主角有效 AC 被护甲强化(ac_up)供给抬高 ~1.2 点。这是 B 案清除 RNG 噪声后**首次可见的真实设计信号**,归调参批处置(护甲强化供给是合法杠杆位);
|
||||||
|
- 压力面结论对 RNG 改版稳健:L1 完美档基线格 87% 通关/承伤均 17.0/p90 24,与改版前同方向同量级——阶段二"压力不足"判定不变,仍顺延调参批;
|
||||||
|
- 同种子历史坐标随 R3 改版整体作废(预期内,已登记 registry 批注)。
|
||||||
|
- **遗留提示**:B 案消除的是"窄窗彩票被系统性放大",30 种子的窗口彩票噪声本身仍在(档位分布 gate 若按 ±2σ 独立样本口径判读仍会误报)——**建议阶段一正式重跑时叠加 A 案**(掷点统计面用宽种子带,如 4200+i×7919 × ≥100 种子),两案正交不冲突。
|
||||||
|
|
||||||
|
### A 案叠加落地结果(2026-09-19 用户拍板 A/B 叠加,同日实施收口)
|
||||||
|
|
||||||
|
- **实现**:`level_monte_carlo.gd` 增第 5 参种子模式 `shared|unique`(缺省 shared = 旧行为零变更,保留同种子 A/B 对照用法;unique = 逐局独立种子 seed0+全局序号)。unique 模式下每个 (种子, scope) 恰消费一次 → 聚合掷点统计回归标准二项分布,±2σ gate 口径重新有效——这是 A 案的本质:消除复用权重,而非换种子段。
|
||||||
|
- **A+B 版模拟批重跑(两关 1200 局,逐局独立种子)验证**:
|
||||||
|
- d20 直方图**全面干净**:20 面值全部落在期望 1011 的 ±2.3σ 内(对照:R2 版 18 点 +57%≈20σ);
|
||||||
|
- nat20 暴击率 5.12%(带内 PASS);主角→敌 / 敌→主角暴击率 5.13%/5.09% 双向对齐理论;
|
||||||
|
- **敌→主角档位分布失真仍在但已是干净设计信号**:全额 50.9%(理论 55%,-7.6σ)、×0.25 档 15.0%(理论 10%,+15σ)——指向主角有效 AC 被护甲强化(ac_up +1×2 层)供给抬高 ~1.5 点,EV 减免 24.59% 同源。此偏差**真实且显著**,归调参批裁决(重新校准 gate 把 AC 增益期计入理论模型,或调护甲供给);
|
||||||
|
- 压力面第三次复测稳如磐石:L1 完美档基线格 87% 通关/承伤 16.8/p90 24——R2/R3/A+B 三批同向同量级,"压力不足"判定与 RNG 无关焊死;L2 完美档 87%/13.9·21;
|
||||||
|
- 弃图率读数稳定(完美档 0.02-0.10 次/局,normal 0)。
|
||||||
|
- **A+B 叠加后的验收口径状态**:掷点面 gate 判读从此有效;阶段一正式重跑数据 = 本批(T220949/T221847 两文件);同种子历史坐标已三重作废(R3 改版 + unique 模式),坐标可比性锚改为「本批 A+B 数据」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 阶段一:机制验收(日志批,gate 判读——全部受发现①污染,仅记录现状)
|
||||||
|
|
||||||
|
数据:两份 MC 日志共 318,626 行、1200 局、20,945 次掷点。
|
||||||
|
|
||||||
|
| 指标 | 读数 | 期望带 | 判读 | 注记 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 零承伤轮(窄口径) | 0 / 8076 攻击落地轮 | 0 | ✅ PASS | 伤害下限 1 生效 |
|
||||||
|
| 零掉血轮(宽口径) | 6706 / 13364 敌战轮(50.2%) | observe | 记录 | 与真人旧读数对照待真人批 |
|
||||||
|
| nat20 暴击率 | 4.53% | 5%±2pp | ✅ PASS(带污染注记) | 种子头部偏置使逐种子暴击率漂移大 |
|
||||||
|
| 档位分布(敌→主角) | 全额 50.8%/×0.75 15.0%/×0.5 21.6%/×0.25 12.6% | 55/15/20/10 各±2σ | ❌ FAIL | 归因=RNG 偏置为主 + 护甲强化增益抬 AC 混入(全额缺口方向与增益一致,但幅度超增益可解释范围) |
|
||||||
|
| 玩家侧全额率 | 主角→敌 EV 减免 0.00% | 100% 全额 | ✅ PASS | 敌 AC 关内 0 生效 |
|
||||||
|
| EV 减免(敌→主角) | 23.98% | 21.25%±2pp | ❌ FAIL | 同上归因 |
|
||||||
|
| Boss 血量锚 | 表值 hp=58(蛛化卓尔精灵) | r_boss=150÷153.5≈0.98 | ⚠️ 锚过期 | 口径写于压缩批与卓尔加血前(150→÷3→58);锚值重校准归调参批,本批记录现状 |
|
||||||
|
| 增益战斗期复原 | 三类可复原(attack_up/weaken/减伤族) | observe | ✅ 记录 | 复原面工作正常 |
|
||||||
|
| 快照 buffs 非空 | **8790/14402** | 恒空(盲区口径=0) | ⚠️ 盲区口径已破 | rider/状态批后快照开始携带 buffs(疑 duration-2 状态使衰减段后仍有存留)——**好消息**(盲区闭合),口径文档需改写该节 |
|
||||||
|
| 数据质量·解析失败 | 0 | 0 | ✅ PASS | |
|
||||||
|
| 数据质量·未配对 battle_end | **1200(系统性 1/局)** | 0 | ⚠️ 行序伪影 | 每局恰 1 条 battle_end 落到 run 行切分点之后(level_end 先于 battle_end 落盘);不影响核心统计(分析器不依赖 battle_end),行序归因待核 |
|
||||||
|
|
||||||
|
## 阶段二:压力验收(模拟批基线格,初稿判读——顺延至掷点修复后终判)
|
||||||
|
|
||||||
|
### 第一关(生死带主判据格:MC perfect 基线格 atk+0%/hp+0%,n=30)
|
||||||
|
|
||||||
|
| 指标 | 读数 | gate | 判读 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 整关承伤分布 | p10=13.0 / p50=18 / p90=25.0 / max=28 | p10∈[35,45] 且 p90∈[55,65] | ❌ FAIL(远低于带下沿——压力不足方向) |
|
||||||
|
| 通关率 | 87% | [35%, 65%] | ❌ FAIL(越上界) |
|
||||||
|
| 通关余量 | 胜局剩余 HP 均 7.4 | p90≤13 且 p10≥3(收敛后 gate) | observe(未收敛) |
|
||||||
|
| 平均轮数 | 16.4 | observe | 记录 |
|
||||||
|
| 盲挖档(normal 基线格)通关率 | 73% | observe(生死带下 0% 为预期态) | 记录——73% 与生死带预期相悖,同证压力不足 |
|
||||||
|
|
||||||
|
### 第二关(对照面,无独立 gate)
|
||||||
|
|
||||||
|
| 指标 | 读数 |
|
||||||
|
|---|---|
|
||||||
|
| 完美档基线格通关率 / 承伤 p50/p90 | 87% / 15.5 / 21.2 |
|
||||||
|
| 盲挖档基线格通关率 | 83% |
|
||||||
|
| 台阶倒挂 | L1 87% vs L2 87%——倒挂消失(旧读数 65vs90→65vs80→本批持平),方向性好转 |
|
||||||
|
|
||||||
|
### F4 满配格(gate:普通场 ≤20% / Boss 场 ≤50% 生效 max_hp)
|
||||||
|
|
||||||
|
| 关卡 | 普通场 | Boss 场 | 判读 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| L1 | 6.5% | 15.7% | ✅ PASS |
|
||||||
|
| L2 | 5.9% | 22.8% | ✅ PASS |
|
||||||
|
|
||||||
|
### 战斗级承伤带(普通 ≤20% / Boss ≤50%,全网格聚合)
|
||||||
|
|
||||||
|
全部 9 个(关×类型×深度)分组 ✓ PASS;Boss 战单独出列读数:L1 Boss 场均承伤 26.7% max_hp / 5.9 轮,L2 Boss 35.7% / 5.0 轮——Boss 承伤占比显著高于普通场(设计方向:Boss 是主要伤害来源),无不可控死法迹象(败北节点全部集中于 Boss 位,普通位败北为 0)。
|
||||||
|
|
||||||
|
### 阶段二初稿结论
|
||||||
|
|
||||||
|
双 gate(承伤带 + 通关率)双败,方向一致=**压力不足**(完美档太容易通关、承伤远低于生死带)。按归因规则本应走 §4e 阶梯(敌方输出侧),但发现①属实现缺陷且优先级在前(§4e 边界 1)——**建议顺序:掷点修复批 → 阶段一重跑 → 阶段二调参批**。附带提醒:修复掷点会轻微改变承伤/通关读数(掷点分布变了),调参批应在修复后的重测读数上工作。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 07⑦ 刷新经济监控——基线读数(本批搭车项,2026-09-19 首批基线)
|
||||||
|
|
||||||
|
分析器已新增两读数(`log_analysis.py` 关卡级统计:弃图率=每局受理刷新次数,与 MC 刷新/局同口径;每轮刷新率=刷新次数÷结算轮数)。**首批基线**:
|
||||||
|
|
||||||
|
| 数据面 | 弃图率(次/局) | 每轮刷新率 | 样本 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| MC L1 完美档基线格 | 0.23 | — | 30 局 |
|
||||||
|
| MC L2 完美档基线格 | 0.03 | — | 30 局 |
|
||||||
|
| MC 全网格 L1 完美档 | 0.08 | 0.006 | 300 局 |
|
||||||
|
| MC 全网格 L2 完美档 | 0.01 | 0.001 | 300 局 |
|
||||||
|
| MC 全网格 normal 档(两关) | 0.00 | 0.000 | 600 局 |
|
||||||
|
| 真人日志参照(并行会话今日 600 局模拟,非本批数据) | 完美档 0.12 | 0.008 | 供交叉参照 |
|
||||||
|
|
||||||
|
解读起点(供调参批参考,非结论):完美档低频弃图(~0.1 次/局量级)、normal 档零弃图——与「完美档卡死才刷新」的口径一致(auto_player 刷新=卡死解除手段);normal 档零使用提示 1 RAP 定价对普通玩家可能偏贵或无感知,真人批数据将回答。**阈值数字仍归调参批**(口径不变:现在定是拍脑袋)。
|
||||||
|
|
||||||
|
**顺带核查项**:07⑥ 速杀退化预警的读数(战斗结束未开资格格占比)经核对**现役日志不可推导**——battle_end 行仅含 result+hero_hp,无格面开格状态面。采集义务需等埋点(board 状态入结算快照或独立行),本批不硬做,注记后延。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 待办与回流
|
||||||
|
|
||||||
|
1. **真人批**(用户):基线档 3–5 局 → k 系数 + 零掉血轮宽口径真人对照 → 本报告终稿。
|
||||||
|
2. **掷点测量修复**(待拍板选案):方案 A(宽种子带,零代码)/方案 B(master 混淆加固,黄金向量重登记)/方案 C(真随机+记录,不推荐);选 A 则登记 06 待办为「验收掷点扫描种子带改造」,选 B 则为 rng_service 加固批;阶段一在修复后重跑。
|
||||||
|
3. **口径文档连带修订**(归合并批):`docs/acceptance-ap6-ac.md` 快照 buffs 盲区节改写、Boss 血量锚参照值重校准(58 现值)、§2 消费读数行补刷新两读数;`06-待办清单`「刷新经济性监控」条目保留至调参批定阈值。
|
||||||
|
4. **曲线调参批门**:确认改为「掷点测量修复 + 阶段一重跑后」起跑(原门=验收读数)。
|
||||||
|
|
||||||
|
## 附录:探针脚本(复现用)
|
||||||
|
|
||||||
|
本批全部 RNG 探针为一次性 `/tmp` 脚本(rng_probe*.gd),核心复现路径:
|
||||||
|
① 从日志抽种子 4227 首局前 23 掷与 `open_stream("armor_roll")` 逐 scope 首输出逐位比对;
|
||||||
|
② `SALT_ARMOR_ROLL ^ (seed + scope×GOLDEN) & 0x7FFF…` 直喂 `RandomNumberGenerator.randi_range(1,20)` 画头部直方图;
|
||||||
|
③ 按 30 种子×40 局×8~31 掷聚合复现失真签名。诊断用工程内探针 `smoke/rng_face_probe.gd` 已随批删除,不留残留。
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
## 当前状态快照(收口批先更新本节,再追加台账;≤10 行)
|
## 当前状态快照(收口批先更新本节,再追加台账;≤10 行)
|
||||||
|
|
||||||
- **更新于**:2026-09-19(技能池节奏体验验证批〔已收口:用户四点拍板(判读带/多种子重跑/免真人补采/授权执行)→ 60 种子正式读数落调参表 v0.13 → 06 条目解决移除 → 合并 b270a94 落 master → worktree 已清,见台账 89-90〕)+(并行)旗行为基线前置采集批:拔旗定价复核+插旗不可逆提案两条自 06 清单销项〔用户拍板标记完成〕,观测面以 07-体验验证清单⑧承接——玩法零改动〔冒烟补旗奖励语义断言 11 项,见台账 83〕,清单 55→53 条)+(并行对答会话)**技能池新效应词汇批已执行收口**:妨害技 debuff 新类型 + 必中附加分量 rider_mult 0.75〔多段命中退役〕,实装面 = 仅 L2 Boss 卓尔〔毒爆+毒分量、蛛网束缚→失衡〕;冒烟 306 项 0 失败+四探针 PASS;800 局模拟试玩 L2 基线 90%→80% 死因集中 Boss、L1 回归一致;文档 v0.17/v0.10/v0.10+registry+07+README+06 条目移除;已提交 d236d9f〔含我方台账 81-83 各面收编〕)+(本会话)**冒烟脚本错误门禁立闸**:tools/run_smoke.py 三闸〔退出码/摘要失败数/SCRIPT ERROR 扫描〕双路径验证 exit 1/0——盲区=脚本错误不计失败数且静默吞剩余断言(83 号首跑实证+并行执行批 board_type 漏网二次实证);CLAUDE.md 冒烟命令改指包装器;台账 84)+(本会话)**地形变异排期改批**:06 清单地形变异名下五条+数据配置「变异表旧字段集」一条状态行统一加注——2026-09-19 用户拍板整体改排 **Alpha 版本之后**、垂直切片期不讨论不做相关实现(纯文档零代码);反制维度承载失义归属行改写〔原与显影尘重定批同窗合流→两批错窗,显影尘侧排期未动〕;魔法道具三条不在范围未动;台账 85)+(本会话)**清图支配性对账重跑批**:06 待办「清图支配性保守地板缺口」对账义务经用户指令提前执行——现行值链重推主判式:非完美清图 18 语境全负、完美态 L1 前段实测板形翻正 +8.3(唯一翻正面),**裁决②"非支配设计态"维持建议已呈报待确认**;保守地板缺口收窄至 L1≈24/L2≈45 当量(u=1,实测板形口径);护栏 B 防钓鱼上界被 C=13 常态越线(压缩批未登记连带面)披露归调参批三选一;重算器 tools/clear_dominance_audit.py(调参批常设入口)+ 板形探针 board_stat_probe.gd 入册;模拟 1200 局双画像配对(analyze_playtest.py +弃图率/轮出口读数+--policy 过滤):刷新流通关率全档位 ≥ 推到底流、刷新策略实测 0.03~0.23 次/局几乎不发生;06 条目销项(清单 51 条);报告 design/research/audit-clear-dominance-2026-09-19.md;冒烟 317 项 0 失败;台账 86)+(本会话)**插旗不可逆全套落地批(真人试玩两 bug 修复批)**:bug⑤「不能挖旗格」=2026-09-18 插旗不可逆提案(台账 72)经用户拍板**转正全套落地**——禁拔旗+挖旗格放行+四情况兑付改判(②雷格直挖只吃挖雷惩罚标中不发/④安全格直挖零惩罚零奖励+作废归因行);bug⑥「L2 棋盘下缘裁掉约 1/6 格高」=格边长公式漏算 (N−1)×2px 网格间距,修复=公式计入间距+垂直预留 24px;冒烟 317→331 项 0 失败(四情况探针+布局公式回归探针);四探针 PASS〔过程登记:board_view 缩进解析错误曾致三 UI 探针静默挂死——冒烟纯脚本模式不加载表现层抓不到,--check-only 定位〕;80 局 MC 双画像回归读数与批前逐位一致(零行为变更);文档 排雷玩法 v0.5/行动经济 v0.4/战斗结算 v0.18/地图战斗资源 v0.12/教学引导/07⑧ 重写+registry 五处;台账 87)+(本会话)**worktree 铁律批**:用户立规「一切开发/设计任务走独立 worktree,完事合并回 master,主工作区禁直改直提交」——CLAUDE.md 新增分支纪律节+硬性红线首条(豁免面仅 active.md 与 .zcode/)+PreToolUse 守卫 worktree-guard.sh 双路拦截(主区 Edit/Write 直改+主区 git commit,exit 2);15 用例三态全 PASS,本批自身走 worktree 示范(合并 0b015dc);活体拦截待下会话确认(钩子注册表会话启动时快照不热载+工作区钩子信任提示须用户批准);grandfather=挂起批次 84/85/86 分三笔收口(c595397/8057956/2ca3e20,registry 按 hunk 拆分只提对账回执);台账 88(本批 commit 信息内写 87 系并行撞号)
|
- **更新于**:2026-09-19(技能池节奏体验验证批〔已收口:用户四点拍板(判读带/多种子重跑/免真人补采/授权执行)→ 60 种子正式读数落调参表 v0.13 → 06 条目解决移除 → 合并 b270a94 落 master → worktree 已清,见台账 89-90〕)+(并行)旗行为基线前置采集批:拔旗定价复核+插旗不可逆提案两条自 06 清单销项〔用户拍板标记完成〕,观测面以 07-体验验证清单⑧承接——玩法零改动〔冒烟补旗奖励语义断言 11 项,见台账 83〕,清单 55→53 条)+(并行对答会话)**技能池新效应词汇批已执行收口**:妨害技 debuff 新类型 + 必中附加分量 rider_mult 0.75〔多段命中退役〕,实装面 = 仅 L2 Boss 卓尔〔毒爆+毒分量、蛛网束缚→失衡〕;冒烟 306 项 0 失败+四探针 PASS;800 局模拟试玩 L2 基线 90%→80% 死因集中 Boss、L1 回归一致;文档 v0.17/v0.10/v0.10+registry+07+README+06 条目移除;已提交 d236d9f〔含我方台账 81-83 各面收编〕)+(本会话)**冒烟脚本错误门禁立闸**:tools/run_smoke.py 三闸〔退出码/摘要失败数/SCRIPT ERROR 扫描〕双路径验证 exit 1/0——盲区=脚本错误不计失败数且静默吞剩余断言(83 号首跑实证+并行执行批 board_type 漏网二次实证);CLAUDE.md 冒烟命令改指包装器;台账 84)+(本会话)**地形变异排期改批**:06 清单地形变异名下五条+数据配置「变异表旧字段集」一条状态行统一加注——2026-09-19 用户拍板整体改排 **Alpha 版本之后**、垂直切片期不讨论不做相关实现(纯文档零代码);反制维度承载失义归属行改写〔原与显影尘重定批同窗合流→两批错窗,显影尘侧排期未动〕;魔法道具三条不在范围未动;台账 85)+(本会话)**清图支配性对账重跑批**:06 待办「清图支配性保守地板缺口」对账义务经用户指令提前执行——现行值链重推主判式:非完美清图 18 语境全负、完美态 L1 前段实测板形翻正 +8.3(唯一翻正面),**裁决②"非支配设计态"维持建议已呈报待确认**;保守地板缺口收窄至 L1≈24/L2≈45 当量(u=1,实测板形口径);护栏 B 防钓鱼上界被 C=13 常态越线(压缩批未登记连带面)披露归调参批三选一;重算器 tools/clear_dominance_audit.py(调参批常设入口)+ 板形探针 board_stat_probe.gd 入册;模拟 1200 局双画像配对(analyze_playtest.py +弃图率/轮出口读数+--policy 过滤):刷新流通关率全档位 ≥ 推到底流、刷新策略实测 0.03~0.23 次/局几乎不发生;06 条目销项(清单 51 条);报告 design/research/audit-clear-dominance-2026-09-19.md;冒烟 317 项 0 失败;台账 86)+(本会话)**插旗不可逆全套落地批(真人试玩两 bug 修复批)**:bug⑤「不能挖旗格」=2026-09-18 插旗不可逆提案(台账 72)经用户拍板**转正全套落地**——禁拔旗+挖旗格放行+四情况兑付改判(②雷格直挖只吃挖雷惩罚标中不发/④安全格直挖零惩罚零奖励+作废归因行);bug⑥「L2 棋盘下缘裁掉约 1/6 格高」=格边长公式漏算 (N−1)×2px 网格间距,修复=公式计入间距+垂直预留 24px;冒烟 317→331 项 0 失败(四情况探针+布局公式回归探针);四探针 PASS〔过程登记:board_view 缩进解析错误曾致三 UI 探针静默挂死——冒烟纯脚本模式不加载表现层抓不到,--check-only 定位〕;80 局 MC 双画像回归读数与批前逐位一致(零行为变更);文档 排雷玩法 v0.5/行动经济 v0.4/战斗结算 v0.18/地图战斗资源 v0.12/教学引导/07⑧ 重写+registry 五处;台账 87)+(本会话)**worktree 铁律批**:用户立规「一切开发/设计任务走独立 worktree,完事合并回 master,主工作区禁直改直提交」——CLAUDE.md 新增分支纪律节+硬性红线首条(豁免面仅 active.md 与 .zcode/)+PreToolUse 守卫 worktree-guard.sh 双路拦截(主区 Edit/Write 直改+主区 git commit,exit 2);15 用例三态全 PASS,本批自身走 worktree 示范(合并 0b015dc);活体拦截待下会话确认(钩子注册表会话启动时快照不热载+工作区钩子信任提示须用户批准);grandfather=挂起批次 84/85/86 分三笔收口(c595397/8057956/2ca3e20,registry 按 hunk 拆分只提对账回执);台账 88(本批 commit 信息内写 87 系并行撞号)
|
||||||
|
- **更新于**:2026-09-19(**验收读数重测批 + 掷点测量修复批 A+B**,独立 worktree 分支执行):模拟+日志两源 1200 局判读初稿已出(真人批缺位待用户 3–5 局);掷点发现经两轮修正定稿=窄种子窗×复用放大(派生公式无恙、玩家单局影响≈机会涨落);B 案 rng_service R2→R3 混淆派生(黄金向量 8 常量重登记)+A 案 MC unique 种子模式已落地,A+B 版直方图全面干净=阶段一正式数据(T220949/T221847);压力面三批复测焊死(L1 完美档 87% 越上界+承伤带下=压力不足);敌→主角 EV 24.6%=护甲强化抬 AC~1.5 点干净设计信号归调参批;07⑦ 刷新基线已采+07⑨ 试玩指引新增;判读报告 production/qa/acceptance-rerun-20260919.md,台账 92-95(原分支内 84-87 因并行撞号重编)
|
||||||
- **在飞**:表现层升级批未启动(前置 = 美术清单 P0 样张 + 用户看图拍板敌人卡形态);两份美术清单合并待拍板;多批工作区未提交
|
- **在飞**:表现层升级批未启动(前置 = 美术清单 P0 样张 + 用户看图拍板敌人卡形态);两份美术清单合并待拍板;多批工作区未提交
|
||||||
- **已完成**:06 待办清理批(清单 87→80 条;三裁决落地:变异死分支删/快照域进 Alpha 首批/未开格微光拍板;排雷玩法节新增禁拔旗提案登记)+ 冒险内成长提案登记批(GP 临时资源+商店房提案登记 06 清单关卡节点地图节,未评估;台账 74)
|
- **已完成**:06 待办清理批(清单 87→80 条;三裁决落地:变异死分支删/快照域进 Alpha 首批/未开格微光拍板;排雷玩法节新增禁拔旗提案登记)+ 冒险内成长提案登记批(GP 临时资源+商店房提案登记 06 清单关卡节点地图节,未评估;台账 74)
|
||||||
- **已完成**:**数值语言拍板批(加法核,台账 75)**——全项目数值语言=小整数加法核(模板 C 骨架+模板 A 成长语言)成文 01-核心循环;甲效矩阵 percent→三档点数 +1/0/−1(pierce×heavy=0 用户拍板,今晨五档 percent 调参〔台账 71〕随批退役);增益池/AC 折扣档/暴击保留百分比+粒度口径成文;元进度/GP 投值语言锁 flat;冒烟 300 全绿+四探针 PASS+flat vs percent A/B(L1 逐值全同、L2 Boss 战基础攻击 +1 生效 hp+100 档 50→60%)
|
- **已完成**:**数值语言拍板批(加法核,台账 75)**——全项目数值语言=小整数加法核(模板 C 骨架+模板 A 成长语言)成文 01-核心循环;甲效矩阵 percent→三档点数 +1/0/−1(pierce×heavy=0 用户拍板,今晨五档 percent 调参〔台账 71〕随批退役);增益池/AC 折扣档/暴击保留百分比+粒度口径成文;元进度/GP 投值语言锁 flat;冒烟 300 全绿+四探针 PASS+flat vs percent A/B(L1 逐值全同、L2 Boss 战基础攻击 +1 生效 hp+100 档 50→60%)
|
||||||
@@ -236,3 +237,11 @@
|
|||||||
|
|
||||||
90. **技能池节奏体验验证批·收口批(2026-09-19,本会话——用户四点拍板后全权执行)**:**拍板链**:①判读带=过涝=敌群连续特殊技无普攻基底(连击 ≥3 记信号,阈值 3 为代拍板默认——M=4 与冷却 2-4 语义下 2 连属正常波动)、过旱=战斗整体全敌人零特殊技(跳战场单列,多敌任一出过即正常);②60 distinct seeds 重跑批准;③真人采集免补(用户 3 局试玩满意);④确认收尾流程后按 worktree 铁律合并。**正式读数**(240 局=60 种子×双策略×两关,rhythm_batch.gd):特殊技执行份额全部对表——地精 10.4%(静态 10%)/地精一伙 8.4%(4200 系 0/484 假象正式证伪)/熊地精系 28.9–42.4%/巨蜘蛛 34.8%/酋长 28.9%/卓尔 35.4%(L2 池含闸速率抽样复核完成);保底越界 0/247;过涝信号 8/1440 场 max 连击 3(无过涝);过旱 456/1440 场(31.7%)按构成分解集中在短命杂鱼(地精系 82–87%、巨蜘蛛 52%,均出招 1.2–2.2 拍;耐久敌酋长 0%/卓尔 2%)=敌人 1–2 拍即死、保底 M=4 结构性无法触发的生存时长问题,非池配置问题——「杂鱼技能纹理」观测移交 06 清单 Alpha 池验证条目(未新增裁决项)。**落地面**:06 条目「单拍行为环的体验验证(改型:技能池节奏体验验证)」解决移除;难度曲线与Boss v0.13(池 EV 锚行读数登记+修订行方法论规则:节奏/EV 读数须 ≥50 distinct seeds);工具三件入库(skill_rhythm_audit.py / skill_rhythm_probe.gd / rhythm_batch.gd)。**提交面**:worktree 两笔(99134ff 工具+e6814c4 文档)合并 b270a94 落 master——合并窗口恰逢并行会话提交 87aa89d(插旗批,顺带将本会话台账 89 一并入库),无冲突、编辑共存已核(06 条目移除+Alpha 注记+调参表登记三处在位);worktree 与分支已清。**遗留 flag**:master 工作区出现 `%SystemDrive%/` 怪名未跟踪目录(疑似某脚本环境变量未展开的产物,非本会话所建,未动待用户处置);docs/playnote.md/.gitignore 并行在飞改动未碰
|
90. **技能池节奏体验验证批·收口批(2026-09-19,本会话——用户四点拍板后全权执行)**:**拍板链**:①判读带=过涝=敌群连续特殊技无普攻基底(连击 ≥3 记信号,阈值 3 为代拍板默认——M=4 与冷却 2-4 语义下 2 连属正常波动)、过旱=战斗整体全敌人零特殊技(跳战场单列,多敌任一出过即正常);②60 distinct seeds 重跑批准;③真人采集免补(用户 3 局试玩满意);④确认收尾流程后按 worktree 铁律合并。**正式读数**(240 局=60 种子×双策略×两关,rhythm_batch.gd):特殊技执行份额全部对表——地精 10.4%(静态 10%)/地精一伙 8.4%(4200 系 0/484 假象正式证伪)/熊地精系 28.9–42.4%/巨蜘蛛 34.8%/酋长 28.9%/卓尔 35.4%(L2 池含闸速率抽样复核完成);保底越界 0/247;过涝信号 8/1440 场 max 连击 3(无过涝);过旱 456/1440 场(31.7%)按构成分解集中在短命杂鱼(地精系 82–87%、巨蜘蛛 52%,均出招 1.2–2.2 拍;耐久敌酋长 0%/卓尔 2%)=敌人 1–2 拍即死、保底 M=4 结构性无法触发的生存时长问题,非池配置问题——「杂鱼技能纹理」观测移交 06 清单 Alpha 池验证条目(未新增裁决项)。**落地面**:06 条目「单拍行为环的体验验证(改型:技能池节奏体验验证)」解决移除;难度曲线与Boss v0.13(池 EV 锚行读数登记+修订行方法论规则:节奏/EV 读数须 ≥50 distinct seeds);工具三件入库(skill_rhythm_audit.py / skill_rhythm_probe.gd / rhythm_batch.gd)。**提交面**:worktree 两笔(99134ff 工具+e6814c4 文档)合并 b270a94 落 master——合并窗口恰逢并行会话提交 87aa89d(插旗批,顺带将本会话台账 89 一并入库),无冲突、编辑共存已核(06 条目移除+Alpha 注记+调参表登记三处在位);worktree 与分支已清。**遗留 flag**:master 工作区出现 `%SystemDrive%/` 怪名未跟踪目录(疑似某脚本环境变量未展开的产物,非本会话所建,未动待用户处置);docs/playnote.md/.gitignore 并行在飞改动未碰
|
||||||
91. **gitignore 缓存误写忽略批(2026-09-19,本会话——用户质询仓库根 {GUID}*.db 文件触发;纯仓库卫生零游戏代码)**:**定性**——仓库根怪目录 `%SystemDrive%/ProgramData/Microsoft/Windows/Caches/` 内三文件(cversions.2.db+{6AF0698E-…}.2.ver0x…01.db+{DDF571F2-…}.2.ver0x…01.db)与真实系统目录 C:\ProgramData\Microsoft\Windows\Caches\ 同名同构(版本后缀 01 vs 系统现役 10),系 Windows shell(资源管理器)缓存库(ESE 格式,非 SQLite、非 ZCode 记忆——记忆在 ~/.zcode/cli/memories/);成因=某进程环境变量 SystemDrive 未展开,按字面相对路径把缓存库写进仓库根(台账 90 遗留 flag 本批处置)。**落地**——.gitignore OS 节增 `%SystemDrive%/` 整目录忽略;另收编主区在飞行 .zcode/plans/ 行(计划模式存档目录、无自动清理机制,会话批准计划即落快照属预期行为非垃圾);误写目录本体经核对为系统缓存副本后删除。**流程**——按 worktree 铁律:worktree 分支 batch/gitignore-junk-caches 两笔提交合并回 master;合并前主区 .gitignore 在飞脏改动(.zcode/plans/ 行)checkout 丢弃(内容已收编入本批提交防冲突);台账预写 90 撞号(并行会话技能池收口批先登记) amend 改 91。**验证**——git status 复核 %SystemDrive%/ 不再出现在未跟踪;冒烟不适用(零游戏代码)。
|
91. **gitignore 缓存误写忽略批(2026-09-19,本会话——用户质询仓库根 {GUID}*.db 文件触发;纯仓库卫生零游戏代码)**:**定性**——仓库根怪目录 `%SystemDrive%/ProgramData/Microsoft/Windows/Caches/` 内三文件(cversions.2.db+{6AF0698E-…}.2.ver0x…01.db+{DDF571F2-…}.2.ver0x…01.db)与真实系统目录 C:\ProgramData\Microsoft\Windows\Caches\ 同名同构(版本后缀 01 vs 系统现役 10),系 Windows shell(资源管理器)缓存库(ESE 格式,非 SQLite、非 ZCode 记忆——记忆在 ~/.zcode/cli/memories/);成因=某进程环境变量 SystemDrive 未展开,按字面相对路径把缓存库写进仓库根(台账 90 遗留 flag 本批处置)。**落地**——.gitignore OS 节增 `%SystemDrive%/` 整目录忽略;另收编主区在飞行 .zcode/plans/ 行(计划模式存档目录、无自动清理机制,会话批准计划即落快照属预期行为非垃圾);误写目录本体经核对为系统缓存副本后删除。**流程**——按 worktree 铁律:worktree 分支 batch/gitignore-junk-caches 两笔提交合并回 master;合并前主区 .gitignore 在飞脏改动(.zcode/plans/ 行)checkout 丢弃(内容已收编入本批提交防冲突);台账预写 90 撞号(并行会话技能池收口批先登记) amend 改 91。**验证**——git status 复核 %SystemDrive%/ 不再出现在未跟踪;冒烟不适用(零游戏代码)。
|
||||||
|
|
||||||
|
92. **验收读数重测批·初稿(2026-09-19,本会话——独立 worktree 分支 `acceptance-rerun-20260919`,主工作区并行改动零接触)**:①执行面=worktree 检出 d236d9f(编辑器缓存刷新后冒烟 317 项 0 失败三闸全过)→ 模拟批 level_monte_carlo N=30 种子 4200+30 both 两关共 1200 局 → 日志批 log_analysis.py + 专项脚本(方向档位分布/基线格承伤分位/按种子直方图)。②**核心发现=掷点流结构性种子偏置**(证据链四步:种子 4227 首局前 23 掷与 open_stream("armor_roll") 逐 scope 首输出逐位一致;种子级头部偏置——4227 头部 30 scope 含 4 个 18 点、4211 零 18 点;真实消费模式 30 种子×40 局×8~31 掷复现失真签名 18 点 +57%≈20σ;纯随机种子对照均匀排除引擎 RNG 本体)——机理=每局从 scope 0 重取号(可回放设计)×派生种子首输出头部聚类×MC 短局(均 ~17 掷)把头部重采样 40 遍;**真实玩家影响**=单局 d20 体验随种子系统性漂移,AC 档位 55/15/20/10 设计地基受损;修复试探=单次预热无效、splitmix64 种子混淆未达标(685→369 仍 11σ),建议立项掷点修复批(含黄金向量重登记+阶段一重跑义务),五条流连带核查。③阶段一判读=零承伤轮 0 PASS/nat20 4.53% PASS(带污染注记)/档位分布与 EV 减免 FAIL(归因 RNG)/Boss 血量锚参照值过期(58 现值)/快照 buffs 非空 8790/14402 盲区口径已破(rider 批后快照携带状态,好消息)/未配对 battle_end 1200 系统性行序伪影(1/局,不影响核心统计)。④阶段二初稿=L1 完美档基线格通关率 87% 越 gate[35,65] 上界+承伤 p10=13/p90=25 远低于带 [35,45]/[55,65](压力不足方向),F4 满配格两关全 PASS,台阶倒挂消失(87vs87),Boss 承伤占比 26.7%/35.7% 出列正常;双 gate 判定顺延掷点修复后终判(§4e 边界 1 先查实现缺陷)。⑤07⑦ 刷新经济基线已采:弃图率 MC 完美档 L1 基线格 0.23/L2 0.03 次/局、normal 档 0、每轮刷新率 ≤0.6%——分析器新增两读数列(弃图率=受理刷新/局与 MC 同口径、每轮刷新率=刷新÷结算轮数),阈值仍归调参批;07⑥ 速杀占比经核不可推导(battle_end 无格面状态面)注记后延。⑥产出=log_analysis.py 读数+07⑦ 基线注记+production/qa/acceptance-rerun-20260919.md 判读报告(真人位留空);06「刷新经济性监控」保留至调参批。⑦诊断探针 rng_face_probe.gd 已删不留残留;/tmp 探针脚本复现路径记录于报告附录。
|
||||||
|
|
||||||
|
93. **掷点发现根因修正批(2026-09-19,本会话——用户质询"为何用伪随机/有无修复方案"触发深勘)**:①修正内容=台账 84 首稿定性「派生种子首输出缺陷、玩家体验受损」**两项均推翻**——2000 跨步种子×头部 31 scope 等权对照 χ²=22.8 证明派生公式全局均匀(splitmix 混淆版 χ²=23.5 同干净);跨步种子窗口 χ²=26 正常 vs 连续 30 种子窗口 18 点 +35% 集中高权重头部。②修正后根因=**窄种子窗(连续 30 种子×头部 ~17~40 scope)×每种子 40 局复用**→窗口自身面值彩票放大 40 倍灌进聚合统计;真实玩家单局影响≈机会涨落(一局仅 17~40 掷,与均匀骰子运气不可区分),实害面=测量有效性(阶段一档位/EV gate 读数失真归因于此,不能算机制/数值账);同构隐患=五条流共享消费模式。③修复三案呈报:A 宽种子带掷点扫描批(推荐,零游戏代码,保 4200–4229 子段可比性)/B rng_service master 混淆加固(可选,保逐 scope 回放语义,黄金向量重登记)/C 真随机+逐次记录(用户原提案,评估后不推荐——存档契约/反事实重算/回放语义全重做+文件无限增长,被 A/B 以小代价覆盖);共性注记=单局运气窗是骰子本性,修复对象是系统性放大。④判读报告核心发现节已重写(修正记录留痕),待用户选案后执行。
|
||||||
|
|
||||||
|
94. **掷点测量修复批 B 案实施批(2026-09-19,本会话——用户拍板「选择B方案」后同日执行收口)**:①实现=rng_service.gd R2→R3:derive = mix64(SALT XOR wrap64(master + scope×GOLDEN)),splitmix64 finalizer 变体(乘数 0xBF58476D1CE4E5B9/0x94D049BB133111EB 分段常量、加数同 GOLDEN_RATIO);关键技术点=**全程 OUT_MASK 63 位掩码**——有符号 int64 算术移位在 63 位正值域与逻辑移位逐位一致,这是与 Python 参考实现对齐的关键(首版 64 位掩码镜像曾出现向量漂移即此因);逐 scope 复放/计数器/存档快照三契约不变。②黄金向量 8 常量重登记(smoke R3 断言+registry stream_seed_derivation 条目含 finalizer_mix 属性+impl_spec 补掩码规约+批注),Python 参考实现与 GDScript 逐位交叉验证一致,R2 旧向量作废。③验证=全量冒烟 316 项 0 失败三闸全过(317→316 系「探针首掷暴击」条件断言在新序列下不触发,良性非丢失);R3 版 MC 两关 1200 局重跑:18 点异常消失(1740→846 回期望带,残差=30 种子窗口彩票理论噪声),nat20 5.92% PASS,**敌→主角 EV 25.6% 仍高但转为干净读数**——档位 ×0.25 档 16.6%/全额 50.0% 指向护甲强化抬主角有效 AC ~1.2 点,B 案清除 RNG 噪声后首个真实设计信号,归调参批;压力面 L1 完美档 87%/承伤 17.0/p90 24 与改版前同向同量级(判定稳健),阶段二仍顺延调参批。④遗留=A/B 两案正交——30 种子窗口彩票噪声仍在,阶段一正式重跑建议叠加 A 案宽种子带(报告已注记);同种子历史坐标随 R3 作废(registry 批注留痕)。⑤诊断探针 rng_verify_probe.gd 用后即删;中断重启的首次 R3 半程日志(T212718)弃用,重跑完整批(T214329/T215335)为权威数据。
|
||||||
|
|
||||||
|
95. **掷点测量修复批 A 案叠加实施批(2026-09-19,本会话——用户拍板「把A方案也叠加进去」)**:①实现=level_monte_carlo.gd 增第 5 参种子模式 shared|unique(缺省 shared 旧行为零变更保同种子 A/B 对照用法;unique=逐局独立种子,每个 (种子,scope) 恰消费一次 → 聚合掷点统计回归标准二项分布、±2σ gate 口径重新有效——A 案本质=消除复用权重而非换种子段)。②A+B 版两关 1200 局重跑验证:d20 直方图全面干净(20 面值全落期望 ±2.3σ,对照 R2 版 18 点 +57%≈20σ)、nat20 5.12% 带内、双向暴击率对齐理论;敌→主角档位分布失真仍在但已是干净设计信号(全额 50.9%/-7.6σ、×0.25 档 15.0%/+15σ、EV 24.59%——护甲强化抬主角有效 AC ~1.5 点,真实且显著,归调参批裁决:gate 计入 AC 增益期或调护甲供给);压力面第三批复测焊死(L1 完美档 87%/16.8·p90 24,R2/R3/A+B 三批同向同量级);弃图率稳定(完美档 0.02-0.10/局、normal 0)。③A+B 叠加后阶段一正式重跑数据=T220949/T221847 两文件;同种子历史坐标三重作废(R3+unique),可比性锚改挂本批 A+B 数据。④报告补 A 案落地节+台账 87;gameplay 代码零改动(仅 MC 工具第 5 参)。
|
||||||
@@ -3,19 +3,23 @@
|
|||||||
# Date: 2026-09-10
|
# Date: 2026-09-10
|
||||||
# RngService autoload(数据配置)——封闭命名流单点(Rule 5)。玩法代码禁止 randomize()/自建 RandomNumberGenerator。
|
# RngService autoload(数据配置)——封闭命名流单点(Rule 5)。玩法代码禁止 randomize()/自建 RandomNumberGenerator。
|
||||||
# 实现 GDD:design/archive/gdd-2026-09-14/d2-data-config.md(系统 ID D2·数据配置——registry 追溯锚,命名规范见 CLAUDE.md)
|
# 实现 GDD:design/archive/gdd-2026-09-14/d2-data-config.md(系统 ID D2·数据配置——registry 追溯锚,命名规范见 CLAUDE.md)
|
||||||
# R2 派生公式(黄金向量已预验证):derive = (SALT XOR wrap64(master + scope×GOLDEN)) AND 0x7FFF…
|
# R3 派生公式(2026-09-19 掷点测量修复批 B 案改版,黄金向量已重登记):derive = mix64(SALT XOR wrap64(master + scope×GOLDEN))——splitmix64 finalizer 变体终末混淆,见 _mix64 注记;R2 旧向量随批作废
|
||||||
# 取号语义:全新实例首个 open_stream = scope 0(地图战斗资源 预推进术语的登记口径)。
|
# 取号语义:全新实例首个 open_stream = scope 0(地图战斗资源 预推进术语的登记口径)。
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
const STREAM_NAMES := ["board_gen", "reward_roll", "encounter", "armor_roll", "behavior_roll"] # 2026-09-12 增 encounter(遭遇随机化批);2026-09-16 增 armor_roll(护甲等级掷点批)+ behavior_roll(敌人技能池批——开轮摇号,每敌派生独立子流,registry rng_service 条目同步)
|
const STREAM_NAMES := ["board_gen", "reward_roll", "encounter", "armor_roll", "behavior_roll"] # 2026-09-12 增 encounter(遭遇随机化批);2026-09-16 增 armor_roll(护甲等级掷点批)+ behavior_roll(敌人技能池批——开轮摇号,每敌派生独立子流,registry rng_service 条目同步)
|
||||||
|
|
||||||
# 分段表达式书写(数据配置 R2 实现级规约——禁 ≥2^63 完整字面量)
|
# 分段表达式书写(数据配置 R3 实现级规约——禁 ≥2^63 完整字面量)
|
||||||
const GOLDEN_RATIO := (0x9E3779B9 << 32) | 0x7F4A7C15 # 0x9E3779B97F4A7C15
|
const GOLDEN_RATIO := (0x9E3779B9 << 32) | 0x7F4A7C15 # 0x9E3779B97F4A7C15
|
||||||
const SALT_BOARD_GEN := (0xA0761D64 << 32) | 0x78BD642F # 0xA0761D6478BD642F
|
const SALT_BOARD_GEN := (0xA0761D64 << 32) | 0x78BD642F # 0xA0761D6478BD642F
|
||||||
const SALT_REWARD_ROLL := (0xE7037ED1 << 32) | 0xA0B428DB # 0xE7037ED1A0B428DB
|
const SALT_REWARD_ROLL := (0xE7037ED1 << 32) | 0xA0B428DB # 0xE7037ED1A0B428DB
|
||||||
const SALT_ENCOUNTER := (0x8EBC6AF0 << 32) | 0x9C88C6E3 # 0x8EBC6AF09C88C6E3(遭遇骰——registry stream_seed_derivation 权威值;旧值 0x5DEECE66D<<32 超 int64 被截断,黄金向量漂移)
|
const SALT_ENCOUNTER := (0x8EBC6AF0 << 32) | 0x9C88C6E3 # 0x8EBC6AF09C88C6E3(遭遇骰——registry stream_seed_derivation 权威值;旧值 0x5DEECE66D<<32 超 int64 被截断,黄金向量漂移)
|
||||||
const SALT_ARMOR_ROLL := (0xC2B2AE3D << 32) | 0x27D4EB2F # 0xC2B2AE3D27D4EB2F(护甲掷点流——互异奇常数 ≠ 乘数;黄金向量见冒烟/registry 同批登记)
|
const SALT_ARMOR_ROLL := (0xC2B2AE3D << 32) | 0x27D4EB2F # 0xC2B2AE3D27D4EB2F(护甲掷点流——互异奇常数 ≠ 乘数;黄金向量见冒烟/registry 同批登记)
|
||||||
const SALT_BEHAVIOR_ROLL := (0x85EBCA77 << 32) | 0x58C24E15 # 0x85EBCA7758C24E15(技能摇号流——互异奇常数 ≠ 乘数;黄金向量见冒烟/registry 同批登记)
|
const SALT_BEHAVIOR_ROLL := (0x85EBCA77 << 32) | 0x58C24E15 # 0x85EBCA7758C24E15(技能摇号流——互异奇常数 ≠ 乘数;黄金向量见冒烟/registry 同批登记)
|
||||||
|
# R3 混淆终末函数常量(splitmix64 finalizer 变体——互异奇常数 ≠ 乘数;全程 OUT_MASK 63 位掩码保持
|
||||||
|
# 有符号 int64 移位语义与参考实现逐位一致,见 _mix64 注记)
|
||||||
|
const MIX_MUL_A := (0xBF58476D << 32) | 0x1CE4E5B9 # 0xBF58476D1CE4E5B9
|
||||||
|
const MIX_MUL_B := (0x94D049BB << 32) | 0x133111EB # 0x94D049BB133111EB
|
||||||
# behavior_roll 派生向量(registry 同批登记):子流 scope = spawn_index × STRIDE + 单敌摇号序(0 起)。
|
# behavior_roll 派生向量(registry 同批登记):子流 scope = spawn_index × STRIDE + 单敌摇号序(0 起)。
|
||||||
# 每敌消费自己的 scope 段 → 单敌出招轨迹可独立复放、敌间互不穿插(proposal 约束二)。
|
# 每敌消费自己的 scope 段 → 单敌出招轨迹可独立复放、敌间互不穿插(proposal 约束二)。
|
||||||
const BEHAVIOR_SUBSTREAM_STRIDE := 1000000
|
const BEHAVIOR_SUBSTREAM_STRIDE := 1000000
|
||||||
@@ -52,7 +56,19 @@ func derive_at(stream: String, scope: int) -> int:
|
|||||||
assert(scope >= 0, "负 scope 与 scope+2^63 经输出掩码别名(禁止)")
|
assert(scope >= 0, "负 scope 与 scope+2^63 经输出掩码别名(禁止)")
|
||||||
var t: int = _master_seed + scope * GOLDEN_RATIO # wrap64 自然回绕——禁 float 中间量/禁 %/禁主动修复
|
var t: int = _master_seed + scope * GOLDEN_RATIO # wrap64 自然回绕——禁 float 中间量/禁 %/禁主动修复
|
||||||
var seed_val: int = _salt_for(stream) ^ t
|
var seed_val: int = _salt_for(stream) ^ t
|
||||||
return seed_val & OUT_MASK
|
return _mix64(seed_val)
|
||||||
|
|
||||||
|
|
||||||
|
# R3 派生终末混淆(splitmix64 finalizer 变体,2026-09-19 掷点测量修复批 B 案):裸派生种子直接作
|
||||||
|
# PCG 初始状态时,「连续小整数 master × 头部 scope 窗口」的面值彩票会被短局复用放大进聚合统计
|
||||||
|
# (验收重测批实证:30 连续种子 × 头部窗口 × 40 局复用 → 18 点聚合 +57%);此混淆使任何窄种子窗
|
||||||
|
# 表现如随机抽样。纯函数、逐 scope 复放语义不变;全程 OUT_MASK 63 位掩码——有符号 int64 的 >>
|
||||||
|
# 为算术移位,63 位正值域内与逻辑移位逐位一致,这是与参考实现(Python 无符号模型)对齐的关键。
|
||||||
|
func _mix64(z: int) -> int:
|
||||||
|
z = (z + GOLDEN_RATIO) & OUT_MASK
|
||||||
|
z = (z ^ (z >> 30)) * MIX_MUL_A & OUT_MASK
|
||||||
|
z = (z ^ (z >> 27)) * MIX_MUL_B & OUT_MASK
|
||||||
|
return (z ^ (z >> 31)) & OUT_MASK
|
||||||
|
|
||||||
|
|
||||||
func set_master_seed(seed_val: int) -> void:
|
func set_master_seed(seed_val: int) -> void:
|
||||||
|
|||||||
@@ -3,10 +3,17 @@
|
|||||||
# 关卡期望扫描(难度曲线与Boss 调参期关卡侧批量工具的原型——对应 棋盘生成 F4 / 战斗侧 monte_carlo.gd):
|
# 关卡期望扫描(难度曲线与Boss 调参期关卡侧批量工具的原型——对应 棋盘生成 F4 / 战斗侧 monte_carlo.gd):
|
||||||
# 扫描 atk% × hp% 网格(模拟天赋树数值提升档位),输出每档"通关率 / 整关承伤期望 / 败北节点分布 /
|
# 扫描 atk% × hp% 网格(模拟天赋树数值提升档位),输出每档"通关率 / 整关承伤期望 / 败北节点分布 /
|
||||||
# 通关剩余 HP 期望 / 进 Boss HP 期望 / 平均轮数"——把"多少数值能通关、通关要掉多少血"变成可测量数据。
|
# 通关剩余 HP 期望 / 进 Boss HP 期望 / 平均轮数"——把"多少数值能通关、通关要掉多少血"变成可测量数据。
|
||||||
# 运行:Godot_console.exe --headless --path . --script res://smoke/level_monte_carlo.gd -- [N] [seed0]
|
# 运行:Godot_console.exe --headless --path . --script res://smoke/level_monte_carlo.gd -- [N] [seed0] [normal|perfect|both] [level_index] [shared|unique]
|
||||||
|
# 种子模式(2026-09-19 掷点测量修复批 A 案):shared(默认,旧行为)= 同批次全部格子×策略共用种子
|
||||||
|
# seed0+i——同种子历史坐标可比,但同一 (种子, scope) 被反复消费,聚合掷点统计被头部窗口彩票放大
|
||||||
|
# (验收重测批实证);unique = 逐局独立种子(seed0 + 全局递增序号),每个掷点恰消费一次 → 聚合
|
||||||
|
# 掷点统计回归标准二项分布(±2σ gate 口径重新有效)。验收掷点面用 unique;同种子 A/B 对照用 shared。
|
||||||
extends SceneTree
|
extends SceneTree
|
||||||
|
|
||||||
|
|
||||||
|
var _run_cursor := 0 # unique 模式全局局序号(seed = seed0 + cursor)
|
||||||
|
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
var args := OS.get_cmdline_user_args()
|
var args := OS.get_cmdline_user_args()
|
||||||
var n := 30
|
var n := 30
|
||||||
@@ -42,9 +49,14 @@ func _initialize() -> void:
|
|||||||
policies = ["perfect"]
|
policies = ["perfect"]
|
||||||
elif policy_arg == "both":
|
elif policy_arg == "both":
|
||||||
policies = ["normal", "perfect"]
|
policies = ["normal", "perfect"]
|
||||||
|
# 种子模式(掷点测量修复批 A 案——见文件头注记):缺省 shared = 旧行为零变更
|
||||||
|
var seed_mode := "shared"
|
||||||
|
if args.size() >= 5 and args[4] in ["shared", "unique"]:
|
||||||
|
seed_mode = args[4]
|
||||||
var atk_axis: Array = [0, 50, 100, 150, 200]
|
var atk_axis: Array = [0, 50, 100, 150, 200]
|
||||||
var hp_axis: Array = [0, 100]
|
var hp_axis: Array = [0, 100]
|
||||||
print("=== 关卡期望扫描:level %d · N=%d/格 · 种子 %d+%d · 策略=%s ===" % [level_arg, n, seed0, n, policy_arg])
|
var seed_label := "种子 %d+%d" % [seed0, n] if seed_mode == "shared" else "种子 %d 起逐局独立" % seed0
|
||||||
|
print("=== 关卡期望扫描:level %d · N=%d/格 · %s · 策略=%s · 种子模式=%s ===" % [level_arg, n, seed_label, policy_arg, seed_mode])
|
||||||
print("%-6s %-10s %-8s %-14s %-14s %-14s %-10s %-12s %-12s %-10s %-10s %-8s %-8s" % ["策略", "atk%/hp%", "通关率", "整关承伤均/p90", "通关剩余HP均(胜)", "进BossHP均", "平均轮数", "踩雷/战", "普通承伤/场%", "跳战率", "Boss承伤%", "踩雷/局", "刷新/局"])
|
print("%-6s %-10s %-8s %-14s %-14s %-14s %-10s %-12s %-12s %-10s %-10s %-8s %-8s" % ["策略", "atk%/hp%", "通关率", "整关承伤均/p90", "通关剩余HP均(胜)", "进BossHP均", "平均轮数", "踩雷/战", "普通承伤/场%", "跳战率", "Boss承伤%", "踩雷/局", "刷新/局"])
|
||||||
var perfect_mine_total := 0 # 完美档构造保证 = 零踩雷(只挖已证安全格)——扫描末断言
|
var perfect_mine_total := 0 # 完美档构造保证 = 零踩雷(只挖已证安全格)——扫描末断言
|
||||||
for policy in policies:
|
for policy in policies:
|
||||||
@@ -65,7 +77,9 @@ func _initialize() -> void:
|
|||||||
var mine_per_run: Array = []
|
var mine_per_run: Array = []
|
||||||
var refresh_per_run: Array = []
|
var refresh_per_run: Array = []
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
var st = autoplay.run_level(db, seed0 + i, level_arg, atk_pct, hp_pct, true, logger, policy)
|
var seed_val := seed0 + i if seed_mode == "shared" else seed0 + _run_cursor
|
||||||
|
_run_cursor += 1
|
||||||
|
var st = autoplay.run_level(db, seed_val, level_arg, atk_pct, hp_pct, true, logger, policy)
|
||||||
dmg_all.append(st.hero_dmg)
|
dmg_all.append(st.hero_dmg)
|
||||||
rounds_all.append(st.rounds)
|
rounds_all.append(st.rounds)
|
||||||
mine_per_run.append(int(st.mine_hits))
|
mine_per_run.append(int(st.mine_hits))
|
||||||
|
|||||||
@@ -31,15 +31,16 @@ func _initialize() -> void:
|
|||||||
print(" error: [%s] %s" % [d.category, d.message])
|
print(" error: [%s] %s" % [d.category, d.message])
|
||||||
var rng = load("res://core/rng_service.gd").new()
|
var rng = load("res://core/rng_service.gd").new()
|
||||||
rng.set_master_seed(42)
|
rng.set_master_seed(42)
|
||||||
# R2 黄金向量(数据配置 AC-3)
|
# R3 黄金向量(数据配置 AC-3——2026-09-19 掷点测量修复批 B 案改版:derive 后过 splitmix64 终末混淆,
|
||||||
check(rng.derive_at("board_gen", 0) == 2339089373825164293, "R2 向量 board_gen m=42 scope=0")
|
# Python 参考实现逐位交叉验证一致;R2 旧向量随批作废)
|
||||||
check(rng.derive_at("board_gen", 1) == 4485977604321908752, "R2 向量 board_gen m=42 scope=1")
|
check(rng.derive_at("board_gen", 0) == 8672514112661456564, "R3 向量 board_gen m=42 scope=0")
|
||||||
check(rng.derive_at("board_gen", 2) == 2024629813010603131, "R2 向量 board_gen m=42 scope=2")
|
check(rng.derive_at("board_gen", 1) == 8834291164406037215, "R3 向量 board_gen m=42 scope=1")
|
||||||
check(rng.derive_at("board_gen", 3) == 8849696722413293638, "R2 向量 board_gen m=42 scope=3")
|
check(rng.derive_at("board_gen", 2) == 7714373262647006282, "R3 向量 board_gen m=42 scope=2")
|
||||||
check(rng.derive_at("reward_roll", 0) == 7422916049646135537, "R2 向量 reward_roll m=42 scope=0")
|
check(rng.derive_at("board_gen", 3) == 1280102845971471347, "R3 向量 board_gen m=42 scope=3")
|
||||||
check(rng.derive_at("encounter", 0) == 1061841193803499209, "R2 向量 encounter m=42 scope=0(registry salt_encounter=0x8EBC6AF09C88C6E3 权威值)")
|
check(rng.derive_at("reward_roll", 0) == 8363815839763232861, "R3 向量 reward_roll m=42 scope=0")
|
||||||
check(rng.derive_at("armor_roll", 0) == 4806095330042243845, "R2 向量 armor_roll m=42 scope=0(护甲等级掷点批 2026-09-16——registry salt_armor_roll=0xC2B2AE3D27D4EB2F 权威值)")
|
check(rng.derive_at("encounter", 0) == 5906263231575069166, "R3 向量 encounter m=42 scope=0(registry salt_encounter=0x8EBC6AF09C88C6E3 权威值)")
|
||||||
check(rng.derive_at("behavior_roll", 0) == 426657203655691839, "R2 向量 behavior_roll m=42 scope=0(敌人技能池批 2026-09-16——registry salt_behavior_roll=0x85EBCA7758C24E15 权威值)")
|
check(rng.derive_at("armor_roll", 0) == 1459964581993244806, "R3 向量 armor_roll m=42 scope=0(护甲等级掷点批 2026-09-16——registry salt_armor_roll=0xC2B2AE3D27D4EB2F 权威值)")
|
||||||
|
check(rng.derive_at("behavior_roll", 0) == 1791557311233092846, "R3 向量 behavior_roll m=42 scope=0(敌人技能池批 2026-09-16——registry salt_behavior_roll=0x85EBCA7758C24E15 权威值)")
|
||||||
check(rng.derive_at("board_gen", 0) == rng.derive_at("board_gen", 0), "derive_at 纯函数恒等")
|
check(rng.derive_at("board_gen", 0) == rng.derive_at("board_gen", 0), "derive_at 纯函数恒等")
|
||||||
# scope 取号语义:首个 open_stream = scope 0;计数器单调
|
# scope 取号语义:首个 open_stream = scope 0;计数器单调
|
||||||
var s0 = rng.open_stream("board_gen")
|
var s0 = rng.open_stream("board_gen")
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ class RunAcc:
|
|||||||
self.snapshot_buffs_total = 0
|
self.snapshot_buffs_total = 0
|
||||||
self.round_ledger = [] # --rounds 逐轮流水
|
self.round_ledger = [] # --rounds 逐轮流水
|
||||||
self.roll_rows = [] # 命中掷点候选字段的 step 行
|
self.roll_rows = [] # 命中掷点候选字段的 step 行
|
||||||
|
self.refresh_count = 0 # 受理的弃图刷新次数(action 行 op=refresh accepted=True)
|
||||||
self._prev_hp = None # 上一结算快照的主角 HP(宽口径逐轮差分用)
|
self._prev_hp = None # 上一结算快照的主角 HP(宽口径逐轮差分用)
|
||||||
self._last_enemy_present = False
|
self._last_enemy_present = False
|
||||||
|
|
||||||
@@ -164,6 +165,11 @@ class RunAcc:
|
|||||||
self.result = e.get("result", "")
|
self.result = e.get("result", "")
|
||||||
self.end_hp = int(e.get("hp", 0))
|
self.end_hp = int(e.get("hp", 0))
|
||||||
|
|
||||||
|
def on_action(self, e):
|
||||||
|
# 刷新经济监控(07 清单⑦):只计受理成功的弃图刷新——被拒尝试不构成弃图。
|
||||||
|
if e.get("op") == "refresh" and e.get("accepted"):
|
||||||
|
self.refresh_count += 1
|
||||||
|
|
||||||
# -- 轮窗口收口(核心口径都在这里)------------------------------------
|
# -- 轮窗口收口(核心口径都在这里)------------------------------------
|
||||||
|
|
||||||
def _finalize_round(self, snap, battle, hp, enemy_present):
|
def _finalize_round(self, snap, battle, hp, enemy_present):
|
||||||
@@ -326,7 +332,9 @@ def _feed(run, res, kind, e):
|
|||||||
run.on_battle_end(e)
|
run.on_battle_end(e)
|
||||||
elif kind == "level_end":
|
elif kind == "level_end":
|
||||||
run.on_level_end(e)
|
run.on_level_end(e)
|
||||||
# action / ux / diagnosis 等其余 kind:本工具当前无消费面,静默跳过
|
elif kind == "action":
|
||||||
|
run.on_action(e)
|
||||||
|
# ux / diagnosis 等其余 kind:本工具当前无消费面,静默跳过
|
||||||
|
|
||||||
|
|
||||||
def resolve_inputs(arg):
|
def resolve_inputs(arg):
|
||||||
@@ -355,6 +363,8 @@ def aggregate_levels(runs):
|
|||||||
wins = sum(1 for r in rs if r.result == "victory")
|
wins = sum(1 for r in rs if r.result == "victory")
|
||||||
boss_rs = [r for r in rs if r.boss_enter_hp() is not None]
|
boss_rs = [r for r in rs if r.boss_enter_hp() is not None]
|
||||||
win_rs = [r for r in rs if r.result == "victory"]
|
win_rs = [r for r in rs if r.result == "victory"]
|
||||||
|
total_rounds = sum(r.rounds_total for r in rs)
|
||||||
|
total_refresh = sum(r.refresh_count for r in rs)
|
||||||
rows.append({
|
rows.append({
|
||||||
"level": lvl, "policy": policy or "—", "runs": n,
|
"level": lvl, "policy": policy or "—", "runs": n,
|
||||||
"clear_rate": wins / n if n else None,
|
"clear_rate": wins / n if n else None,
|
||||||
@@ -362,6 +372,8 @@ def aggregate_levels(runs):
|
|||||||
"avg_boss_hp": (sum(r.boss_enter_hp() for r in boss_rs) / len(boss_rs)) if boss_rs else None,
|
"avg_boss_hp": (sum(r.boss_enter_hp() for r in boss_rs) / len(boss_rs)) if boss_rs else None,
|
||||||
"avg_end_hp": (sum(r.end_hp for r in win_rs) / len(win_rs)) if win_rs else None,
|
"avg_end_hp": (sum(r.end_hp for r in win_rs) / len(win_rs)) if win_rs else None,
|
||||||
"avg_dmg": sum(r.damage_total for r in rs) / n if n else None,
|
"avg_dmg": sum(r.damage_total for r in rs) / n if n else None,
|
||||||
|
"refresh_per_run": total_refresh / n if n else None, # 弃图率(与 MC 刷新/局同口径)
|
||||||
|
"refresh_per_round": total_refresh / total_rounds if total_rounds else None, # 每轮刷新率
|
||||||
})
|
})
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
@@ -502,13 +514,17 @@ def render(res_files, args, out):
|
|||||||
print("== 关卡级统计 ==", file=out)
|
print("== 关卡级统计 ==", file=out)
|
||||||
print(" 口径:局=run 行切分(无 run 行的旧日志整文件一局);通关=result=victory;", file=out)
|
print(" 口径:局=run 行切分(无 run 行的旧日志整文件一局);通关=result=victory;", file=out)
|
||||||
print(" 进BossHP=Boss首结算快照HP+首轮承伤−首轮治疗(精确反推);平均轮数=每局settlement数。", file=out)
|
print(" 进BossHP=Boss首结算快照HP+首轮承伤−首轮治疗(精确反推);平均轮数=每局settlement数。", file=out)
|
||||||
hdr = f" {'关卡':>6} {'档位':>8} {'局数':>5} {'通关率':>7} {'平均轮数':>8} {'进BossHP均':>10} {'通关剩余HP均':>12} {'整局承伤均':>10}"
|
print(" 弃图率=每局受理刷新次数(07⑦ 基线读数,与 MC 刷新/局同口径);", file=out)
|
||||||
|
print(" 每轮刷新率=刷新次数÷结算轮数(组内加权)。阈值数字归调参批,本表只出基线。", file=out)
|
||||||
|
hdr = (f" {'关卡':>6} {'档位':>8} {'局数':>5} {'通关率':>7} {'平均轮数':>8} {'进BossHP均':>10} "
|
||||||
|
f"{'通关剩余HP均':>12} {'整局承伤均':>10} {'弃图率':>7} {'每轮刷新率':>9}")
|
||||||
print(hdr, file=out)
|
print(hdr, file=out)
|
||||||
for row in aggregate_levels(all_runs):
|
for row in aggregate_levels(all_runs):
|
||||||
print(f" {str(row['level']):>6} {row['policy']:>8} {row['runs']:>5} "
|
print(f" {str(row['level']):>6} {row['policy']:>8} {row['runs']:>5} "
|
||||||
f"{fmt(row['clear_rate'] * 100 if row['clear_rate'] is not None else None):>6}% "
|
f"{fmt(row['clear_rate'] * 100 if row['clear_rate'] is not None else None):>6}% "
|
||||||
f"{fmt(row['avg_rounds']):>8} {fmt(row['avg_boss_hp']):>10} "
|
f"{fmt(row['avg_rounds']):>8} {fmt(row['avg_boss_hp']):>10} "
|
||||||
f"{fmt(row['avg_end_hp']):>12} {fmt(row['avg_dmg']):>10}", file=out)
|
f"{fmt(row['avg_end_hp']):>12} {fmt(row['avg_dmg']):>10} "
|
||||||
|
f"{fmt(row['refresh_per_run'], 2):>7} {fmt(row['refresh_per_round'], 3):>9}", file=out)
|
||||||
print(file=out)
|
print(file=out)
|
||||||
|
|
||||||
print("== 战斗级统计(按 关卡/节点类型/深度 分组;对照承伤带 普通≤20%、Boss≤50% max_hp)==", file=out)
|
print("== 战斗级统计(按 关卡/节点类型/深度 分组;对照承伤带 普通≤20%、Boss≤50% max_hp)==", file=out)
|
||||||
@@ -553,11 +569,11 @@ def render(res_files, args, out):
|
|||||||
|
|
||||||
if args.per_run:
|
if args.per_run:
|
||||||
print("== 逐局明细(--per-run)==", file=out)
|
print("== 逐局明细(--per-run)==", file=out)
|
||||||
print(f" {'文件':<28} {'种子':>6} {'档位':>8} {'结果':>8} {'轮数':>4} {'承伤':>5} {'零承伤轮':>8} {'进BossHP':>8} {'终局HP':>6}", file=out)
|
print(f" {'文件':<28} {'种子':>6} {'档位':>8} {'结果':>8} {'轮数':>4} {'承伤':>5} {'零承伤轮':>8} {'进BossHP':>8} {'终局HP':>6} {'刷新':>4}", file=out)
|
||||||
for run in all_runs:
|
for run in all_runs:
|
||||||
print(f" {run.src_file:<28} {str(run.seed):>6} {run.policy or '—':>8} "
|
print(f" {run.src_file:<28} {str(run.seed):>6} {run.policy or '—':>8} "
|
||||||
f"{run.result or '—':>8} {run.rounds_total:>4} {run.damage_total:>5} "
|
f"{run.result or '—':>8} {run.rounds_total:>4} {run.damage_total:>5} "
|
||||||
f"{run.zero_narrow:>8} {fmt(run.boss_enter_hp(), 0):>8} {str(run.end_hp):>6}", file=out)
|
f"{run.zero_narrow:>8} {fmt(run.boss_enter_hp(), 0):>8} {str(run.end_hp):>6} {run.refresh_count:>4}", file=out)
|
||||||
print(file=out)
|
print(file=out)
|
||||||
|
|
||||||
if args.rounds:
|
if args.rounds:
|
||||||
|
|||||||
Reference in new issue
Block a user