## VERTICAL SLICE - NOT FOR PRODUCTION ## 调整板批量模拟控制器:逐次驱动关卡自动策略(与 headless 扫描同口径),进度/报告经面板 setter 注入。 ## 零核心写——表基线复位由组合根在移交前完成,加成施加只走自动策略内部 runner.set_hero_override 单路径。 ## presentation 不 preload smoke:驱动实例由调用方注入(须供与 level_autoplay 同款 run_level 签名),缺省 null=运行时 load 兜底。 extends RefCounted const SEED_BASE := 4200 # 模拟种子基(与历史实现同源——同种子可回放) const PlaytestLogger := preload("res://presentation/playtest_logger.gd") # 试玩日志(同层依赖——运行时 load 收敛为 preload 常量) var db var panel # 调试浮窗 setter 面:atk_pct/hp_pct/set_sim_running/set_sim_progress/set_sim_report var _base_hp := 0 # 报告中的"基础 HP"口径注记值 var _driver = null # 关卡自动策略驱动(调用方注入;null = 旧行为运行时 load 兜底) var _running := false # 运行态(run 全程 true——组合根互查守卫用,与面板置灰解耦) func _init(db_ref, panel_ref, base_hp: int, driver = null) -> void: db = db_ref panel = panel_ref _base_hp = base_hp _driver = driver # 驱动解析:注入优先;缺省回退运行时 load(旧行为——编译期反向依赖已解除,运行时口径与拆分前逐位一致) func _autoplay() -> Variant: if _driver != null: return _driver return load("res://sim/level_autoplay.gd") # 与 headless 扫描同口径的自动策略(P3 兜底路径) # 运行态查询出口(组合根互查守卫:模拟在跑期禁开调试对局/二次模拟) func is_running() -> bool: return _running func run(n: int) -> void: _running = true # 共享日志会话(模拟运行与真人试玩同日志合规——操作/轮次/战斗/关卡完成全量 JSONL; # 一文件多局,run 行携带种子切分局次) var logger = PlaytestLogger.new() logger.ap_per_round = int(db.run.action_economy.ap_per_round) logger.start_session(SEED_BASE) panel.set_sim_running(true) panel.set_sim_progress("模拟中:0/%d …" % n) var stats := {"wins": 0, "dmg_all": [], "hp_left_win": [], "hp_boss": [], "rounds_all": [], "death_nodes": {}} var autoplay = _autoplay() for i in range(n): _run_one_level(autoplay, stats, i, panel, logger) panel.set_sim_progress("模拟中:%d/%d …" % [i + 1, n]) await panel.get_tree().process_frame logger.close_session() panel.set_sim_report(HudPresenter.tune_sim_report(n, panel.atk_pct(), panel.hp_pct(), stats, _base_hp)) ## 单局模拟域(循环体提函数——结果四桶记账;u19 stats 六键同构承载) func _run_one_level(autoplay, stats: Dictionary, i: int, panel, logger) -> void: var st = autoplay.run_level(db, SEED_BASE + i, 1, panel.atk_pct(), panel.hp_pct(), false, logger) (stats["dmg_all"] as Array).append(st.hero_dmg) (stats["rounds_all"] as Array).append(st.rounds) if st.result == "victory": stats["wins"] = int(stats["wins"]) + 1 (stats["hp_left_win"] as Array).append(st.hp_left) (stats["hp_boss"] as Array).append(st.hp_at_boss) elif st.result == "defeat": var key := "%d.%s" % [st.defeat_node_index, st.defeat_node_type] stats["death_nodes"][key] = int(stats["death_nodes"].get(key, 0)) + 1 panel.set_sim_running(false) _running = false