test(迁移): 批 B 波 1 G3 套3 棋盘生成 22 条迁入 board_gen_reward_test.gd——剪切挂载绿(宿主累计 57 检查)+按条变异 22/22 验红零死断言候选(_ceil_key 首试 crash 形态换 depth_ceil 插入已记账;legality 判别器隔离直调与内部消费);套内独占 _board_dump/_BoardRowStub 随迁,smoke_all.gd 同批删函数两 helper
This commit is contained in:
1 parent
c84a05f5a2
commit
5dd6d8498a
3 files changed
+91
-76
No files matched your search
@@ -1654,64 +1654,6 @@ func _hero_attack_row_with(opts: Dictionary, hero_atk_val: int, seed_val: int) -
|
||||
return {}
|
||||
|
||||
|
||||
func _smoke_board_generator() -> void:
|
||||
print("--- 棋盘生成 ---")
|
||||
var board_generator = load("res://core/board_generator.gd").new()
|
||||
for L in [1, 2]:
|
||||
var row = _db.resolve_board_gen(L, 0)
|
||||
check(not row.is_empty(), "BoardGen 行解析 (%d,0)" % L)
|
||||
if L == 2:
|
||||
# R1 ceil 口径:无精确行向上取整保证偏难——L2 深度 3 为恢复点无行,解析到深度 4
|
||||
var ceil_row: Dictionary = _db.resolve_board_gen(2, 3)
|
||||
check(int(ceil_row.get("node_depth", -1)) == 4, "R1 ceil 解析 (2,3)→(2,4)(向上取整偏难)")
|
||||
var b1 = board_generator.generate(L, 0, _rng.open_stream("board_gen"), _db)
|
||||
check(b1 != null, "L%d 生成产物非空" % L)
|
||||
if b1 == null:
|
||||
continue
|
||||
check(board_generator.is_clearable(b1), "L%d clearable(安全格 8 邻连通)" % L)
|
||||
check(board_generator.legality(b1, row, _db), "L%d legality 全过" % L)
|
||||
var inf := float(b1.metrics.get("inferability", 0.0))
|
||||
var mode := String(b1.metrics.get("accept_mode", ""))
|
||||
print(" L%d 实测:inferability=%.3f / attempts_used=%d / accept_mode=%s / target=%.2f" % [
|
||||
L, inf, int(b1.metrics.get("attempts_used", -1)), mode, float(row.inferability_target)])
|
||||
# 出图验收(棋盘生成 登记口径):first_pass 必须 ≥ target;accept_best(重试耗尽接受最优)允许低于 target
|
||||
# 但必须打印实测值(正常出口);accept_worst 由下方 illegal_product 断言承担。
|
||||
check(inf >= float(row.inferability_target) or mode == "accept_best",
|
||||
"L%d inferability %.3f %s target %.2f(accept_mode=%s)" % [L, inf, "≥" if inf >= float(row.inferability_target) else "<", float(row.inferability_target), mode])
|
||||
check(b1.variants.is_empty(), "L%d 生成器产物零变体格(变异布置归战斗初始化第 4 步——生成器管线不布置,2026-09-19 用户拍板棋盘设置顺序)" % L)
|
||||
check(b1.metrics.has("degraded_product") and b1.metrics.has("target_mines"), "L%d 指标集输出降级标记与目标雷数(三分出口表)" % L)
|
||||
check(b1.degraded_product == (mode == "accept_best"), "L%d 降级产物标记 = (accept_mode==accept_best)(%s→%s)" % [L, mode, str(b1.degraded_product)])
|
||||
check(b1.illegal_product == (mode == "accept_worst"), "L%d 非法产物标记 = (accept_mode==accept_worst)(%s→%s)" % [L, mode, str(b1.illegal_product)])
|
||||
check(not b1.degraded_product or not b1.illegal_product, "L%d 降级/非法产物标记互斥(两出口不可同真)" % L)
|
||||
check(int(b1.metrics.actual_mines) <= int(b1.metrics.target_mines), "L%d 产物断言:实际雷数 %d ≤ 目标雷数 N=%d(先布后删只减不增)" % [L, int(b1.metrics.actual_mines), int(b1.metrics.target_mines)])
|
||||
check(b1.metrics.get("attempts_used", 99) >= 1 and b1.metrics.get("attempts_used", 99) <= int(row.max_gen_attempts), "L%d attempts_used ∈ [1,%d]" % [L, int(row.max_gen_attempts)])
|
||||
check(not b1.illegal_product, "L%d 非法产物标记 = false" % L)
|
||||
# 生成确定性:同种子逐格相同
|
||||
var b2 = board_generator.generate(L, 0, _mk_stream("board_gen", 777), _db)
|
||||
var b3 = board_generator.generate(L, 0, _mk_stream("board_gen", 777), _db)
|
||||
check(_board_dump(b2) == _board_dump(b3), "L%d 同种子两次生成逐格相同" % L)
|
||||
var b4 = board_generator.generate(L, 0, _mk_stream("board_gen", 778), _db)
|
||||
check(_board_dump(b2) != _board_dump(b4), "L%d 异种子产物不同(退化护栏)" % L)
|
||||
# ---- 初始展开收窄断言 ----
|
||||
# ① 结构断言:R₀ ≤ cap(正式表行投值,合法性闸承载——出图必过);② r0_cap_rejected 尝试事实在位;
|
||||
# ③ ring_removed 量级:≤ 域内候选危险格数(5×5−出生 9=16——无全域剃雷);
|
||||
# ④ 闸压线行为:cap=9(出生保障面下限)时出图必 r0≤9 或 accept_worst 非法标记(三分出口诚实降级,玩家永不卡死)
|
||||
var cap_val: int = int(row.get("r0_max_cap", 0))
|
||||
check(cap_val >= BoardData.SPAWN_AREA_CELLS, "L%d r0_max_cap 正式行投值在位(%d ≥ 出生保障面 9——板面 30%% 锚)" % [L, cap_val])
|
||||
check(int(b1.metrics.r0_count) <= cap_val, "L%d 结构断言 R₀=%d ≤ cap=%d(R₀≤cap 重掷闸承载)" % [L, int(b1.metrics.r0_count), cap_val])
|
||||
check(int(b1.metrics.get("r0_cap_rejected", -1)) >= 0, "L%d r0_cap_rejected 尝试事实指标在位(本图 %d 次触发)" % [L, int(b1.metrics.get("r0_cap_rejected", -1))])
|
||||
check(int(b1.metrics.get("ring_removed", 99)) <= (2 + int(row.get("shave_ring_radius", 1))) * (2 + int(row.get("shave_ring_radius", 1))) * 4 - 5, "L%d ring_removed=%d ≤ 剃雷域候选危险格数((3+2r)²−9——全域剃雷退役)" % [L, int(b1.metrics.get("ring_removed", 99))])
|
||||
var row9: Dictionary = row.duplicate()
|
||||
row9["r0_max_cap"] = BoardData.SPAWN_AREA_CELLS
|
||||
row9["max_gen_attempts"] = 4
|
||||
var stub9 := _BoardRowStub.new()
|
||||
stub9.row = row9
|
||||
var b9 = board_generator.generate(1, 0, _mk_stream("board_gen", 909), stub9)
|
||||
check(b9 != null and (int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS or b9.illegal_product),
|
||||
"L1 cap 压线 9:出图 R₀=%d %s(三分出口诚实降级——超阈即 accept_worst 非法标记,玩家永不卡死)" % [int(b9.metrics.r0_count), "≤9" if int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS else ">9→illegal_product"])
|
||||
check(int(b9.metrics.get("r0_cap_rejected", 0)) >= 0 and String(b9.metrics.get("accept_mode", "")) != "", "L1 cap 压线出图指标集完整(accept_mode=%s / 闸触发 %d 次)" % [String(b9.metrics.get("accept_mode", "")), int(b9.metrics.get("r0_cap_rejected", 0))])
|
||||
|
||||
|
||||
func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
|
||||
# stream_name = 调用点自述标签(不参与派生),保留参数零改调用方
|
||||
var rg := RandomNumberGenerator.new()
|
||||
@@ -1738,15 +1680,6 @@ class _CountVariantRng extends RngServiceCore:
|
||||
return super.open_stream(purpose)
|
||||
|
||||
|
||||
# 板行覆盖桩(cap 压线行为断言;接口面 = resolve_board_gen 单点)
|
||||
class _BoardRowStub:
|
||||
var row: Dictionary
|
||||
func resolve_board_gen(_L: int, _D: int) -> Dictionary:
|
||||
return row
|
||||
func status_effect_row(_id: String) -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
func _smoke_global_variant() -> void:
|
||||
print("--- 全局作用域变异(门控三维 + 全局池空兜底回落 + 资源面偏斜)---")
|
||||
# ① 跨字段互锁负样本(resource_face ⟺ scope=global 三条 + effect_value 新域 [0,50])
|
||||
@@ -1998,15 +1931,6 @@ func _variant_dump(b) -> String:
|
||||
return "|".join(parts)
|
||||
|
||||
|
||||
func _board_dump(b) -> String:
|
||||
var parts: Array = [str(b.width), str(b.height), str(b.spawn_center)]
|
||||
for y in b.height:
|
||||
for x in b.width:
|
||||
var c := Vector2i(x, y)
|
||||
parts.append("%d:%d:%d:%s" % [x, y, 1 if b.is_mine(c) else 0, str(b.variants.get(c, []))])
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
# ---- 完整战斗回放(自动玩家,确定性)——回放断言:同种子两遍步骤流逐行相同 ----
|
||||
|
||||
func _smoke_full_battle(L: int, D: int, label: String) -> void:
|
||||
|
||||
@@ -32,6 +32,7 @@ func _init() -> void:
|
||||
# 套执行序沿源编排序
|
||||
_smoke_layout_cell_formula()
|
||||
_smoke_reward_identity_unit()
|
||||
_smoke_board_generator()
|
||||
quit(Kit.finish("board_gen_reward_test"))
|
||||
|
||||
|
||||
@@ -112,3 +113,92 @@ func _smoke_reward_identity_unit() -> void:
|
||||
# 退役后受理拒绝
|
||||
reward_economy.retire_mapping()
|
||||
Kit.check("映射退役后 grant 拒绝(生命周期闭合)", reward_economy.grant(eligible[0].cell) == null)
|
||||
|
||||
|
||||
# ---- 棋盘生成(生成-验证循环 / 三分出口 / r0 闸)----
|
||||
|
||||
# 板行覆盖桩(cap 压线行为断言;接口面 = resolve_board_gen 单点)
|
||||
class _BoardRowStub:
|
||||
var row: Dictionary
|
||||
func resolve_board_gen(_L: int, _D: int) -> Dictionary:
|
||||
return row
|
||||
func status_effect_row(_id: String) -> Dictionary:
|
||||
return {}
|
||||
|
||||
|
||||
func _smoke_board_generator() -> void:
|
||||
print("--- 棋盘生成 ---")
|
||||
var board_generator = load("res://core/board_generator.gd").new()
|
||||
for L in [1, 2]:
|
||||
var row = _db.resolve_board_gen(L, 0)
|
||||
Kit.check("BoardGen 行解析 (%d,0)" % L, not row.is_empty())
|
||||
if L == 2:
|
||||
# R1 ceil 口径:无精确行向上取整保证偏难——L2 深度 3 为恢复点无行,解析到深度 4
|
||||
var ceil_row: Dictionary = _db.resolve_board_gen(2, 3)
|
||||
Kit.check("R1 ceil 解析 (2,3)→(2,4)(向上取整偏难)", int(ceil_row.get("node_depth", -1)) == 4)
|
||||
var b1 = board_generator.generate(L, 0, _rng.open_stream("board_gen"), _db)
|
||||
Kit.check("L%d 生成产物非空" % L, b1 != null)
|
||||
if b1 == null:
|
||||
continue
|
||||
Kit.check("L%d clearable(安全格 8 邻连通)" % L, board_generator.is_clearable(b1))
|
||||
Kit.check("L%d legality 全过" % L, board_generator.legality(b1, row, _db))
|
||||
var inf := float(b1.metrics.get("inferability", 0.0))
|
||||
var mode := String(b1.metrics.get("accept_mode", ""))
|
||||
print(" L%d 实测:inferability=%.3f / attempts_used=%d / accept_mode=%s / target=%.2f" % [
|
||||
L, inf, int(b1.metrics.get("attempts_used", -1)), mode, float(row.inferability_target)])
|
||||
# 出图验收(棋盘生成 登记口径):first_pass 必须 ≥ target;accept_best(重试耗尽接受最优)允许低于 target
|
||||
# 但必须打印实测值(正常出口);accept_worst 由下方 illegal_product 断言承担。
|
||||
Kit.check("L%d inferability %.3f %s target %.2f(accept_mode=%s)" % [L, inf, "≥" if inf >= float(row.inferability_target) else "<", float(row.inferability_target), mode],
|
||||
inf >= float(row.inferability_target) or mode == "accept_best")
|
||||
Kit.check("L%d 生成器产物零变体格(变异布置归战斗初始化第 4 步——生成器管线不布置,2026-09-19 用户拍板棋盘设置顺序)" % L, b1.variants.is_empty())
|
||||
Kit.check("L%d 指标集输出降级标记与目标雷数(三分出口表)" % L, b1.metrics.has("degraded_product") and b1.metrics.has("target_mines"))
|
||||
Kit.check("L%d 降级产物标记 = (accept_mode==accept_best)(%s→%s)" % [L, mode, str(b1.degraded_product)],
|
||||
b1.degraded_product == (mode == "accept_best"))
|
||||
Kit.check("L%d 非法产物标记 = (accept_mode==accept_worst)(%s→%s)" % [L, mode, str(b1.illegal_product)],
|
||||
b1.illegal_product == (mode == "accept_worst"))
|
||||
Kit.check("L%d 降级/非法产物标记互斥(两出口不可同真)" % L,
|
||||
not b1.degraded_product or not b1.illegal_product)
|
||||
Kit.check("L%d 产物断言:实际雷数 %d ≤ 目标雷数 N=%d(先布后删只减不增)" % [L, int(b1.metrics.actual_mines), int(b1.metrics.target_mines)],
|
||||
int(b1.metrics.actual_mines) <= int(b1.metrics.target_mines))
|
||||
Kit.check("L%d attempts_used ∈ [1,%d]" % [L, int(row.max_gen_attempts)],
|
||||
b1.metrics.get("attempts_used", 99) >= 1 and b1.metrics.get("attempts_used", 99) <= int(row.max_gen_attempts))
|
||||
Kit.check("L%d 非法产物标记 = false" % L, not b1.illegal_product)
|
||||
# 生成确定性:同种子逐格相同
|
||||
var b2 = board_generator.generate(L, 0, _mk_stream("board_gen", 777), _db)
|
||||
var b3 = board_generator.generate(L, 0, _mk_stream("board_gen", 777), _db)
|
||||
Kit.check("L%d 同种子两次生成逐格相同" % L, _board_dump(b2) == _board_dump(b3))
|
||||
var b4 = board_generator.generate(L, 0, _mk_stream("board_gen", 778), _db)
|
||||
Kit.check("L%d 异种子产物不同(退化护栏)" % L, _board_dump(b2) != _board_dump(b4))
|
||||
# ---- 初始展开收窄断言 ----
|
||||
# ① 结构断言:R₀ ≤ cap(正式表行投值,合法性闸承载——出图必过);② r0_cap_rejected 尝试事实在位;
|
||||
# ③ ring_removed 量级:≤ 域内候选危险格数(5×5−出生 9=16——无全域剃雷);
|
||||
# ④ 闸压线行为:cap=9(出生保障面下限)时出图必 r0≤9 或 accept_worst 非法标记(三分出口诚实降级,玩家永不卡死)
|
||||
var cap_val: int = int(row.get("r0_max_cap", 0))
|
||||
Kit.check("L%d r0_max_cap 正式行投值在位(%d ≥ 出生保障面 9——板面 30%% 锚)" % [L, cap_val],
|
||||
cap_val >= BoardData.SPAWN_AREA_CELLS)
|
||||
Kit.check("L%d 结构断言 R₀=%d ≤ cap=%d(R₀≤cap 重掷闸承载)" % [L, int(b1.metrics.r0_count), cap_val],
|
||||
int(b1.metrics.r0_count) <= cap_val)
|
||||
Kit.check("L%d r0_cap_rejected 尝试事实指标在位(本图 %d 次触发)" % [L, int(b1.metrics.get("r0_cap_rejected", -1))],
|
||||
int(b1.metrics.get("r0_cap_rejected", -1)) >= 0)
|
||||
Kit.check("L%d ring_removed=%d ≤ 剃雷域候选危险格数((3+2r)²−9——全域剃雷退役)" % [L, int(b1.metrics.get("ring_removed", 99))],
|
||||
int(b1.metrics.get("ring_removed", 99)) <= (2 + int(row.get("shave_ring_radius", 1))) * (2 + int(row.get("shave_ring_radius", 1))) * 4 - 5)
|
||||
var row9: Dictionary = row.duplicate()
|
||||
row9["r0_max_cap"] = BoardData.SPAWN_AREA_CELLS
|
||||
row9["max_gen_attempts"] = 4
|
||||
var stub9 := _BoardRowStub.new()
|
||||
stub9.row = row9
|
||||
var b9 = board_generator.generate(1, 0, _mk_stream("board_gen", 909), stub9)
|
||||
Kit.check("L1 cap 压线 9:出图 R₀=%d %s(三分出口诚实降级——超阈即 accept_worst 非法标记,玩家永不卡死)" % [int(b9.metrics.r0_count), "≤9" if int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS else ">9→illegal_product"],
|
||||
b9 != null and (int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS or b9.illegal_product))
|
||||
Kit.check("L1 cap 压线出图指标集完整(accept_mode=%s / 闸触发 %d 次)" % [String(b9.metrics.get("accept_mode", "")), int(b9.metrics.get("r0_cap_rejected", 0))],
|
||||
int(b9.metrics.get("r0_cap_rejected", 0)) >= 0 and String(b9.metrics.get("accept_mode", "")) != "")
|
||||
|
||||
|
||||
# 排雷 core 板面摘要(确定性对照面——尺寸/出生点/逐格雷位与变体清单)
|
||||
func _board_dump(b) -> String:
|
||||
var parts: Array = [str(b.width), str(b.height), str(b.spawn_center)]
|
||||
for y in b.height:
|
||||
for x in b.width:
|
||||
var c := Vector2i(x, y)
|
||||
parts.append("%d:%d:%d:%s" % [x, y, 1 if b.is_mine(c) else 0, str(b.variants.get(c, []))])
|
||||
return "\n".join(parts)
|
||||
Reference in new issue
Block a user