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:
DKChan committed 2026-10-23 02:18:40 +08:00
1 parent c84a05f5a2
commit 5dd6d8498a
3 files changed
+91 -76

No files matched your search

-76
View File
@@ -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)
@@ -269,6 +269,7 @@
- `_smoke_layout_cell_formula`(2 条):2/2 验红。变异点——board_view.gd:233 删 `- float((n - 1) * sep)` 格间距项(bug⑥ 原缺陷形态;红唯一两条迭代齐红 L1 438/L2 442 > 436,档内条保持绿);board_view.gd:234 clamp 上界 46→25(该条守面=钳制带本体——夹具板实测格边 41/33 为带内值,带内改界不红,改界出带方验红;红唯一两条迭代齐红 25px < 26,网格高条保持绿)。
- `_smoke_reward_identity_unit`(10 条):10/10 验红(全部红唯一 1/14)。变异点——reward_economy.gd:89 roll_board 尾 return true→false(红「roll_board 受理」);:39 相位守卫 `_phase == "ready"`→`"never"`(红「重复 roll_board 被拒」);:113 投影删 tier 键(红「query_identity 投影」);:111 清单外出口 return null→{}(红「清单外坐标查询」;null→{} 形态避免 `_mapping[cell]` 缺键 crash);:140 grant 幂等缓存出口改扰动副本 duplicate+stacks=99(红「同格重复 grant 幂等」——重算快照值相等,非扰动副本形态红不了);:137 grant 清单外出口 return null→{}(红「清单外 grant 拒绝」);:87 `_clear_identity = clear_rid`→`"gp_coin"`(红「清图批尾身份」,power 掷定仍循真 clear_rid 故 :1977 power 条保持绿——隔离成功);:85 `_clear_power` 区间掷点→`power_min - 1`(红「清图奖励 power ∈ 表区间」roll 23 < 24);:152 grant_clear 幂等缓存出口改扰动副本(红「grant_clear 同批次重调幂等」);:163–164 两点变异 `_phase = "retired"` 与 `_mapping.clear()` 双双 pass 化(红「映射退役后 grant 拒绝」——该条守面=相位门+映射 wipe 联合,单点均被另一机制代偿必须两点)。
- `_smoke_board_generator`(22 条):22/22 验红(零死断言候选)。变异点——config_db_resolver.gd:156 行匹配 return row→`return {}`(红「BoardGen 行解析」双迭代+generate 行缺失断言链连带:「产物非空」「R1 ceil」同轮红——resolve 与 generate 共用单点不可分);**首试无效变异**:_ceil_key `return int(k)`→`int(k) - 1` 键值偏移致 level 键错位空 depth_keys 数组越界 crash(Parse 级污染不算红),换形 depth_ceil 路径插 `if missing == "depth_ceil": return {}`(红「R1 ceil 解析」红唯一 1/57);board_generator.gd:75 return accepted→null(红「生成产物非空」双迭代+suite1 rebuild 空板访问中断连带——预期形态);:278 is_clearable 尾 return true→false(红「clearable」双迭代+legality 内嵌消费链连带 6 条:legality 双红/accept_worst 链 inferability/非法产物/R₀ 结构);:282 legality 头插判别器 `if params.has("node_depth"): return false`(红「legality 全过」双迭代红唯一——generate 内部 params 无 node_depth 不受扰,防三分出口链连带);:340 指标 inferability→0.0(红「inferability ≥ target」L1 迭代红唯一——L2 原生 accept_best 走右支保持绿);:354 后插雷位格放变异 `for c in b.mines.keys(): b.variants[c] = []; break`(红「零变体格」双迭代红唯一——雷位格不入 spawn/R₀ 合法性扫描域);:346 指标删 degraded_product 键(红「指标集输出」双迭代红唯一——板字段独立在 :354 故三分出口条零连带);:354 板 degraded_product→true(红「降级标记」L1 红唯一——L2 原生 accept_best 与恒真恰一致);:353 板 illegal_product→true(红「非法标记==」双迭代+A14 双红+L2 互斥连带);:353–354 双标记恒 true(红「互斥」双迭代+A9/A10/A14 连带);:341 指标 actual_mines+10(红「实际≤目标」双迭代——真实雷数不动绕开 _finalize 内同不变式 _fatal 守卫);:344 指标 attempts_used→0(红「attempts 域」双迭代红唯一);:353 板 illegal_product 取反(红「非法标记=false」双迭代+A10 双红+L2 互斥+A21 b9 诚实降级标记连带);:100 取号换全局未播种 randi_range(红「同种子逐格相同」双迭代红唯一);:100 取号恒 i 恒等置换(红「异种子不同」+退化板 legality 链连带——板全同构时退化板本身非法属必然形态);board_gen.tres L1 depth0 行 r0_max_cap 45→5(红「cap 投值 ≥9」+cap 闸压全尝试 accept_worst 链连带 2 条);:349 指标 r0_count+100(红「R₀≤cap」双迭代红唯一——b9 illegal 支路承载故 A21 零连带);:351 指标 r0_cap_rejected→-1(红「尝试事实在位」双迭代+A22 双红连带);:348 指标 ring_removed→999(红「剃雷量界」双迭代红唯一);:316 r0_cap 闸条件 >→<(红「cap 压线 9」双迭代+L2 结构断言连带——闸关后高 R₀ 板入收);:345 指标 accept_mode→""(红「指标集完整」双迭代+L2 A6/A9 连带——右支与降级比较均读该指标)。
## 十、支援线 9 项待裁闭合(2026-10-22 主会话裁)