From d73508ffa96b259da9bbb6efbde78681a331ab54 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sat, 19 Sep 2026 15:40:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(audit):=20=E6=B8=85=E5=9B=BE=E6=94=AF?= =?UTF-8?q?=E9=85=8D=E6=80=A7=E5=AF=B9=E8=B4=A6=E9=87=8D=E8=B7=91=E6=89=B9?= =?UTF-8?q?=E2=80=94=E2=80=94=E6=9D=A1=E6=AC=BE=E2=91=A4=E7=8E=B0=E8=A1=8C?= =?UTF-8?q?=E5=80=BC=E9=93=BE=E9=87=8D=E6=8E=A8=EF=BC=88=E5=8F=AA=E8=AF=BB?= =?UTF-8?q?=E5=AF=B9=E8=B4=A6=E9=9B=B6=E6=95=B0=E5=80=BC=E6=94=B9=E5=8A=A8?= =?UTF-8?q?=EF=BC=9B2026-09-19=20=E7=94=A8=E6=88=B7=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E7=BB=8F=20plan=20=E6=89=B9=E5=87=86=E6=8F=90=E5=89=8D?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=2006=20=E5=BE=85=E5=8A=9E=E5=AF=B9=E8=B4=A6?= =?UTF-8?q?=E4=B9=89=E5=8A=A1=EF=BC=9B=E5=8F=B0=E8=B4=A6=2086=EF=BC=89?= =?UTF-8?q?=E2=80=94=E2=80=94=E2=91=A0=E9=87=8D=E7=AE=97=E5=99=A8=20tools/?= =?UTF-8?q?clear=5Fdominance=5Faudit.py=EF=BC=88registry=20clause5=5Fdomin?= =?UTF-8?q?ance=20=E5=88=A4=E5=BC=8F=E5=85=A8=E5=8F=82=E6=95=B0=20CLI=20?= =?UTF-8?q?=E5=8F=AF=E9=85=8D=EF=BC=9D=E9=9A=BE=E5=BA=A6=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E8=B0=83=E5=8F=82=E6=89=B9=E5=B8=B8=E8=AE=BE=E9=87=8D=E8=B7=91?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=EF=BC=9BE=5Fdig=20=E4=B8=83=E5=9E=8B=2067=20?= =?UTF-8?q?=E6=9D=83=E9=87=8D=E6=B1=A0=E9=87=8D=E6=8E=A8=20(54+39u)=C3=B76?= =?UTF-8?q?7=E2=89=881.388=E3=80=94u=3D1=E3=80=95=EF=BC=9BV=5Fmine=20?= =?UTF-8?q?=E5=8F=8C=E5=8F=A3=E5=BE=84=EF=BC=9A=E7=94=B2=3D=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E5=85=AC=E5=BC=8F=20u=C3=97m=5Famb=20=E8=BF=9E?= =?UTF-8?q?=E7=BB=AD=E5=AF=B9=E6=AF=94=20/=20=E4=B9=99=3D=E6=9E=81?= =?UTF-8?q?=E6=80=A7=E7=9F=A9=E9=98=B5=E8=B4=9F=E5=90=91=E5=AD=97=E5=85=B8?= =?UTF-8?q?=E5=8A=A0=E6=9D=83=20(42+50.4u)=C3=B767=E2=89=881.379=20?= =?UTF-8?q?=E4=B8=BB=E8=AF=BB=E6=95=B0=E2=80=94=E2=80=94=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E5=85=AC=E5=BC=8F=E6=88=90=E6=96=87=E4=BA=8E"=E6=89=80?= =?UTF-8?q?=E6=9C=89=E9=9B=B7=E2=86=92=E5=9B=BA=E5=AE=9A=E4=BC=8F=E5=87=BB?= =?UTF-8?q?"=E6=97=A7=E4=B8=96=E7=95=8C=EF=BC=8C=E7=9F=A9=E9=98=B5?= =?UTF-8?q?=E6=89=B9=E5=90=8E=E8=B8=A9=E9=9B=B7=E6=83=A9=E7=BD=9A=E6=8C=89?= =?UTF-8?q?=E6=A0=BC=E5=9E=8B=E8=B7=AF=E7=94=B1=EF=BC=89=EF=BC=9B=E2=91=A1?= =?UTF-8?q?=E6=9D=BF=E5=BD=A2=E6=8E=A2=E9=92=88=20smoke/board=5Fstat=5Fpro?= =?UTF-8?q?be.gd=EF=BC=88200=20=E6=A0=B7=E6=9C=AC/=E8=A1=8C=EF=BC=9A?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=E5=B9=B8=E5=AD=98=E9=9B=B7=2010=C3=9710?= =?UTF-8?q?=E2=89=8812.9=20/=2012=C3=9712=E2=89=8822.4=EF=BC=8C=E8=BF=9C?= =?UTF-8?q?=E4=BD=8E=E4=BA=8E=E5=90=8D=E4=B9=89=E5=88=9D=E5=B8=83=2023/34?= =?UTF-8?q?=E2=80=94=E2=80=94"=E5=85=88=E5=B8=83=E5=90=8E=E5=88=A0"?= =?UTF-8?q?=E8=90=BD=E5=9C=B0=E5=80=BC=EF=BC=89=EF=BC=9B=E2=91=A2=E4=B8=BB?= =?UTF-8?q?=E7=BB=93=E8=AE=BA=EF=BC=88=E8=AE=BE=E8=AE=A1=E6=9D=83=E5=A8=81?= =?UTF-8?q?=20design/research/audit-clear-dominance-2026-09-19.md=EF=BC=89?= =?UTF-8?q?=EF=BC=9A=E9=9D=9E=E5=AE=8C=E7=BE=8E=E6=80=81=2018=20=E8=AF=AD?= =?UTF-8?q?=E5=A2=83=E5=85=A8=E8=B4=9F=E3=80=81=E5=AE=8C=E7=BE=8E=E6=80=81?= =?UTF-8?q?=E5=94=AF=E4=B8=80=E7=BF=BB=E6=AD=A3=E9=9D=A2=3DL1=20=E5=89=8D?= =?UTF-8?q?=E6=AE=B5=E5=AE=9E=E6=B5=8B=E6=9D=BF=E5=BD=A2=20+8.3=E2=80=94?= =?UTF-8?q?=E2=80=94=E4=B8=8E=202026-09-14=20=E9=87=8D=E7=AE=97=E6=89=B9?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=90=8C=E5=90=91=EF=BC=8C=E8=A3=81=E5=86=B3?= =?UTF-8?q?=E2=91=A1"=E6=B8=85=E5=9B=BE=E9=9D=9E=E4=B8=A5=E6=A0=BC?= =?UTF-8?q?=E6=94=AF=E9=85=8D=3D=E8=AE=BE=E8=AE=A1=E6=80=81"=E7=BB=B4?= =?UTF-8?q?=E6=8C=81=E5=BB=BA=E8=AE=AE=E5=91=88=E6=8A=A5=EF=BC=88=E6=8B=8D?= =?UTF-8?q?=E6=9D=BF=E5=BD=92=E7=94=A8=E6=88=B7=EF=BC=89=EF=BC=9B=E4=BF=9D?= =?UTF-8?q?=E5=AE=88=E5=9C=B0=E6=9D=BF=E7=BC=BA=E5=8F=A3=E6=94=B6=E7=AA=84?= =?UTF-8?q?=20L1=E2=89=8824/L2=E2=89=8845=20=E5=BD=93=E9=87=8F=EF=BC=88u?= =?UTF-8?q?=3D1=C2=B7=E5=AF=B9=20C=5Fmin=3D8=EF=BC=89=EF=BC=9B=E6=8A=A4?= =?UTF-8?q?=E6=A0=8F=20B=20=E9=98=B2=E9=92=93=E9=B1=BC=E4=B8=8A=E7=95=8C?= =?UTF-8?q?=E8=A2=AB=20C=3D13=20=E5=B8=B8=E6=80=81=E8=B6=8A=E7=BA=BF?= =?UTF-8?q?=EF=BC=882026-09-17=20=E5=8E=8B=E7=BC=A9=E6=89=B9=E6=9C=AA?= =?UTF-8?q?=E7=99=BB=E8=AE=B0=E8=BF=9E=E5=B8=A6=E9=9D=A2=EF=BC=89=E6=8A=AB?= =?UTF-8?q?=E9=9C=B2=E5=BD=92=E8=B0=83=E5=8F=82=E6=89=B9=E4=B8=89=E9=80=89?= =?UTF-8?q?=E4=B8=80=EF=BC=9B=E2=91=A3analyze=5Fplaytest.py=20=E5=A2=9E?= =?UTF-8?q?=E5=BC=83=E5=9B=BE=E5=88=B7=E6=96=B0=E7=8E=87/=E8=BD=AE?= =?UTF-8?q?=E5=87=BA=E5=8F=A3=E5=88=86=E5=B8=83=E8=AF=BB=E6=95=B0+--policy?= =?UTF-8?q?=20=E8=BF=87=E6=BB=A4=EF=BC=88=E5=88=B7=E6=96=B0=E7=BB=8F?= =?UTF-8?q?=E6=B5=8E=E6=80=A7=E7=9B=91=E6=8E=A7=E6=9D=A1=E7=9B=AE=E5=88=86?= =?UTF-8?q?=E6=9E=90=E4=BE=A7=E7=BC=BA=E5=8F=A3=E9=97=AD=E5=90=88=EF=BC=8C?= =?UTF-8?q?=E5=9F=BA=E7=BA=BF=E4=BB=8D=E6=8C=82=E9=AA=8C=E6=94=B6=E9=87=8D?= =?UTF-8?q?=E6=B5=8B=E6=89=B9=EF=BC=89=E2=80=94=E2=80=94=E5=8F=8C=E7=94=BB?= =?UTF-8?q?=E5=83=8F=E9=85=8D=E5=AF=B9=201200=20=E5=B1=80=E5=AE=9E?= =?UTF-8?q?=E8=AF=81=EF=BC=9A=E5=88=B7=E6=96=B0=E6=B5=81=E9=80=9A=E5=85=B3?= =?UTF-8?q?=E7=8E=87=E5=85=A8=E6=A1=A3=E4=BD=8D=20=E2=89=A5=20=E6=8E=A8?= =?UTF-8?q?=E5=88=B0=E5=BA=95=E6=B5=81=EF=BC=88L1=20=E5=9F=BA=E7=BA=BF?= =?UTF-8?q?=E6=A1=A3=2087%=20vs=2073%=EF=BC=89=E3=80=81=E5=AE=9E=E6=B5=8B?= =?UTF-8?q?=E7=9B=B2=E6=8C=96=E8=B8=A9=E9=9B=B7=200.30=E2=80=930.87/?= =?UTF-8?q?=E5=B1=80=20=E8=BF=9C=E4=BD=8E=E4=BA=8E=E5=88=A4=E5=BC=8F?= =?UTF-8?q?=E4=BF=9D=E5=AE=88=E8=AE=A1=E4=BB=B7=20E[=E8=B8=A9=E9=9B=B7]?= =?UTF-8?q?=E2=89=8812=E2=80=9321/=E6=9D=BF=EF=BC=88=E5=9D=87=E5=8C=80?= =?UTF-8?q?=E4=BA=A4=E9=94=99=E5=85=A8=E6=B1=A0=E7=9B=B2=E6=8C=96=3D?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E6=80=A7=E4=B8=8A=E7=95=8C=EF=BC=89=E3=80=81?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E7=AD=96=E7=95=A5=200.03=E2=80=930.23=20?= =?UTF-8?q?=E6=AC=A1/=E5=B1=80=E5=87=A0=E4=B9=8E=E4=B8=8D=E5=8F=91?= =?UTF-8?q?=E7=94=9F=E2=80=94=E2=80=94"=E6=B8=85=E5=9B=BE=E8=A2=AB?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E6=B7=98=E6=B1=B0"=E9=A3=8E=E9=99=A9?= =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E9=9D=A2=E4=B8=8D=E6=88=90=E7=AB=8B=EF=BC=9B?= =?UTF-8?q?=E2=91=A4=E7=99=BB=E8=AE=B0=E9=9D=A2=EF=BC=9Aregistry=20clause5?= =?UTF-8?q?=5Fdominance=20rerun=5F2026=5F09=5F19=20=E5=9B=9E=E6=89=A7+reru?= =?UTF-8?q?n=5Fobligation=20=E6=8C=82=E4=B8=A4=E5=B7=A5=E5=85=B7=E5=85=A5?= =?UTF-8?q?=E5=8F=A3+=E4=BF=AE=E8=AE=A2=E7=95=99=E7=97=95=E5=9D=97?= =?UTF-8?q?=EF=BC=9B=E9=9A=BE=E5=BA=A6=E6=9B=B2=E7=BA=BF=E4=B8=8EBoss.md?= =?UTF-8?q?=20=E6=AD=A3=E6=96=87=E5=AF=B9=E8=B4=A6=E5=8F=A5=E6=94=B9?= =?UTF-8?q?=E5=86=99+P1=20=E8=A1=8C=E5=9B=9E=E6=89=A7=E6=8C=87=E9=92=88?= =?UTF-8?q?=EF=BC=9B=E2=91=A5=E9=AA=8C=E8=AF=81=EF=BC=9A=E5=86=92=E7=83=9F?= =?UTF-8?q?=20317=20=E9=A1=B9=200=20=E5=A4=B1=E8=B4=A5=EF=BC=88=E6=9C=AC?= =?UTF-8?q?=E6=89=B9=E9=9B=B6=E6=B8=B8=E6=88=8F=E4=BB=A3=E7=A0=81=EF=BC=8C?= =?UTF-8?q?=E5=86=92=E7=83=9F=E4=BD=9C=E5=9B=9E=E5=BD=92=E6=8A=A4=E6=A0=8F?= =?UTF-8?q?=EF=BC=89=E3=80=82=E8=BE=B9=E7=95=8C=EF=BC=9A06=20=E6=9D=A1?= =?UTF-8?q?=E7=9B=AE=E5=88=A0=E9=99=A4=E4=B8=8E=20active.md=20=E5=8F=B0?= =?UTF-8?q?=E8=B4=A6=2086=20=E4=B8=A4=E4=B8=AA=E5=85=B1=E4=BA=AB=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=96=87=E4=BB=B6=E7=95=99=E5=9C=A8=E4=B8=BB=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E5=8C=BA=E9=9A=8F=E6=94=B6=E5=8F=A3=E6=89=B9=E6=94=B6?= =?UTF-8?q?=E7=BC=96=EF=BC=88=E5=B9=B6=E8=A1=8C=E4=BC=9A=E8=AF=9D=E5=9C=A8?= =?UTF-8?q?=E9=A3=9E=20hunk=20=E6=B7=B7=E8=BD=BD=EF=BC=8C=E4=B8=8D?= =?UTF-8?q?=E5=85=A5=E6=9C=AC=E5=88=86=E6=94=AF=E2=80=94=E2=80=94registry?= =?UTF-8?q?=20=E5=9B=9E=E6=89=A7=E4=B8=8E=E6=9C=AC=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=B8=BA=E5=88=86=E6=94=AF=E4=BE=A7=E7=99=BB=E8=AE=B0=E4=BA=8B?= =?UTF-8?q?=E5=AE=9E=E6=BA=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/gdd/systems/冒险循环/难度曲线与Boss.md | 4 +- design/registry/entities.yaml | 10 +- .../audit-clear-dominance-2026-09-19.md | 163 +++++++++++++ .../smoke/board_stat_probe.gd | 57 +++++ .../smoke/board_stat_probe.gd.uid | 1 + tools/analyze_playtest.py | 43 +++- tools/clear_dominance_audit.py | 215 ++++++++++++++++++ 7 files changed, 486 insertions(+), 7 deletions(-) create mode 100644 design/research/audit-clear-dominance-2026-09-19.md create mode 100644 prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd create mode 100644 prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd.uid create mode 100644 tools/clear_dominance_audit.py diff --git a/design/gdd/systems/冒险循环/难度曲线与Boss.md b/design/gdd/systems/冒险循环/难度曲线与Boss.md index 5d9781a1..192c2f6f 100644 --- a/design/gdd/systems/冒险循环/难度曲线与Boss.md +++ b/design/gdd/systems/冒险循环/难度曲线与Boss.md @@ -158,7 +158,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板 | 护甲类型 ↔ 克制矩阵 | [战斗结算](../战斗循环/战斗结算.md) | 敌种护甲变更须复算击杀区间(2026-09-19 充能退役——原"充能投桶与量"联动半边废止) | | 护甲等级 ↔ 攻击基线 ↔ 区间带宽 | [战斗结算](../战斗循环/战斗结算.md) | 敌种与主角的护甲等级行值变更须复算生存链区间(掷点带宽随折扣档位与攻击基线同向放大);掷点形式与档位已定稿(d20 三档——档位读 `settlement.tres`;nat20 暴击形式留档,倍率同表),护甲等级行值变更仍须复算生存链区间并同步 registry——现行行值读 `hero.tres` / `enemy.tres` 的 armor_class 列(均暂定),敌方正式行值随怪物设定批投值、与加难杠杆扫描合并调 | -五条经济契约的对账由[战斗结算](../战斗循环/战斗结算.md)闭合验收,其中挖掘风险不等式与清图支配性两条的现行验算已破线或存在缺口(现状见其「待办」),重跑义务落在本系统的下一次调参批执行——这是本系统当前最优先的调参义务。完美排雷乘数的调参权在本系统。 +五条经济契约的对账由[战斗结算](../战斗循环/战斗结算.md)闭合验收,其中挖掘风险不等式现行验算破线(现状见其「待办」);清图支配性已于 2026-09-19 按现行值链重跑、裁决②"非支配设计态"维持(回执见 design/research/audit-clear-dominance-2026-09-19.md)——两型的重跑义务都落在本系统的下一次调参批随批执行,这是本系统当前最优先的调参义务。完美排雷乘数的调参权在本系统。 元进度接口预留:**结论——元进度解锁对难度的影响,以生存链区间的平移换算率接入;接口启用形态已定稿(2026-09-18 元进度定稿批,用户拍板):永久强化影响折算为通关率带平移量,判读口径不变;换算率表首版三行(生命上限 / 基础攻击 / 护甲等级——护甲行强条目,验收读数须按解锁后参数重测)与键结构登记见 registry `meta_progression_conversion_table`,数值行读 `data/tables/`、标定随元进度设计批。** 元进度数值行落地前,本系统不为它预留任何数值行。 @@ -194,7 +194,7 @@ Boss 战的棋盘用本关最大板形(板形行值读棋盘参数表),板 | 优先级 | 内容 | 后置原因 | |---|---|---| | P1 | 加难杠杆扫描落带 | 候选杠杆已登记(血量锚走廊、群战上探、注入衰减上调候选),扫描未执行;护甲等级换装点锚定(基准护甲等级自带敌方输出期望的结构性削减 + 减伤墙退役 + 伤害下限)的方向性偏移并入本扫描一并调带(带宽补扫含暴击档与折扣档);落带前现行行值维持 provisional-pending-scan。第二关行集随分支节点图批落地后并入本扫描(L2 读数基线/加成档已随批实测,见 v0.7) | -| P1 | 挖掘风险不等式与清图支配性对账重跑 | 两条对账现行破线 / 缺口,义务落在本文调参批(现状见[战斗结算](../战斗循环/战斗结算.md)「待办」) | +| P1 | 挖掘风险不等式与清图支配性对账重跑 | 两条对账:清图支配性已于 2026-09-19 按现行值链重跑(裁决②"非支配设计态"维持——缺口收窄主读数 L1≈24/L2≈45 当量〔u=1〕,设计权威 design/research/audit-clear-dominance-2026-09-19.md,重跑入口 tools/clear_dominance_audit.py);调参批执行时按当期行值随批重跑。挖掘风险不等式现行破线,义务仍落本文调参批(现状见[战斗结算](../战斗循环/战斗结算.md)「待办」) | | P1 | 真人通关率修正系数标定 | 带按模拟口径定义;试玩批次实测真人显著强于模拟者,系数待后续试玩批次定量 | | P1 | 完美策略档的结构性加难杠杆 | 数值杠杆对完美档已被实测证伪,结构候选未裁决(见「待办」) | | P2 | 精英节点完整语义与修饰乘数表首行 | 随[关卡节点地图](关卡节点地图.md)定稿联动;首个使用场景 = 精英节点 | diff --git a/design/registry/entities.yaml b/design/registry/entities.yaml index 0b5f2109..0dc7776d 100644 --- a/design/registry/entities.yaml +++ b/design/registry/entities.yaml @@ -378,7 +378,8 @@ entities: first_pass: **条款⑤未闭合(2026-09-10 模型修订重推——旧"两态通过"读数作废)**:L1 −5.3 / L2 −10.1(完美双份 +2.7/−2.1);满配语境 unit_count=3 深度为负(−49.6/−97.5,与 clause3_supply 破线同向联动);实现率折减口径(E_dig×0.6)更差(−18.5/−39.5);保守地板需求 L1 ≥ 46.1 / L2 ≥ 91.8(vs C=8/完美 16——缺口 −38.1/−75.8)。**难度曲线与Boss/地图战斗资源 约束包**:① C 量级上调整向(护栏 B 口径联动复核)② 或裁"清图非严格支配"为设计态(如裁设计态须同步声明 行动经济 条款⑤ P1 对冲弱化 + 地图战斗资源 预警加权监控)——①②二选一归 难度曲线与Boss 裁;③ 多敌放行判据 = 条款③⑤在全部登记行组合下同时成立。判据函数角色 = 调参约束生成器(AC-40 断言输出与约束包一致) c3_ruling: **约束包②采信(非支配设计态)+ 计价基元换位重推(2026-09-14 难度曲线与Boss 修订批)**——clear_default 槽由 clear_knife(入库刀 C=8/完美 16)换位为 clear_blast(instant_aoe 当场兑付全体存活敌,**2026-09-17 数值压缩批后 C = power_min/power_max 区间 [8,18]、中点 13**):保守地板需求缺口重推 = 46.1−13 = 33.0(L1)/ 91.8−13 = 78.8(L2)(**压缩批前后读数对比——原 6.1/51.8 系 C=40 口径、压缩批后按新区间中点 13 重推**);C 量级不上调 ✓;P1 对冲弱化同步声明(② 条件)+ 弃图率加权监控随 OQ4 持续;本条 first_pass 旧读数(C=8/16 口径)留作模型演进记录;**区间批义务(2026-09-14 登记 + 2026-09-17 压缩批修订)**:C 语义改区间〔压缩批前 [25,55] 中点 40 / 压缩批后 [8,18] 中点 13——期望口径按压缩批后中点 13 读〕;保守地板口径(min=8)缺口重推 = 38.1/83.8——战斗结算 修订批对齐条款⑤措辞。**重算回执(2026-09-14 战斗结算 重算批——v3 曲线 d0.25/t0.88 × E_dig=4.5 重推,参考板形换锚 难度曲线与Boss MVP 行值总表)**:主判式 L1 −28.7/+11.3(完美翻正)、L2 −67.4/−27.4、满配 −153.2/−113.2 与 −257.1/−217.1;保守地板需求 L1 ≥ 110.3 / L2 ≥ 166.8(缺口 70.3/126.8,对 clear_blast——**2026-09-17 压缩批后按 C=13 重推为 ≥ 56.1 / ≥ 112.6,缺口按新中点重核**);上段 46.1/91.8 需求系 v1 曲线旧值链产物退役;**难度曲线与Boss 裁决②非支配设计态维持**(qualitative 结构不变——非完美态负、完美态 L1 翻正、L2 全负);护栏 A 方向性复核 ≈−1.1 越下界(E_dig 修正)/ 护栏 B C=40 越线——W2 复核三选一裁决随 难度曲线与Boss 收口批;actuals 交付后按 clear_blast 语义强制重跑(战斗结算 AC-40 同批口径) guardrails: 护栏 B 防钓鱼(**2026-09-10 输入登记更正 + 双读数**:|S|_min = 棋盘生成 行级 knob 禁写死;|R₀|_max 无登记供给方——登记 棋盘生成 产出义务〔R₀ 规模分布上界,报告 C 扩列〕;s_ref=D_ref=12 比真实敌方 DPS 期望松 2.5–3×→ D_ref 口径上界 24〔C_eff=16 ✓〕/ DPS 严格读数 ≈8〔C_eff=16 越〕——两读数裁决归 难度曲线与Boss,与约束包①联动;结构承载 = 棋盘生成 min_safe_count + 布雷数下限 + 排雷玩法 R₀≠S 三闸的对账复核,非运行期校验) - rerun_obligation: actuals p10 交付后强制重跑(战斗结算 AC-40);难度曲线与Boss 每次调参重跑(D_ref/P_pf/C 联动) + rerun_2026_09_19: **对账重跑回执(用户指令提前执行 06 待办「清图支配性保守地板缺口」的对账义务——设计权威 design/research/audit-clear-dominance-2026-09-19.md,重算器 tools/clear_dominance_audit.py〔判式全参数可配=调参批常设重跑入口〕)**:①现行值链重推(D_ref 4 / C [8,18] 中点 13 / AP_r 6 / 伏击 1 / 七型 67 权重池重推 E_dig=(54+39u)÷67 ≈1.388〔u=1〕)——**定性结构不变,裁决②维持**:非完美态 18 语境全负(L1 前段实测 −4.7 ~ L2 名义 −44.3),完美态 L1 前段实测板形翻正 +8.3(名义 −9.8)、12×12 全负;②**V_mine 双口径登记**——注册公式 V_mine=u×m_amb 成文于"所有雷→固定伏击"旧世界,极性矩阵批后踩雷惩罚按格型路由(伏击仅 blast 型负向),新增口径乙 = 负向字典 67 权重加权 (42+50.4u)÷67 ≈1.379〔u=1,主读数〕,口径甲留作旧账连续对比;③**板形双口径**——"先布后删"使实测幸存雷(10×10 ≈12.9 / 12×12 ≈22.4,board_stat_probe.gd 200 样本)远低于名义初布(23/34),E[踩雷] 近乎减半;④**保守地板缺口主读数收窄**——L1 前段 ≈24.2 / L2 ≈44.9(u=1·对 C_min=8;完美双份对照 16.2/36.9),较压缩批注记 38.1/83.8 显著收窄;⑤**护栏 B 连带越线披露(2026-09-17 压缩批未登记面)**——D_ref=4 后防钓鱼上界 ⌈(|S|min−|R₀|max)/AP_r⌉×D_ref÷2 = 10〔|S|min=50〕/14〔60〕,C=13 越 1.3×、完美 26 越 1.9–2.6×——三选一(上界改判/接受+强化监控/回调 C)归 难度曲线与Boss 调参批;⑥模拟实证同向(双画像配对 1200 局:刷新流通关率全面 ≥ 推到底流,L1 基线档 87% vs 73%;实测盲挖踩雷 0.30–0.87/局 远低于判式保守计价 E[踩雷]≈12–21/板——保守地板系构造性上界;刷新策略实测 0.03–0.23 次/局几乎不发生);06 待办条目随本回执销项(解决即移除),常设重跑义务以本条 rerun_obligation 为准 + rerun_obligation: actuals p10 交付后强制重跑(战斗结算 AC-40);难度曲线与Boss 每次调参重跑(D_ref/P_pf/C 联动——重跑入口 tools/clear_dominance_audit.py + 实测板形 smoke/board_stat_probe.gd 重取样) referenced_by: [难度曲线与Boss, 地图战斗资源, 棋盘生成] # 占位表中的原型参考值(伏击 +3、清图 +10、敌 18HP/4ATK 等)为 provisional, @@ -791,3 +792,10 @@ entities: # web_snare 蛛网束缚新行(debuff→off_guard,duration 2 = 1 有效拍,冷却 4,池权重 2 → 卓尔池 6/2/2/2); # 实装面 = 仅 L2 Boss 卓尔,其余敌种不动(用户拍板); # ④ 冒烟 306 项 0 失败 + 四探针 PASS;L2 Boss 行为变更并入验收读数重测批变量清单(07 头注)。 +# 2026-09-19 清图支配性对账重跑批(用户指令提前执行 06 待办对账义务——只读对账零数值改动;与 +# 06-待办清单 / 难度曲线与Boss / design/research 新报告 / 切片工具面同批): +# ① clause5_dominance 增 rerun_2026_09_19 回执(现行值链重推:非完美态全负·完美态 L1 前段实测翻正 +8.3—— +# 裁决②维持;V_mine 双口径〔甲=注册公式 u×m_amb / 乙=极性矩阵加权主读数〕+ 板形双口径〔名义/实测〕登记; +# 保守地板缺口收窄 L1≈24/L2≈45〔u=1〕;护栏 B 连带越线披露归调参批三选一); +# ② 重算入口 tools/clear_dominance_audit.py + 实测板形探针 smoke/board_stat_probe.gd 入 rerun_obligation; +# ③ 06 清单「清图支配性保守地板缺口」条目随回执销项(解决即移除——常设重跑义务留本条目)。 diff --git a/design/research/audit-clear-dominance-2026-09-19.md b/design/research/audit-clear-dominance-2026-09-19.md new file mode 100644 index 00000000..71c3b2a5 --- /dev/null +++ b/design/research/audit-clear-dominance-2026-09-19.md @@ -0,0 +1,163 @@ +# 清图支配性保守地板缺口——对账重跑报告 + +**日期**:2026-09-19 +**性质**:只读对账作业——履行 06 待办「清图支配性保守地板缺口」的对账义务(用户指令:从难度曲线调参批提前执行)。本报告不动任何数值;调参建议仅呈报,拍板归用户。 +**判式权威**:[registry entities.yaml `clause5_dominance`](../registry/entities.yaml)(挖穿残余池计价,模型本体不变) +**配套工具**:`tools/clear_dominance_audit.py`(重算器,判式全参数可配——难度曲线调参批的常设重跑入口)+ `prototypes/.../smoke/board_stat_probe.gd`(实测板形统计探针) +**归属**:[难度曲线与Boss](../gdd/systems/冒险循环/难度曲线与Boss.md)(裁决方)× [地图战斗资源](../gdd/systems/战斗循环/地图战斗资源.md)(清图奖励供给方)× [行动经济](../gdd/systems/排雷循环/行动经济.md)(契约本体)× [战斗结算](../gdd/systems/战斗循环/战斗结算.md)(对账责任方) + +--- + +## 结论速览 + +1. **定性结构未变,裁决②「清图非严格支配 = 设计态」维持成立**:非完美清图的期望收益在全部登记板形语境下仍为负;完美清图在 L1 前段实测板形下翻正(+8.3 当量),其余仍为负——与 2026-09-14 重算批「非完美态负、完美态窄板形翻正」的结构完全同向。 +2. **缺口比旧账面显著收窄**:两个此前未计入的现行事实让清图侧变好——「先布后删」使实测幸存雷均值(10×10≈12.9 / 12×12≈22.4)远低于名义初布(23/34),E[踩雷]近乎减半;D_ref 12→4 压低了轮数代价腿。L2 单敌语境的保守地板缺口从旧值链约 79~113 当量收窄至 **44.9 当量**(对 C_min=8)/ 36.9(对完美双份 26)。 +3. **连带发现——护栏 B(防钓鱼上界)被现行清图奖励常态越线**:D_ref 压到 4 后上界降到 10(|S|min=50 口径),C=13 越 1.3×、完美双份 26 越 2.6×。这是 2026-09-17 压缩批的未登记连带面,归难度曲线调参批三选一裁决(上界改判 / 接受+强化监控 / 回调 C),本批不处理。 +4. **模拟实证与解析同向**:双画像配对批(两关 × 30 种子 × 10 天赋档 × 双策略,共 1200 局)显示刷新策略通关率全面不低于推到底策略(L1 基线档 87% vs 73%),且刷新策略实测极少被触发(0.03~0.23 次/局)、零踩雷——「弃图刷新」是理性占优策略但现行画像几乎用不上它,清图玩法被淘汰的风险在模拟面不成立。 + +--- + +## 1. 现行值链快照(2026-09-19) + +| 参数 | 现行值 | 出处 | 与 2026-09-14 重算批的差异 | +|---|---|---|---| +| D_ref(s_ref,当量参考敞口) | 4 | `settlement.tres` equivalence_ref_damage | 12→4(压缩批) | +| 清图奖励 C | [8,18],期望口径中点 13 | `reward.tres` clear_blast | [25,55] 中点 40 → ÷3 后 [8,18] 中点 13 | +| 完美乘数 P_perfect | 200(×2 双份交付) | `settlement.tres` p_perfect | 不变 | +| 轮行动点 AP_r | 6 | `action_economy.tres` ap_per_round | 8→6(压速批) | +| 挖掘标准价 / 刷新门槛 | 1 / 6(满停一轮=恰好一刷) | `action_economy.tres` | 刷新 4→6 | +| 伏击 magnitude | 1 flat/层(ambush_double 每雷 +2 层) | `status_effects.tres` ambush / `reward.tres` | 3→1(压缩批) | +| ι(可推理率代理) | 0.88 | `board_gen.tres` inferability_target | 不变 | +| 格子池 | 七型 67 权重(attack 14 / defense 11 / blast 16 / heal 2 / weaken 8 / pierce 8 / magic 8) | `reward.tres` | 四型扩七型、权重重排 | +| 停手侧 RAP 机会收益 | 零计价(registry 显式假设沿用) | registry clause5_dominance | 不变 | + +**板形双口径**(判式输入 |M| / |S|): + +| 板形 | 名义初布(旧参考板形口径) | 实测幸存(`board_stat_probe.gd` 200 样本/行,"先布后删"落地值) | +|---|---|---| +| L1 前段 10×10(D0-1) | \|M\|=23,\|S\|=77 | \|M\|=12.91,\|S\|=87.09 | +| L1 后段 12×12(D2-4)/ L2 12×12 | \|M\|=34,\|S\|=110 | \|M\|=22.61 / 22.39,\|S\|=121.39 / 121.61 | + +## 2. 模型口径说明(两处现行化 + E_dig 重推) + +判式本体、域守卫、RAP 零价假设全部沿用 registry 条目不动。两处输入口径随机制演化更新,均为**事实登记而非模型改形**: + +**① 单雷代价 V_mine 双口径。** 注册公式 V_mine = unit_count × m_amb 成文于「所有雷→固定伏击」的旧世界;极性矩阵批(2026-09-15 v0.4)后踩雷惩罚 = 该格资源类型的负向兑付(七型各一行),伏击只是 blast 型的负向。故: + +- **口径甲(注册模型连续口径)**:V_mine = u × m_amb,m_amb = 伏击行 magnitude = 1 → V_mine = 1/2/3(u=1/2/3)。用于与旧账连续对比。 +- **口径乙(现行矩阵加权口径,主读数)**:V_mine = 负向字典按 67 权重池加权 = (42 + 50.4u) ÷ 67 → 1.379 / 2.131 / 2.884。其中 hero 侧固定腿(反噬 1、乏力 1、穿刺陷阱 2、魔法反噬 2)不随 u 缩放,enemy 侧 side-wide 腿(暴走 1.0u、失衡 0.4u、伏击 +2 层 2.0u)随 u 缩放。 + +**② 板形双口径。** 旧验算用名义初布值;现行生成器有「先布后删」段(出生区外扩环删雷),实测幸存雷显著更低。实测口径为主读数,名义口径留作与旧账连续对比。 + +**③ E_dig(单安全格期望收益)按现行七型池重推**,换算严格走战斗结算效果档位对照表单一口径: + +| 类型(权重) | 正向兑付 | 当量算式 | E(u=1) | +|---|---|---|---| +| attack(14) | 增伤 +50% ×1 拍 | 0.50 × D_ref | 2.00 | +| defense(11) | 护甲强化 +1 AC ×1 拍 | 1 × 5pp × D_ref | 0.20 | +| blast(16) | 爆裂粉尘 1 点 × 存活敌数 | 1 × u | 1.00 | +| heal(2) | 急救敷料 1 点 | 表值 | 1.00 | +| weaken(8) | 削弱 −65%(有效拍 1) | 0.65 × D_ref × u | 2.60 | +| pierce(8) | 穿刺弹 2 点(轻甲 −1,地板 1) | max(1, 2−1) | 1.00 | +| magic(8) | 魔法矢 2 点(轻甲 ±0) | 2 | 2.00 | + +→ **E_dig(u) = (54 + 39u) ÷ 67**:u=1 → **1.388**;u=2 → 1.970;u=3 → 2.552。 + +**假设登记**(敏感性腿见 §6):(a) percent 类按对照表「每结算每层 × D_ref」字面折算,AC 轴按 d20 线性 5pp/点一阶近似(tier 折扣非线性不计);(b) 敌方侧 side-wide 效果按 u 个敌拍计、hero 侧单拍不随 u 缩放;(c) 克制矩阵按轻甲基础口径(Boss 战魔法甲差异登记为已知偏差源);(d) 池 clamp 相互作用与增益满层未生效折损未建模;(e) 伏击 cap=16 的动态层叠未建模;(f) RAP 零价假设沿用(对「推到底」偏利一分)。 + +## 3. 主判式验算(口径乙 · 主读数,C=13) + +判式:Δ_clear = [R_res + C_eff] − [X_res + Δr × s_ref],≥0 为闭合;完美态 C_eff = 13×2 = 26。 + +| 板形 | u | n_s | E[踩雷] | R_res | X_res | Δr(代价) | Δ_clear 非完美 | Δ_clear 完美 | 判定 | +|---|---|---|---|---|---|---|---|---|---| +| L1前段·名义 | 1 | 9.24 | 20.75 | 12.8 | 28.6 | 5(20) | **−22.8** | −9.8 | ✗ | +| L1后段·名义 | 1 | 13.20 | 31.61 | 18.3 | 43.6 | 8(32) | **−44.3** | −31.3 | ✗ | +| L2·名义 | 1 | 13.20 | 31.61 | 18.3 | 43.6 | 8(32) | **−44.3** | −31.3 | ✗ | +| L1前段·实测 | 1 | 10.45 | 11.78 | 14.5 | 16.2 | 4(16) | **−4.7** | **+8.3** | 完美✓ | +| L1后段·实测 | 1 | 14.57 | 21.16 | 20.2 | 29.2 | 6(24) | **−20.0** | −7.0 | ✗ | +| L2·实测 | 1 | 14.59 | 20.95 | 20.3 | 28.9 | 6(24) | **−19.6** | −6.6 | ✗ | +| L2·实测 | 2 | 14.59 | 20.95 | 28.8 | 44.7 | 6(24) | −26.9 | −13.9 | ✗ | +| L2·实测 | 3 | 14.59 | 20.95 | 37.2 | 60.4 | 6(24) | −34.2 | −21.2 | ✗ | + +口径甲(注册公式字面,V_mine=u×1)对照要点:结构完全一致,数值整体偏正一档——L1 前段实测非完美 −0.3(近闭合)、完美 +12.7;12×12 实测完美 u=1 微正(+1.1/+1.3);名义与 u≥2 全负。完整表可用 `python tools/clear_dominance_audit.py` 复现(含 u=2/3 全行)。 + +**结构性读法**: +- **非完美态(推到底含盲挖)在全部 18 个登记语境下为负**——保守地板口径下"推到底清图不吃亏"不成立,缺口真实存在。 +- **完美态在 L1 前段实测板形翻正**(口径乙 +8.3 / 口径甲 +12.7)——单敌小板上"完美清图已经是正收益";名义板形下仍负,说明翻正依赖"先布后删"降低雷密度的现行事实。 +- **多敌语境(u≥2)单调恶化**——与挖掘风险不等式的满配破线同向,同属难度曲线调参批的联动禁区。 + +## 4. 保守地板缺口(本待办的登记对象) + +保守地板式 C_eff(min) ≥ X_res + Δr × s_ref(对 C_min=8 计价,完美双份 26 对照): + +| 板形 | u | 地板需求 | 缺口(对 min=8) | 缺口(对完美=26) | +|---|---|---|---|---| +| L1前段·实测 | 1 | 32.2 | **+24.2** | **+16.2** | +| L2·实测 | 1 | 52.9 | **+44.9** | **+36.9** | +| L2·实测 | 3 | 84.4 | +76.4 | +68.4 | +| L2·名义 | 1 | 75.6 | +67.6 | +59.6 | + +(全表见工具输出。)**结论**:保守地板当量缺口现行主读数 **L1 前段 ≈ 24 / L2 ≈ 45**(单敌语境)——较 2026-09-17 压缩批注记的 38.1/83.8(名义·口径甲旧值链混合口径)显著收窄,主因是实测板形 E[踩雷] 近乎减半。 + +## 5. 与 2026-09-14 重算批读数对比 + +| 读数(u=1) | 2026-09-14(旧值链·名义) | 2026-09-19(现行·名义·口径乙) | 2026-09-19(现行·实测·口径乙) | +|---|---|---|---| +| L1 主判式 非完美 / 完美 | −28.7 / +11.3 | −22.8 / −9.8 | −4.7 / **+8.3** | +| L2 主判式 非完美 / 完美 | −67.4 / −27.4 | −44.3 / −31.3 | −19.6 / −6.6 | +| 保守地板需求 L1 / L2 | 110.3 / 166.8(对 C=40 时代) | 48.6 / 75.6 | 32.2 / 52.9 | + +**漂移归因**(三腿):① C 40→13 使完美态收益腿减半(L1 完美翻正腿被吞是本次唯一恶化方向);② D_ref 12→4 与 AP 8→6 使轮数代价腿大降(L2 代价腿 72→32);③ 实测板形使 X_res 近乎减半。三者合力,缺口总量收窄、结构不变。 + +## 6. 敏感性带 + +| 变体 | L1前段·实测 u=1(非完美/完美) | L2·实测 u=1(非完美/完美) | +|---|---|---| +| 主读数(口径乙) | −4.7 / +8.3 | −19.6 / −6.6 | +| 口径甲(V_mine=u×1) | −0.3 / +12.7 | −11.7 / +1.3 | +| E_dig 实现率折减 ×0.6(legacy 口径) | 更负约 −1.6 ~ −4.5 | 同向更负 | +| 口径甲 m_amb=2(伏击双层口径) | −12.1 / +0.9 | −32.7 / −19.7 | + +**唯一在任何敏感性变体下都不翻正的结论**:非完美态全负;L2 完美态除口径甲 u=1 微正(+1.3)外全负。L1 前段完美态在全部变体下为正。 + +## 7. 模拟实证(双画像配对批 2026-09-19) + +**设计**:现有两套自动玩家画像恰好是判式两侧的策略载体——普通画像(新手级推理+盲挖边界兜底+不刷新)≈「推到底清图」;完美画像(零盲挖+全标旗+卡死刷新)≈「确定格挖完就弃图刷新」。`level_monte_carlo.gd` 两关各 30 种子 × 10 天赋档 × 双画像 = 1200 局,同种子同档配对。 + +**基线档(atk+0%/hp+0%)配对读数**: + +| 读数 | L1 普通画像(推到底) | L1 完美画像(刷新流) | L2 普通画像 | L2 完美画像 | +|---|---|---|---|---| +| 通关率 | 73% | **87%** | 83% | **87%** | +| 整关承伤均 | 17.2 | 17.9 | 15.6 | 15.7 | +| 踩雷/局 | 0.87 | **0**(构造保证) | 0.30 | **0** | +| 弃图刷新/局(弃图率) | 0(0%) | 0.23(4%) | 0(0%) | 0.03(1%) | +| 轮出口分布(清图换板/停手/耗尽) | 1% / 0% / 99% | 1% / 2% / 97% | 0% / 0% / 99% | 0% / 2% / 98% | +| 平均轮数 | 16.1 | 16.4 | 11.9 | 12.2 | + +(天赋轴全表:完美画像通关率在全部 20 个档位组合上 ≥ 普通画像,无一处反超;承伤两画像几乎持平。) + +**实证判读**: +1. **刷新策略占优方向与解析一致**——同种子配对下刷新流通关率全面不低于推到底流(L1 基线档 +14pp 最显著),与「非完美清图被刷新策略支配」的解析结论同向。 +2. **实测踩雷代价远低于判式保守计价**——普通画像盲挖边界格踩雷 0.87/0.30 次/局,而判式「挖穿残余池」计价 E[踩雷]=11.8~21/板:模型按均匀交错全池盲挖定价,真实盲挖只发生在信息边缘。保守地板的"保守"名副其实,实际缺口比账面更小。 +3. **刷新策略在模拟里几乎不发生**(0.03~0.23 次/局,弃图率 1~4%)——刷新门槛 6 = 满停一轮才攒够一刷,且卡死场景本身稀少;轮出口 97~99% 是行动点耗尽、清图换板仅 0~3%。「清图玩法被刷新策略淘汰」的风险在模拟面不成立;真人侧刷新率读数挂 07 清单⑧随真人试玩批次采集。 + +**样本注记**:基线档通关率(L1 73%/87%、L2 83%/87%)与台账既有读数(L1 65%/85%、L2 80%/90%,20 种子)的差异有相当部分来自种子样本 20→30 扩样,非行为变更(代码零改动、同种子逐步可回放)。 + +## 8. 结论与呈报事项 + +**对账结论**:条款⑤对账义务已用现行值链履行完毕。**裁决②「清图非严格支配 = 设计态」建议维持**——定性结构(非完美负 / 完美窄板形翻正 / 多敌恶化)与 2026-09-14 完全同向,且缺口量级收窄、模拟面刷新策略未构成淘汰压力。清图奖励量级、刷新定价均不建议在本批调整(禁独立调参联动网络在案)。 + +**需要用户拍板的事项(本批不执行,随难度曲线调参批一并处理)**: +1. 裁决②维持是否确认(确认后本待办销项的口径即定稿); +2. 护栏 B 越线的三选一(上界改判 / 接受+强化监控 / 回调 C)——2026-09-17 压缩批的未登记连带面,本报告代为披露。 + +**重跑义务去向**:registry `clause5_dominance` 的 rerun_obligation(难度曲线与Boss 每次调参重跑)不变;下次重跑直接执行 `python tools/clear_dominance_audit.py`(按当期 .tres 更新文件头默认值即可),实测板形用 `board_stat_probe.gd` 重取样。 + +## 9. 局限登记 + +- E_dig/V_mine 的当量换算在 AC 轴与 side-wide percent 腿上是一阶近似(假设 §2③); +- 判式的「挖穿残余池」计价是构造性保守地板(均匀交错全池盲挖),实测行为代价显著更低(§7.2)——缺口读数应理解为上界而非期望; +- 模拟画像不能替代真人试玩:刷新策略在真人手里的真实吸引力(心理账「白挖一格」的沉没成本感)只有 07 清单⑧旗行为同批的真人日志能回答; +- 本报告不覆盖挖掘风险不等式(另一条破线对账,独立登记)。 diff --git a/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd b/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd new file mode 100644 index 00000000..ac146da0 --- /dev/null +++ b/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd @@ -0,0 +1,57 @@ +# VERTICAL SLICE - NOT FOR PRODUCTION +# Date: 2026-09-19 +# 棋盘板形统计探针(清图支配性对账重跑批取数工具——判式"实测板形"口径的数据源): +# 对 board_gen.tres 每行 (L, D) 生成 N 张板,统计幸存雷数 |M| 与安全格数 |S| +# 的均值 / 最小 / 最大("先布后删"后的落地值——名义值 density×(W×H−9) 不含删除段)。 +# 只读诊断,零游戏代码改动;装载面与 level_monte_carlo 同源(config_db.load_tables)。 +# 运行:Godot_console.exe --headless --path . --script res://smoke/board_stat_probe.gd -- [N] [seed0] +extends SceneTree + + +func _initialize() -> void: + var args := OS.get_cmdline_user_args() + var n := 200 + if args.size() >= 1 and args[0].is_valid_int(): + n = maxi(10, int(args[0])) + var seed0 := 9000 + if args.size() >= 2 and args[1].is_valid_int(): + seed0 = int(args[1]) + var db = load("res://core/config_db.gd").new() + if not db.load_tables("res://data/tables", false): + print("表加载失败") + quit(1) + return + var gen = load("res://core/board_generator.gd").new() + print("=== 板形统计:N=%d/行 · 种子基 %d ===" % [n, seed0]) + print("%-4s %-4s %-8s %-8s %-10s %-10s %-10s %-10s %-10s %-10s" % ["L", "D", "宽x高", "类型", "|M|均", "|M|min", "|M|max", "|S|均", "雷密度实测", "达标率"]) + for row in db.board_gen.rows: + var L: int = int(row.get("level_index", 0)) + var D: int = int(row.get("node_depth", -1)) + var w: int = int(row.get("board_width", 0)) + var h: int = int(row.get("board_height", 0)) + var btype := String(row.get("board_type", "")) + var mine_counts: Array = [] + var accepts := 0 + for i in range(n): + var rng = load("res://core/rng_service.gd").new() + rng.set_master_seed(seed0 + L * 1000 + D * 100 + i) + var stream: RandomNumberGenerator = rng.open_stream("board_gen") + var board = gen.generate(L, D, stream, db) + if board == null: + continue + mine_counts.append(board.mines.size()) + if not board.illegal_product: + accepts += 1 + if mine_counts.is_empty(): + print("%-4d %-4d 生成全败" % [L, D]) + continue + mine_counts.sort() + var total := 0 + for m in mine_counts: + total += int(m) + var mean_m := float(total) / float(mine_counts.size()) + var mean_s := float(w * h) - mean_m + print("%-4d %-4d %-8s %-8s %-10.2f %-10d %-10d %-10.2f %-10.4f %-10.3f" % [ + L, D, "%dx%d" % [w, h], btype, mean_m, int(mine_counts[0]), int(mine_counts[mine_counts.size() - 1]), + mean_s, mean_m / float(w * h), float(accepts) / float(mine_counts.size())]) + quit(0) diff --git a/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd.uid b/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd.uid new file mode 100644 index 00000000..96eeb6a7 --- /dev/null +++ b/prototypes/dungeon-sweeper-vertical-slice/smoke/board_stat_probe.gd.uid @@ -0,0 +1 @@ +uid://b4bmmnuwpld77 diff --git a/tools/analyze_playtest.py b/tools/analyze_playtest.py index 7e5caef3..8f444f38 100644 --- a/tools/analyze_playtest.py +++ b/tools/analyze_playtest.py @@ -96,8 +96,10 @@ def parse_log(path): # ---- 多局聚合模式(monte carlo 共享日志:run 行切分局次,按通关/失败分组对比) ---- -def analyze_runs(rows, label, tier=None): - """tier = (atk_pct, hp_pct):只统计该天赋档(None = 全档)。""" +def analyze_runs(rows, label, tier=None, policy=None): + """tier = (atk_pct, hp_pct):只统计该天赋档(None = 全档)。 + policy = "normal"/"perfect":只统计该策略画像(清图支配性对账批 2026-09-19—— + 双画像同文件时分开聚合做配对对照;None = 全画像混算,旧口径不变)。""" runs = [] # [{meta, rows}] cur = None for r in rows: @@ -111,6 +113,8 @@ def analyze_runs(rows, label, tier=None): runs = [run for run in runs if int(run["meta"].get("atk_pct", -999)) == tier[0] and int(run["meta"].get("hp_pct", -999)) == tier[1]] + if policy is not None: + runs = [run for run in runs if run["meta"].get("policy") == policy] stats = [] for run in runs: res = analyze_run_core(run["rows"], run["meta"]) @@ -123,7 +127,8 @@ def analyze_run_core(rows, meta): """单局聚合:返回该局的总账(结果/死亡节点/造伤/承伤/回复/奖励/轮数 + 战斗级明细)。""" out = dict(meta=meta, result="", death_node=-1, hp_left=-1, hero_dmg=0, reward_dmg=0, taken=0, healed=0, rest_heal=0, - rounds=0, rewards_n=0, eff={}, battles_won=0, battles=0, battle_list=[]) + rounds=0, rewards_n=0, eff={}, battles_won=0, battles=0, battle_list=[], + refresh_ok=0, refresh_rej=0, exits={}) eff_counts = {} cur_b = None for r in rows: @@ -196,6 +201,15 @@ def analyze_run_core(rows, meta): cur_b["taken"] += v if k == "node" and r.get("type") == "rest": out["rest_heal"] += int(r.get("healed", 0)) + # 弃图刷新与轮出口(清图支配性对账批 2026-09-19 增补读数——此前日志有行无分析) + elif k == "action" and r.get("op") == "refresh": + if r.get("accepted", False): + out["refresh_ok"] += 1 + else: + out["refresh_rej"] += 1 + elif k == "ux" and r.get("ux") == "ux_round_exit": + tag = r.get("path_tag", "?") + out["exits"][tag] = out["exits"].get(tag, 0) + 1 out["eff"] = eff_counts return out if out["rounds"] > 0 else None @@ -234,6 +248,22 @@ def print_run_report(label, stats): print(" 平均结算轮数 :%.1f" % avg(group, "rounds")) print(" 平均每局奖励件数 :%.1f(%.2f 件/轮)" % ( avg(group, "rewards_n"), avg(group, "rewards_n") / max(1.0, avg(group, "rounds")))) + # 弃图刷新面(清图支配性对账批 2026-09-19:刷新板数÷总板数 = 弃图率) + boards = sum(s["battles"] + s["refresh_ok"] for s in group) + refreshes = sum(s["refresh_ok"] for s in group) + print(" 平均每局弃图刷新 :%.2f 次(被拒 %.2f 次) 弃图率:%.0f%%" % ( + refreshes / max(1, len(group)), + sum(s["refresh_rej"] for s in group) / max(1, len(group)), + 100.0 * refreshes / max(1, boards))) + exits = {} + for s in group: + for k, v in s["exits"].items(): + exits[k] = exits.get(k, 0) + v + exit_total = sum(exits.values()) or 1 + exit_cn = {"cleared": "清图换板", "stopped": "主动停手", "ap_exhausted": "行动点耗尽"} + print(" 轮出口分布 :%s" % "、".join( + "%s %d(%.0f%%)" % (exit_cn.get(k, k), v, 100.0 * v / exit_total) + for k, v in sorted(exits.items(), key=lambda x: -x[1]))) print(" 地图战斗资源构成(件/轮) :%s" % eff_line(group)) if name.startswith("失败"): dn = {} @@ -598,12 +628,17 @@ def main(): # --tier ATK,HP:只统计该天赋档(默认 0,0 基线档——0.5 传作 50)。 if "--runs" in args: tier = (0, 0) + policy = None for i, a in enumerate(args): if a == "--tier" and i + 1 < len(args): tier = tuple(int(x) for x in args[i + 1].split(",")) elif a.startswith("--tier="): tier = tuple(int(x) for x in a.split("=")[1].split(",")) - analyze_runs(rows, os.path.basename(path), tier) + elif a == "--policy" and i + 1 < len(args): + policy = args[i + 1] + elif a.startswith("--policy="): + policy = a.split("=")[1] + analyze_runs(rows, os.path.basename(path), tier, policy) elif "--run" in args: # 抽单局(大日志里按 run 序号或种子挑一局)走三层维度报告 sel = None diff --git a/tools/clear_dominance_audit.py b/tools/clear_dominance_audit.py new file mode 100644 index 00000000..3fed0765 --- /dev/null +++ b/tools/clear_dominance_audit.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""清图支配性对账重算工具(行动经济 条款⑤ · registry clause5_dominance)。 + +判式权威 = design/registry/entities.yaml clause5_dominance(挖穿残余池计价): + 主判式 Δ_clear = [R_res + C_eff] − [X_res + Δr × s_ref] ≥ 0 + 保守地板 C_eff(min) ≥ X_res + Δr × s_ref + E[踩雷] = |M| × n_s ÷ (n_s + 1) (均匀交错模型) + n_s = (1 − ι) × |S| (域守卫 n_s < 1 ⇒ 不评估) + R_res = n_s × E_dig;X_res = E[踩雷] × V_mine;Δr = ⌈(n_s + E[踩雷]) ÷ AP_r⌉ + s_ref = D_ref;停手侧 RAP 机会收益按零计价(显式假设)。 + +本工具 2026-09-19 随对账重跑批建立,是难度曲线调参批的常设重跑入口: +所有输入可经命令行覆盖(--d-ref --c-clear --ap-r --iota --m-amb --u ...), +重跑时按当期 .tres 行值更新默认值即可,公式本体不动。 + +单雷代价 / 单格收益的当量换算严格走 战斗结算「效果档位对照表」单一口径: + flat 类 E = 表值;percent 类 E = |层数×行值|÷100 × D_ref(每结算每层); + AC 轴换算 = AC 点数 × 5pp(d20 线性)× D_ref(假设登记,见审计报告)。 +2026-09-19 起极性矩阵下踩雷惩罚按格型路由(不再固定伏击),故 V_mine 双口径: + 甲 = 注册模型连续口径 V_mine = unit_count × m_amb(m_amb = 伏击行 magnitude); + 乙 = 现行矩阵加权口径 V_mine = 负向字典按 67 权重池加权(主流读数)。 +""" + +import argparse +import math + +# ============ 现行值链(2026-09-19 快照,出处见各注释;重跑批按当期 .tres 更新) ============ + +D_REF = 4 # settlement.tres equivalence_ref_damage(2026-09-17 压缩批 12→4) +P_PERFECT = 200 # settlement.tres(percent,÷100 = ×2 双份交付) +C_MIN, C_MAX = 8, 18 # reward.tres clear_blast power_min/max;期望口径 = 中点 13 +AP_R = 6 # action_economy.tres ap_per_round(2026-09-16 压速批 8→6) +DIG_COST = 1 # action_economy.tres dig_ap_cost +IOTA = 0.88 # board_gen.tres inferability_target(判式 ι 代理) + +# 效果行值(status_effects.tres,2026-09-19 快照) +ATTACK_UP_PCT = 50 # 增伤 +50%,duration 1,hero 侧 +AC_UP_POINT = 1 # 护甲强化 +1 AC,duration 1 +WEAKEN_PCT = 65 # 削弱 −65%(有效拍 1:duration 2 先兑付后衰减) +ENRAGE_PCT = 25 # 暴走 +25%,enemy 侧 side-wide +SAPPED_PCT = 25 # 乏力 −25%,hero 侧 +AMBUSH_MAG = 1 # 伏击 +1 flat/层(2026-09-17 压缩批 3→1) +AMBUSH_STACKS = 2 # reward.tres ambush_double stacks(每雷伏击层数) +OFF_GUARD_AC = 2 # 失衡 AC −2(2026-09-18 换装) + +# 直伤/群伤 flat 值(reward.tres,2026-09-17 ÷3 后) +SPARK_AOE = 1 # 爆裂粉尘(全体存活敌) +HEAL_MINOR = 1 # 急救敷料 +HEAL_BACKLASH = 1 # 反噬震荡(主角直伤) +PIERCE_STRIKE = 2 # 穿刺弹(单目标克制直伤,必中全额) +MAGIC_BOLT = 2 # 魔法矢(同上) +PIERCE_SNARE = 2 # 穿刺陷阱(主角直伤) +MAGIC_RECOIL = 2 # 魔法反噬(主角直伤) + +# 甲效矩阵(settlement.tres,加法核点数):基础值 + 点数,damage_floor=1 +ARMOR_EFFECT = { # attack_type → {armor_type: 点数};切片 L1 全轻甲 / L2 除 Boss 全轻甲 + "pierce": {"light": -1, "ward": 1, "heavy": 0}, + "magic": {"light": 0, "ward": -1, "heavy": 1}, + "normal": {"light": 0, "ward": 1, "heavy": -1}, +} + +# 格面资源池正向权重(reward.tres,2026-09-18 伤害道具批后,合计 67) +# 类型 → (权重);负向行 weight=0 不参与摇号,类型分布 = 正向权重 +POOL_WEIGHTS = {"attack": 14, "defense": 11, "blast": 16, "heal": 2, + "weaken": 8, "pierce": 8, "magic": 8} + +# 板形(|M| 幸存雷 / |S| 安全格)双口径 +# 名义 = density×(W×H−9) 初布值(2026-09-14 重算批参考板形口径,连续性参照) +# 实测 = smoke/board_stat_probe.gd 200 样本/行均值("先布后删"落地值,主流读数) +BOARDS = { + "L1前段·名义(10x10)": {"M": 23, "S": 77}, + "L1后段·名义(12x12)": {"M": 34, "S": 110}, + "L2·名义(12x12)": {"M": 34, "S": 110}, + "L1前段·实测(10x10)": {"M": 12.91, "S": 87.09}, + "L1后段·实测(12x12)": {"M": 22.61, "S": 121.39}, + "L2·实测(12x12)": {"M": 22.39, "S": 121.61}, +} + + +def e_dig(u: float, d_ref: float, aoe_per_unit: bool = True) -> float: + """单安全格期望收益(当量),格子池 67 权重加权。 + + u = 敌方单位数。hero 侧单目标效果不随 u 缩放(主角每轮出手一次); + enemy 侧 side-wide 效果(ac_up 承伤面 / spark_aoe 群伤 / weaken 全体减伤)随 u 缩放。 + """ + w = POOL_WEIGHTS + total = sum(w.values()) + attack = w["attack"] * ATTACK_UP_PCT / 100 * d_ref # 主角下一拍增伤 + ac_up = w["defense"] * AC_UP_POINT * 0.05 * d_ref * u # 每个来敌拍 −5pp 命中 + spark = w["blast"] * (SPARK_AOE * u if aoe_per_unit else SPARK_AOE) # 全体存活敌 + heal = w["heal"] * HEAL_MINOR + weaken = w["weaken"] * WEAKEN_PCT / 100 * d_ref * u # 全体敌拍 ×0.35 + pierce = w["pierce"] * max(1, PIERCE_STRIKE + ARMOR_EFFECT["pierce"]["light"]) # 轻甲口径 + magic = w["magic"] * max(1, MAGIC_BOLT + ARMOR_EFFECT["magic"]["light"]) + return (attack + ac_up + spark + heal + weaken + pierce + magic) / total + + +def v_mine_a(u: float, m_amb: float) -> float: + """口径甲:注册模型连续口径 V_mine = unit_count × m_amb(registry 公式字面执行)。""" + return u * m_amb + + +def v_mine_b(u: float, d_ref: float) -> float: + """口径乙:现行极性矩阵加权口径——踩雷兑付 = 该格类型负向行,按 67 权重池加权。 + + hero 侧固定(直伤三类 heal_backlash/snare/recoil + 乏力 sapped); + enemy 侧 side-wide(enrage 每敌拍 / off_guard 每敌拍命中上浮 / ambush_double 每敌拍 +2 flat)随 u 缩放。 + """ + w = POOL_WEIGHTS + total = sum(w.values()) + enrage = w["attack"] * ENRAGE_PCT / 100 * d_ref * u + off_guard = w["defense"] * OFF_GUARD_AC * 0.05 * d_ref * u # AC−2 → 每敌拍 +10pp 命中 + backlash = w["heal"] * HEAL_BACKLASH + ambush = w["blast"] * AMBUSH_STACKS * AMBUSH_MAG * u + sapped = w["weaken"] * SAPPED_PCT / 100 * d_ref # 主角下一拍 −25% + snare = w["pierce"] * PIERCE_SNARE + recoil = w["magic"] * MAGIC_RECOIL + return (enrage + off_guard + backlash + ambush + sapped + snare + recoil) / total + + +def audit_shape(name: str, m: float, s: float, u: float, c_clear: float, + d_ref: float, ap_r: int, iota: float, v_mine: float, + e_dig: float, dig_cost: int) -> dict: + """单板形单语境全量计算,返回判式各腿与判定。""" + n_s = (1 - iota) * s + if n_s < 1: + return {"name": name, "skip": True} + e_mine = m * n_s / (n_s + 1) + r_res = n_s * e_dig + x_res = e_mine * v_mine + dr = math.ceil((n_s + e_mine * dig_cost) / ap_r) + c_eff_normal = c_clear + c_eff_perfect = c_clear * P_PERFECT / 100 + d_normal = (r_res + c_eff_normal) - (x_res + dr * d_ref) + d_perfect = (r_res + c_eff_perfect) - (x_res + dr * d_ref) + floor_req = x_res + dr * d_ref # 保守地板需求(对 C_eff) + return { + "name": name, "skip": False, "n_s": n_s, "e_mine": e_mine, + "r_res": r_res, "x_res": x_res, "dr": dr, "dr_cost": dr * d_ref, + "floor_req": floor_req, "gap_normal": floor_req - c_eff_normal, + "gap_perfect": floor_req - c_eff_perfect, + "d_normal": d_normal, "d_perfect": d_perfect, + } + + +def main() -> None: + ap = argparse.ArgumentParser(description="清图支配性(条款⑤)对账重算") + ap.add_argument("--d-ref", type=float, default=D_REF) + ap.add_argument("--c-clear", type=float, default=None, + help="清图奖励当量 C(默认 = (C_MIN+C_MAX)/2 = 13;传 8 得保守地板口径)") + ap.add_argument("--ap-r", type=int, default=AP_R) + ap.add_argument("--iota", type=float, default=IOTA) + ap.add_argument("--m-amb", type=float, default=float(AMBUSH_MAG), + help="口径甲的伏击行 magnitude(默认 1;传 2 = ambush_double 双层口径)") + ap.add_argument("--e-dig-discount", type=float, default=1.0, + help="E_dig 实现率折减(legacy 敏感性口径传 0.6)") + args = ap.parse_args() + c_clear = args.c_clear if args.c_clear is not None else (C_MIN + C_MAX) / 2 + + print(f"现行值链快照:D_ref={args.d_ref:g} C={c_clear:g}(min {C_MIN}/max {C_MAX}) " + f"AP_r={args.ap_r} ι={args.iota} p_perfect={P_PERFECT} RAP零价假设照旧") + print(f"E_dig(67权重池加权当量): u=1 {e_dig(1, args.d_ref):.3f} · u=2 {e_dig(2, args.d_ref):.3f} · " + f"u=3 {e_dig(3, args.d_ref):.3f}(折减 ×{args.e_dig_discount:g} 后同乘)") + print(f"V_mine 口径甲(u×m_amb, m_amb={args.m_amb:g}): u=1 {v_mine_a(1, args.m_amb):.3f} · " + f"u=2 {v_mine_a(2, args.m_amb):.3f} · u=3 {v_mine_a(3, args.m_amb):.3f}") + print(f"V_mine 口径乙(极性矩阵加权): u=1 {v_mine_b(1, args.d_ref):.3f} · " + f"u=2 {v_mine_b(2, args.d_ref):.3f} · u=3 {v_mine_b(3, args.d_ref):.3f}") + print() + + for vm_label, vm_fn in [("口径甲(注册模型 V_mine=u×m_amb)", lambda u: v_mine_a(u, args.m_amb)), + ("口径乙(现行矩阵加权 V_mine)", lambda u: v_mine_b(u, args.d_ref))]: + print(f"### 主判式 · {vm_label} · C={c_clear:g}") + print("| 板形 | u | n_s | E[踩雷] | R_res | X_res | Δr(代价) | Δ_clear 非完美 | Δ_clear 完美 | 判定 |") + print("|---|---|---|---|---|---|---|---|---|---|") + for bname, b in BOARDS.items(): + for u in (1, 2, 3): + ed = e_dig(u, args.d_ref) * args.e_dig_discount + r = audit_shape(bname, b["M"], b["S"], u, c_clear, args.d_ref, + args.ap_r, args.iota, vm_fn(u), ed, DIG_COST) + if r["skip"]: + continue + verdict = "✓" if r["d_perfect"] >= 0 and r["d_normal"] >= 0 else ( + "完美✓" if r["d_perfect"] >= 0 else "✗") + print(f"| {bname} | {u} | {r['n_s']:.2f} | {r['e_mine']:.2f} | {r['r_res']:.1f} | " + f"{r['x_res']:.1f} | {r['dr']}({r['dr_cost']:.0f}) | {r['d_normal']:+.1f} | " + f"{r['d_perfect']:+.1f} | {verdict} |") + print() + + print("### 保守地板(C_eff(min)=C_MIN)需求与缺口 · 口径乙") + print("| 板形 | u | 地板需求 X_res+Δr×s_ref | 缺口(对 min) | 缺口(对完美 ×2) |") + print("|---|---|---|---|---|") + for bname, b in BOARDS.items(): + for u in (1, 3): + ed = e_dig(u, args.d_ref) * args.e_dig_discount + r = audit_shape(bname, b["M"], b["S"], u, float(C_MIN), args.d_ref, + args.ap_r, args.iota, v_mine_b(u, args.d_ref), ed, DIG_COST) + if r["skip"]: + continue + print(f"| {bname} | {u} | {r['floor_req']:.1f} | +{r['gap_normal']:.1f} | +{r['gap_perfect']:.1f} |") + print() + + # 护栏 B(防钓鱼——退化板刷清图奖励上界):⌈(|S|min − |R0|max) ÷ AP_r⌉ × s_ref ÷ 2 + # |S|min = min_safe_count 当期行集(50/60);|R0|max = 20 经验值(无登记供给方) + print("### 护栏 B 复核(防钓鱼上界,D_ref 口径)") + for s_min in (50, 60): + ub = math.ceil((s_min - 20) / args.ap_r) * args.d_ref / 2 + print(f"|S|min={s_min}: 上界 = ⌈({s_min}−20)/{args.ap_r}⌉×{args.d_ref:g}÷2 = {ub:g}" + f" → C={c_clear:g} {'✓' if c_clear <= ub else '越 %.1f×' % (c_clear / ub)}" + f" / 完美 C_eff={c_clear * P_PERFECT / 100:g} " + f"{'✓' if c_clear * P_PERFECT / 100 <= ub else '越 %.1f×' % (c_clear * P_PERFECT / 100 / ub)}") + + +if __name__ == "__main__": + main()