feat(mc): 掷点测量修复批 A 案叠加实施——level_monte_carlo 增 unique 种子模式(2026-09-19 用户拍板 A/B 叠加)——①第 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 点,归调参批裁决);压力面三批复测焊死(L1 完美档 87% R2/R3/A+B 同向同量级);③阶段一正式重跑数据=T220949/T221847,同种子历史坐标三重作废(R3+unique)可比性锚改挂本批;④gameplay 零改动(仅 MC 工具第 5 参)+报告 A 案落地节+台账 87

This commit is contained in:
DKChan committed 2026-09-19 22:52:24 +08:00
1 parent cc34f4371a
commit 129be45817
3 files changed
+42 -4

No files matched your search

@@ -3,10 +3,17 @@
# 关卡期望扫描(难度曲线与Boss 调参期关卡侧批量工具的原型——对应 棋盘生成 F4 / 战斗侧 monte_carlo.gd):
# 扫描 atk% × 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
var _run_cursor := 0 # unique 模式全局局序号(seed = seed0 + cursor)
func _initialize() -> void:
var args := OS.get_cmdline_user_args()
var n := 30
@@ -42,9 +49,14 @@ func _initialize() -> void:
policies = ["perfect"]
elif policy_arg == "both":
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 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承伤%", "踩雷/局", "刷新/局"])
var perfect_mine_total := 0 # 完美档构造保证 = 零踩雷(只挖已证安全格)——扫描末断言
for policy in policies:
@@ -65,7 +77,9 @@ func _initialize() -> void:
var mine_per_run: Array = []
var refresh_per_run: Array = []
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)
rounds_all.append(st.rounds)
mine_per_run.append(int(st.mine_hits))