219 lines
12 KiB
Python
219 lines
12 KiB
Python
#!/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()
|