304 lines
17 KiB
Python
304 lines
17 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""清图支配性对账重算工具(行动经济 条款⑤ · 挖穿残余池计价)。
|
||
|
||
判式权威 = design/gdd/systems/排雷循环/行动经济.md 条款⑤(公式本体同时内联于本 docstring):
|
||
主判式 Δ_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 机会收益按零计价(显式假设)。
|
||
|
||
本工具是难度曲线调参的常设重跑入口:
|
||
所有输入可经命令行覆盖(--d-ref --c-clear --ap-r --iota ...),
|
||
重跑时按当期 .tres 行值更新默认值即可,公式本体不动。
|
||
|
||
单雷代价 / 单格收益的当量换算严格走 战斗结算「效果档位对照表」单一口径:
|
||
flat 类 E = 表值;percent 类 E = |层数×行值|÷100 × D_ref(每结算每层);
|
||
AC 轴换算 = AC 点数 × 5pp(d20 线性)× D_ref(假设登记,见审计报告)。
|
||
|
||
【现行判式口径】
|
||
- 池权重合计 77(含 action 6 / gp 2;clear_blast 系清图槽对象不入格池)。
|
||
- 直伤雷负向三行 6/8/8(backlash/snare/recoil);
|
||
正向 pierce_strike/magic_bolt 维持 flat 2;heal_minor 2(Package B 第 2 轮)。
|
||
- 清图槽 C_MIN/C_MAX = 24/40(中点 32);AP_r = 8。
|
||
- off_guard 走 ac 轴 −1(0.2u 模型:点数×5pp×D_ref=0.2 当量/每敌拍)。
|
||
- V_mine 为九型负向字典口径(enrage/off_guard/警觉/backlash/sapped/snare/recoil/
|
||
ap_drain/gp_lose——ap_drain 按 A6 flat 1、gp_lose 按 A5 代理 2 计)。
|
||
- β 比值带判读与逐型净期望输出:
|
||
β(u)=V_mine/E_dig ∈ [1.2, 2.5];条件一 (1−ρ̂)E_dig−ρ̂V_mine ≥ 0(下限 0,上限归 β_hi);
|
||
条件二 E[标中兑付] ≥ (1+δ)·E_dig(δ=1.25 provisional,兑付溢价形态 a)。
|
||
"""
|
||
|
||
import argparse
|
||
import math
|
||
|
||
# ============ 现行值链(出处见各注释;重跑按当期 .tres 更新) ============
|
||
|
||
D_REF = 4 # settlement.tres equivalence_ref_damage
|
||
P_PERFECT = 200 # settlement.tres(percent,÷100 = ×2 双份交付)
|
||
C_MIN, C_MAX = 24, 40 # reward.tres clear_blast power_min/max;期望口径 = 中点 32
|
||
AP_R = 8 # action_economy.tres ap_per_round
|
||
DIG_COST = 1 # action_economy.tres dig_ap_cost
|
||
IOTA = 0.88 # board_gen.tres inferability_target(判式 ι 代理)
|
||
|
||
# 效果行值(status_effects.tres)
|
||
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 侧
|
||
OFF_GUARD_AC = 1 # 失衡 AC −1(0.2u 模型:1 点 × 5pp × D_ref = 0.2 当量/每敌拍)
|
||
ALERT_EQUIV = 0.2 # 警觉(敌 AC+1×1拍):主角每拍恰 1 攻 × 1 拍寿命 ⇒ 0.2 当量,u 无关(假设 A4)
|
||
|
||
# 直伤/群伤 flat 值(reward.tres)
|
||
SPARK_AOE = 1 # 爆裂粉尘(全体存活敌)
|
||
HEAL_MINOR = 2 # 急救敷料(Package B 第 2 轮)
|
||
HEAL_BACKLASH = 6 # 反噬震荡(主角直伤)
|
||
PIERCE_STRIKE = 2 # 穿刺弹(单目标克制直伤,必中全额)
|
||
MAGIC_BOLT = 2 # 魔法矢(同上)
|
||
PIERCE_SNARE = 8 # 穿刺陷阱(主角直伤)
|
||
MAGIC_RECOIL = 8 # 魔法反噬(主角直伤)
|
||
AP_UP = 1 # 行动点 +1(当量 = flat 表值 1,机会成本口径更高仅登记——假设 A6)
|
||
GP_COIN = 3 # GP 袋 +3 GP(gp 当量 = flat power 代理——假设 A5,口径空白登记)
|
||
GP_LOSE = 2 # 破财 −2GP(同上代理)
|
||
|
||
# 甲效矩阵(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,合计 77)
|
||
# 类型 → (权重);负向行 weight=0 不参与摇号,类型分布 = 正向权重
|
||
# clear_blast pool_tag=clear_default 系清图槽对象,不入格池(地图战斗资源.md §清图槽)。
|
||
POOL_WEIGHTS = {"attack": 14, "defense": 11, "blast": 16, "heal": 4,
|
||
"weaken": 8, "pierce": 8, "magic": 8, "action": 6, "gp": 2}
|
||
|
||
# β 比值带 [1.2, 2.5](u=3 登记态 1.17 微破下限=点名不强制回滚)
|
||
BETA_LO, BETA_HI = 1.2, 2.5
|
||
# δ 旗溢价(形态 a 兑付溢价,δ=1.25 provisional ⇒ 兑付按同型正向 ×(1+δ))
|
||
DELTA = 0.25
|
||
|
||
# 板形(|M| 幸存雷 / |S| 安全格)双口径
|
||
# 名义 = density×(W×H−9) 初布值(参考板形口径,连续性参照)
|
||
# 实测 = smoke/board_stat_probe.gd 200 样本/行均值("先布后删"落地值,主流读数)
|
||
# (实测值沿用 board_stat_probe 读数;板形行值未变,不强制复跑)
|
||
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:
|
||
"""单安全格期望收益(当量),格子池 77 权重加权。
|
||
|
||
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"])
|
||
action = w["action"] * AP_UP
|
||
gp = w["gp"] * GP_COIN
|
||
return (attack + ac_up + spark + heal + weaken + pierce + magic + action + gp) / total
|
||
|
||
|
||
def v_mine(u: float, d_ref: float) -> float:
|
||
"""现行极性矩阵加权口径(九型负向字典)——踩雷兑付 = 该格类型负向行,按 77 权重池加权。
|
||
|
||
hero 侧固定(直伤三类 heal_backlash/snare/recoil + 乏力 sapped + ap_drain + gp_lose);
|
||
enemy 侧 side-wide(enrage 每敌拍 / off_guard 每敌拍命中上浮)随 u 缩放;
|
||
警觉按 0.2 当量固定(假设 A4)。
|
||
"""
|
||
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−1 → 每敌拍 +5pp 命中
|
||
alert = w["blast"] * ALERT_EQUIV
|
||
backlash = w["heal"] * HEAL_BACKLASH
|
||
sapped = w["weaken"] * SAPPED_PCT / 100 * d_ref # 主角下一拍 −25%
|
||
snare = w["pierce"] * PIERCE_SNARE
|
||
recoil = w["magic"] * MAGIC_RECOIL
|
||
ap_drain = w["action"] * AP_UP
|
||
gp_lose = w["gp"] * GP_LOSE
|
||
return (enrage + off_guard + alert + backlash + sapped + snare + recoil
|
||
+ ap_drain + gp_lose) / total
|
||
|
||
|
||
def w_flag_hit(u: float, d_ref: float, prem_pct: int = 125) -> float:
|
||
"""标中旗兑付聚合当量 W(u)——整数量级实现口径(与机制同式:各型四舍五入取整后折算)。
|
||
|
||
条件二常设判读式:条件二 = W(u) ≥ (1+δ)·E_dig(u)。
|
||
取整跟随机制(GDScript round=半分远离零),非 Python banker's rounding。
|
||
1 点量纲行(ac_up/action/spark)取整地板=×1.0——u=3 聚合微欠的成因(登记面)。
|
||
"""
|
||
w = POOL_WEIGHTS
|
||
total = sum(w.values())
|
||
|
||
def sc(x: float) -> int:
|
||
return int(math.floor(x * prem_pct / 100.0 + 0.5))
|
||
|
||
attack = w["attack"] * sc(ATTACK_UP_PCT) / 100 * d_ref
|
||
ac_up = w["defense"] * sc(AC_UP_POINT) * 0.05 * d_ref * u
|
||
spark = w["blast"] * (sc(SPARK_AOE) * u)
|
||
heal = w["heal"] * sc(HEAL_MINOR)
|
||
weaken = w["weaken"] * sc(WEAKEN_PCT) / 100 * d_ref * u
|
||
pierce = w["pierce"] * max(1, sc(PIERCE_STRIKE) + ARMOR_EFFECT["pierce"]["light"])
|
||
magic = w["magic"] * max(1, sc(MAGIC_BOLT) + ARMOR_EFFECT["magic"]["light"])
|
||
action = w["action"] * sc(AP_UP)
|
||
gp = w["gp"] * sc(GP_COIN)
|
||
return (attack + ac_up + spark + heal + weaken + pierce + magic + action + gp) / total
|
||
|
||
|
||
def per_type_table(u: float, d_ref: float) -> list:
|
||
"""逐型 P_t/N_t 明细(当量),供条件净期望计算。返回 [(型, P_t, N_t)]。"""
|
||
return [
|
||
("attack", ATTACK_UP_PCT / 100 * d_ref, ENRAGE_PCT / 100 * d_ref * u),
|
||
("defense", AC_UP_POINT * 0.05 * d_ref * u, OFF_GUARD_AC * 0.05 * d_ref * u),
|
||
("blast", float(SPARK_AOE * u), ALERT_EQUIV),
|
||
("heal", float(HEAL_MINOR), float(HEAL_BACKLASH)),
|
||
("weaken", WEAKEN_PCT / 100 * d_ref * u, SAPPED_PCT / 100 * d_ref),
|
||
("pierce", float(max(1, PIERCE_STRIKE + ARMOR_EFFECT["pierce"]["light"])), float(PIERCE_SNARE)),
|
||
("magic", float(max(1, MAGIC_BOLT + ARMOR_EFFECT["magic"]["light"])), float(MAGIC_RECOIL)),
|
||
("action", float(AP_UP), float(AP_UP)),
|
||
("gp", float(GP_COIN), float(GP_LOSE)),
|
||
]
|
||
|
||
|
||
def audit_shape(name: str, m: float, s: float, u: float, c_clear: float,
|
||
d_ref: float, ap_r: int, iota: float, v_mine_v: float,
|
||
e_dig_v: 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_v
|
||
x_res = e_mine * v_mine_v
|
||
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="清图支配性(条款⑤)对账重算 + 判式换代面板(条款3)")
|
||
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 = 32;传 24 得保守地板口径)")
|
||
ap.add_argument("--ap-r", type=int, default=AP_R)
|
||
ap.add_argument("--iota", type=float, default=IOTA)
|
||
ap.add_argument("--rho-nominal", type=float, default=0.25, help="名义雷率(判式主口径)")
|
||
ap.add_argument("--rho-measured", type=float, default=0.129, help="实测幸存雷率(10×10 包络口径)")
|
||
ap.add_argument("--delta", type=float, default=DELTA, help="旗溢价系数 δ(兑付溢价形态 a)")
|
||
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(77权重池加权当量): 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=1 {v_mine(1, args.d_ref):.3f} · "
|
||
f"u=2 {v_mine(2, args.d_ref):.3f} · u=3 {v_mine(3, args.d_ref):.3f}")
|
||
print()
|
||
print("### 条款3 判式换代面板(β 比值带 + 条件一聚合健康式 + 条件二旗溢价)")
|
||
print(f"β 带 = [{BETA_LO:g}, {BETA_HI:g}](2026-10-04 用户裁 P4) 兑付溢价 ×(1+δ) = ×{1 + args.delta:g}(形态 a)")
|
||
print("| u | E_dig | V_mine | β=V/E | 带判定 | 条件一 盲挖净期望(名义ρ) | 条件一 盲挖净期望(实测ρ̂) | 条件二 W(u) | 条件二 阈值(1+δ)E_dig | 条件二判定 |")
|
||
print("|---|---|---|---|---|---|---|---|---|---|")
|
||
for u in (1, 2, 3):
|
||
ed = e_dig(u, args.d_ref)
|
||
vm = v_mine(u, args.d_ref)
|
||
beta = vm / ed
|
||
verdict = "✓带内" if BETA_LO <= beta <= BETA_HI else (
|
||
"✗破下限(登记态)" if beta < BETA_LO else "✗破上限")
|
||
blind_nom = (1 - args.rho_nominal) * ed - args.rho_nominal * vm
|
||
blind_meas = (1 - args.rho_measured) * ed - args.rho_measured * vm
|
||
# 条件二(机制在位):W=整数量级标中兑付聚合(取整跟随机制),阈值 =(1+δ)·E_dig
|
||
wfh = w_flag_hit(u, args.d_ref, int(round((1 + args.delta) * 100)))
|
||
thresh = (1 + args.delta) * ed
|
||
cond2 = "✓转绿" if wfh >= thresh else "✗微欠(整数量级取整地板,登记面)"
|
||
print(f"| {u} | {ed:.3f} | {vm:.3f} | {beta:.2f} | {verdict} | "
|
||
f"{blind_nom:+.2f} | {blind_meas:+.2f} | {wfh:.3f} | {thresh:.3f} | {cond2} |")
|
||
print()
|
||
print("### 逐型条件净期望 (1−ρ)P_t − ρN_t(当量/格,u=1,名义 ρ 与实测 ρ̂ 双列)")
|
||
print("| 型 | P_t | N_t | 净期望(名义ρ) | 净期望(实测ρ̂) | 判(名义) |")
|
||
print("|---|---|---|---|---|---|")
|
||
for t, p, n in per_type_table(1, args.d_ref):
|
||
net = (1 - args.rho_nominal) * p - args.rho_nominal * n
|
||
net_m = (1 - args.rho_measured) * p - args.rho_measured * n
|
||
verdict = "✓" if net > 1e-9 else ("踩线" if abs(net) <= 1e-9 else "✗破线")
|
||
print(f"| {t} | {p:g} | {n:g} | {net:+.2f} | {net_m:+.2f} | {verdict} |")
|
||
for u in (2, 3):
|
||
cells = " · ".join(f"{t}({(1 - args.rho_nominal) * p - args.rho_nominal * n:+.2f})"
|
||
for t, p, n in per_type_table(u, args.d_ref))
|
||
print(f"u={u} 净期望: {cells}")
|
||
print()
|
||
|
||
print(f"### 主判式(条款⑤)· 九型矩阵加权 V_mine · 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, v_mine(u, args.d_ref), 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(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()
|