Merge branch 'skill-pool-rhythm-20260919'
This commit is contained in:
commit
b270a949b2
6 files changed
+249
-10
No files matched your search
@@ -0,0 +1,38 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# Date: 2026-09-19
|
||||
# 技能池节奏读数批量采集(06 待办「技能池节奏体验验证」机器半边正式读数):
|
||||
# 60 distinct seeds × 双策略 × 两关,atk/hp 零加成基线——单网格组合避免种子重复
|
||||
# (4200 系 0/484 假象教训:节奏/EV 读数须 ≥50 distinct seeds,见台账 89)。
|
||||
# 运行:Godot_console.exe --headless --path . --script res://smoke/rhythm_batch.gd -- [seeds] [seed0]
|
||||
extends SceneTree
|
||||
|
||||
func _initialize() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var n := 60
|
||||
if args.size() >= 1 and args[0].is_valid_int():
|
||||
n = int(args[0])
|
||||
var seed0 := 4400
|
||||
if args.size() >= 2 and args[1].is_valid_int():
|
||||
seed0 = int(args[1])
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
if not db.load_tables("res://data/tables", false):
|
||||
print("表加载失败")
|
||||
quit(1)
|
||||
return
|
||||
var logger = load("res://presentation/playtest_logger.gd").new()
|
||||
logger.ap_per_round = int(db.action_economy.ap_per_round)
|
||||
var log_path: String = logger.start_session(seed0)
|
||||
print("节奏批日志: %s" % log_path)
|
||||
var autoplay = load("res://smoke/level_autoplay.gd")
|
||||
var t0 := Time.get_ticks_msec()
|
||||
var total := 0
|
||||
for L in [1, 2]:
|
||||
for policy in ["normal", "perfect"]:
|
||||
for i in range(n):
|
||||
var r = autoplay.run_level(db, seed0 + i, L, 0, 0, false, logger, policy, "min")
|
||||
total += 1
|
||||
if i % 10 == 0:
|
||||
print("进度 L%d %s %d/%d" % [L, policy, i, n])
|
||||
logger.close_session()
|
||||
print("节奏批完成:%d 局,耗时 %.1f 秒\n日志: %s" % [total, (Time.get_ticks_msec() - t0) / 1000.0, log_path])
|
||||
quit(0)
|
||||
@@ -0,0 +1,72 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# Date: 2026-09-19
|
||||
# 技能池节奏探针:地精一伙 (1,1) 750 出招零突刺异常的定位——
|
||||
# ① 表侧:resolve_enemy_rowset(1,1) 的池快照内容;
|
||||
# ② 摇号侧:隔离 SkillLottery.draw 大样本份额;
|
||||
# ③ 战斗侧:真实 (1,1) 战斗逐执行行按 skill_id 计数。
|
||||
# 运行:Godot_console.exe --headless --path . --script res://smoke/skill_rhythm_probe.gd
|
||||
extends SceneTree
|
||||
|
||||
func _initialize() -> void:
|
||||
var db = load("res://core/config_db.gd").new()
|
||||
db.load_tables("res://data/tables", false)
|
||||
|
||||
# ① 表侧
|
||||
var row = db.resolve_enemy_rowset(1, 1)
|
||||
print("[1] row(1,1) display=", row.get("display_name"), " unit_count=", row.get("unit_count"),
|
||||
" pool=", row.get("pool"))
|
||||
|
||||
# ② 摇号侧隔离
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(20260919)
|
||||
var lot = load("res://core/skill_lottery.gd")
|
||||
var counter := {}
|
||||
for i in range(10000):
|
||||
var stream: RandomNumberGenerator = rng.open_scope("behavior_roll", i % 7)
|
||||
var s: String = lot.draw(row.get("pool"), stream)
|
||||
counter[s] = counter.get(s, 0) + 1
|
||||
print("[2] SkillLottery 10000 抽(scope 0-6 复用): ", counter)
|
||||
|
||||
# ③ 战斗侧(真实路径):(1,0) 对照 + (1,1) 异常组
|
||||
for depth in [0, 1]:
|
||||
var casts := {}
|
||||
var battles := 0
|
||||
for i in range(10):
|
||||
var r = _run_battle(db, 4200 + i, 1, depth, casts)
|
||||
battles += 1
|
||||
print("[3] 战斗侧 (1,%d) %d 场执行出招 skill_id 计数: " % [depth, battles], casts)
|
||||
quit(0)
|
||||
|
||||
|
||||
func _run_battle(db, seed_val: int, L: int, depth: int, casts: Dictionary) -> Dictionary:
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
rng.set_master_seed(seed_val)
|
||||
var settlement = load("res://core/battle_orchestrator.gd").new(db, rng)
|
||||
var out := {"result": ""}
|
||||
settlement.battle_finished.connect(func(payload): out.result = payload.get("result", ""))
|
||||
settlement.step_row.connect(func(row):
|
||||
if row.type == "damage" and row.source_class == "enemy_action":
|
||||
var sid: String = str(row.get("skill_id", "?"))
|
||||
casts[sid] = casts.get(sid, 0) + 1)
|
||||
if not settlement.begin_battle({"level_index": L, "node_depth": depth, "hero_hp": int(db.hero.max_hp)}):
|
||||
return out
|
||||
var AutoPlayer = load("res://smoke/auto_player.gd")
|
||||
var guard_rounds := 40
|
||||
while out.result == "" and guard_rounds > 0:
|
||||
guard_rounds -= 1
|
||||
var start_round: int = settlement.round_index
|
||||
var minesweeper = settlement.minesweeper
|
||||
var guard := 400
|
||||
while settlement.action_economy.phase == "Active" and settlement.round_index == start_round and guard > 0 and out.result == "":
|
||||
guard -= 1
|
||||
var plan = AutoPlayer.choose_dig(minesweeper)
|
||||
if plan.is_empty():
|
||||
break
|
||||
if plan.hero_cell != minesweeper.hero_pos():
|
||||
minesweeper.settle_batch([{"action": "move", "cell": plan.hero_cell}])
|
||||
if settlement.action_economy.phase != "Active" or settlement.round_index != start_round:
|
||||
break
|
||||
minesweeper.settle_batch([{"action": "dig", "cell": plan.dig_cell}])
|
||||
if settlement.action_economy.phase == "Active" and settlement.round_index == start_round and out.result == "":
|
||||
minesweeper.settle_batch([{"action": "stop"}])
|
||||
return out
|
||||
@@ -0,0 +1 @@
|
||||
uid://b5vagf2sq2suk
|
||||
Reference in new issue
Block a user