Files
gplan-2/tools/clear_dominance_audit.py
T
DKChan 7876642122 feat(resource): 格面资源八型批——伏击退役换装警觉+新增行动点第8型+护甲型数值对齐(2026-09-20 用户拍板)——①动机=全字典镜像对账(系统设计分析):伏击的层数×出手敌数复利集中在主角单血条、与爆裂粉尘摊 N 条敌方血条双重不对称;护甲型惩罚 −2 比奖励 +1 反向偏重;敌方护甲等级轴全系统空缺;②伏击退役=伤害公式拆除伏击附加项(敌方技能攻击=max(damage_floor, floor(掷点档位技能基础分量)×乘区)+rider)、快照 ambush_layers 字段拆除、效果行/毒爆复算断言同步;③blast 负向换装=enemy_alert 警觉(敌方全体护甲等级 +1/层,1 结算,side-wide 逐颗叠加无上限)——消费=_defender_ac 敌方侧 ac 型状态读法本批接线(防守方 AC=表值+Σac 型效果,敌方路径从纯表值扩展);④第 8 型 action=ap_up 行动点(正向,下轮 AP+1,weight 6)/ap_drain 迟滞(负向,下轮 AP−1)——action_economy 排队面 queue_ap_delta/pending_ap_delta 新增,notify_round_start 兑现(基线 6+净值,下限 0,兑现清零),明细记 effect 行;⑤护甲型对齐=off_guard −2→−1;⑥schema=八型封闭枚举十六格、伏击加层行特例校验退役、effect_pool_map 删 ambush/flat_attach 键;⑦表现层=敌卡伏击池行拆除(警觉入敌方增益投影,percent|ac 双量纲)、状态槽图标 ambush→alert;⑧文档=敌人系统 v0.12(伏击节退役改写)/战斗结算 v0.20(公式与授予段)/地图战斗资源 v0.14(八型字典)/行动经济 v0.5(下轮行动点修正节+F1 条款3 改写)/难度曲线 v0.15/增益状态 v0.8/06 清单(伏击量纲条目随批解决+调参批数值点评登记)/registry 22 处(ambush_unit_definition 退役+继任 alert、clause3_supply 伏击暴露口径作废、reward_table 八型 74 权重、行动经济排队面)/ux battle/关卡节点地图;⑨工具=analyze_playtest M_AMB 归零保旧日志兼容、clear_dominance 伏击暴露模型转历史口径注记(新口径归调参批);⑩验证=冒烟 330 项 0 失败三闸全过(新增警觉在位+action 正负抵消排队断言)+gdd_lint 与 master 基线一致(8 文件存量);遗留=警觉/行动点数值 provisional 归曲线调参批(06 已登记),真人批试玩建议在终版规则上执行
2026-09-20 03:58:15 +08:00

219 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 侧
# 【2026-09-20 八型批口径注记】伏击机制退役,blast 负向现况 = 警觉(敌方 AC +1,掷点折扣分布型惩罚)——
# 本脚本的伏击暴露当量模型(AMBUSH_MAG/AMBUSH_STACKS)转为历史口径,仅用于旧读数复算;
# 新口径(掷点折扣期望建模)归曲线调参批重立后再改模型。
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()