From 824a88d26d1d5dcc5d1afafb28974ec890f00c90 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Fri, 23 Oct 2026 02:24:48 +0800 Subject: [PATCH] =?UTF-8?q?test(=E8=BF=81=E7=A7=BB):=20=E6=89=B9=20B=20?= =?UTF-8?q?=E6=B3=A2=201=20G3=20=E5=A5=974=20=E4=BC=A4=E5=AE=B3=E9=87=8F?= =?UTF-8?q?=E5=80=BC=E5=8C=BA=E9=97=B4=E4=BA=94=E6=9D=A1=E8=BF=81=E5=85=A5?= =?UTF-8?q?=20board=5Fgen=5Freward=5Ftest.gd=E2=80=94=E2=80=94=E5=89=AA?= =?UTF-8?q?=E5=88=87=E6=8C=82=E8=BD=BD=E7=BB=BF=EF=BC=88=E5=AE=BF=E4=B8=BB?= =?UTF-8?q?=E7=B4=AF=E8=AE=A1=2062=20=E6=A3=80=E6=9F=A5=EF=BC=89=EF=BC=8B?= =?UTF-8?q?=E5=8F=98=E5=BC=82=204/5=20=E9=AA=8C=E7=BA=A2=EF=BC=9B=E3=80=8C?= =?UTF-8?q?=E5=8C=BA=E9=97=B4=E8=A1=8C=E4=B8=8A=E4=B8=8B=E9=98=B6=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E6=B5=81=E5=8A=A8=E3=80=8D=E8=AF=81=E6=AD=BB=E6=96=AD?= =?UTF-8?q?=E8=A8=80=E5=80=99=E9=80=89=EF=BC=88=E5=AE=88=E9=9D=A2=E5=90=8C?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E8=AF=BB=E6=95=B0=E8=87=AA=E6=AF=94=E8=BE=83?= =?UTF-8?q?=E6=81=92=E5=81=87=EF=BC=8C=E6=BA=90=E7=A0=81=E8=87=AA=E5=B8=A6?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=E9=9D=9E=E8=BF=81=E7=A7=BB=E5=BC=95=E5=85=A5?= =?UTF-8?q?=EF=BC=8C=E7=85=A7=E8=BF=81=E7=A6=81=E5=88=A0=E4=B8=8A=E6=8A=A5?= =?UTF-8?q?=E4=B8=BB=E4=BC=9A=E8=AF=9D=EF=BC=89=EF=BC=9B=5Frow=5Fpower=20?= =?UTF-8?q?=E5=A5=97=E5=86=85=E7=8B=AC=E5=8D=A0=E9=9A=8F=E8=BF=81=EF=BC=8C?= =?UTF-8?q?smoke=5Fall.gd=20=E5=90=8C=E6=89=B9=E5=88=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=B8=8E=E6=B8=B8=E7=A6=BB=E8=8A=82=E5=A4=B4=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/smoke/smoke_all.gd | 84 ------------------- game/tests/unit/core/board_gen_reward_test.gd | 80 ++++++++++++++++++ reports/批B-断言迁移账本-2026-10-22.md | 1 + 3 files changed, 81 insertions(+), 84 deletions(-) diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index 7d412df8..6ff18e98 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -1331,9 +1331,6 @@ func _ms_digest(ms, ae) -> Array: return [[int(ms.hero_pos().x), int(ms.hero_pos().y)], rev, seals, ae.ap, ae.phase, ms.seal_count()] -# ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)---- - - # ---- 排雷玩法 封印动作耗尽末点 AP 回归(playtest 缺陷②——v1 冒烟盲区:自动玩家不用封印)---- func _smoke_seal_ap_exhausted() -> void: @@ -2023,87 +2020,6 @@ func _auto_play_round(settlement, out: Dictionary) -> void: -# ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)---- - -func _smoke_power_interval() -> void: - print("--- 地图战斗资源·伤害量值区间(上阶/下阶随机)---") - # ① 表侧静态锚(配置推导——改表不断锚):凡带 power_min/power_max 的行 = 区间行, - # 校验配对齐全(lo ≤ hi)+ power = floor 中点(行动经济 条款①期望当量锚);其余行必须零区间字段。 - # 行清单与区间值全部随表走——现行区间行 heal_minor/clear_blast 只是恰然,不再是锚。 - var interval_rows := {} # rid → [lo, hi](读表) - var anchors_ok := true - for row in _db.reward.rows: - var rid := String(row.reward_id) - if row.has("power_min") or row.has("power_max"): - var lo: int = int(row.get("power_min", -1)) - var hi: int = int(row.get("power_max", -1)) - interval_rows[rid] = [lo, hi] - if lo > hi or int(row.power) != (lo + hi) / 2: - anchors_ok = false - check(anchors_ok and interval_rows.size() >= 1, - "区间行配对齐全且 power = floor 中点(配置推导 %d 行:%s)" % [interval_rows.size(), str(interval_rows.keys())]) - # ② 运行侧:24 板 roll——区间行快照 power 全域内 + 上下阶实际流动 + 定值行不受扰 - var rng = load("res://core/rng_service.gd").new() - rng.set_master_seed(20260914) - var reward_economy_factory = load("res://core/reward_economy.gd") - var eligible: Array = [] - for i in range(6): - eligible.append({"cell": Vector2i(i, 0)}) - var seen := {} - for rid in interval_rows.keys(): - seen[rid] = {} # rid → {roll 值集}(区间行随表注册) - var in_domain := true - var fixed_ok := true - for trial in range(24): - var reward_economy = reward_economy_factory.new(_db, rng) - if not reward_economy.roll_board(eligible): - continue - for e in eligible: - var snap: Dictionary = reward_economy.query_full_snapshot(e.cell) - var rid := String(snap.reward_id) - if interval_rows.has(rid): - var v := int(snap.power) - seen[rid][v] = true - if v < interval_rows[rid][0] or v > interval_rows[rid][1]: - in_domain = false - elif int(snap.power) != _row_power(rid): - fixed_ok = false # 定值行快照 power 必须仍是表值 - var cs: Dictionary = reward_economy.grant_clear() - var cv := int(cs.power) - var c_rid := String(cs.reward_id) - if not seen.has(c_rid): - seen[c_rid] = {} - seen[c_rid][cv] = true - if interval_rows.has(c_rid) and (cv < interval_rows[c_rid][0] or cv > interval_rows[c_rid][1]): - in_domain = false - check(in_domain, "24 板全区间行快照 power ∈ [power_min, power_max](含清图槽)") - check(fixed_ok, "定值行快照 power 恒等表值——区间批零外溢") - # 定值行(区间 lo==hi 的行,如 heal_minor)roll 恒等表值;区间行(lo 0 and not (samples == 1 and seen[rid].has(lo)): - fixed_rows_ok = false - elif samples >= 2 and seen[rid].size() < 2: - variance_ok = false - check(variance_ok, "区间行上下阶实际流动(≥2 样本的区间行须 ≥2 个不同 roll 值)") - check(fixed_rows_ok, "定值行(lo=hi)roll 恒等表值") - - -func _row_power(rid: String) -> int: - for row in _db.reward.rows: - if String(row.reward_id) == rid: - return int(row.power) - return -1 - - - - # ---- 行动经济·轮内刷新冒烟(方案 A:Active 相位当场换图继续挖)---- func _smoke_active_refresh() -> void: diff --git a/game/tests/unit/core/board_gen_reward_test.gd b/game/tests/unit/core/board_gen_reward_test.gd index b1fe72d1..de142373 100644 --- a/game/tests/unit/core/board_gen_reward_test.gd +++ b/game/tests/unit/core/board_gen_reward_test.gd @@ -33,6 +33,7 @@ func _init() -> void: _smoke_layout_cell_formula() _smoke_reward_identity_unit() _smoke_board_generator() + _smoke_power_interval() quit(Kit.finish("board_gen_reward_test")) @@ -202,3 +203,82 @@ func _board_dump(b) -> String: 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) + + +# ---- 地图战斗资源·伤害量值区间冒烟(roll 域内 + 中点锚 + 变异实际流动 + 定值行不受扰)---- + +func _smoke_power_interval() -> void: + print("--- 地图战斗资源·伤害量值区间(上阶/下阶随机)---") + # ① 表侧静态锚(配置推导——改表不断锚):凡带 power_min/power_max 的行 = 区间行, + # 校验配对齐全(lo ≤ hi)+ power = floor 中点(行动经济 条款①期望当量锚);其余行必须零区间字段。 + # 行清单与区间值全部随表走——现行区间行 heal_minor/clear_blast 只是恰然,不再是锚。 + var interval_rows := {} # rid → [lo, hi](读表) + var anchors_ok := true + for row in _db.reward.rows: + var rid := String(row.reward_id) + if row.has("power_min") or row.has("power_max"): + var lo: int = int(row.get("power_min", -1)) + var hi: int = int(row.get("power_max", -1)) + interval_rows[rid] = [lo, hi] + if lo > hi or int(row.power) != (lo + hi) / 2: + anchors_ok = false + Kit.check("区间行配对齐全且 power = floor 中点(配置推导 %d 行:%s)" % [interval_rows.size(), str(interval_rows.keys())], + anchors_ok and interval_rows.size() >= 1) + # ② 运行侧:24 板 roll——区间行快照 power 全域内 + 上下阶实际流动 + 定值行不受扰 + var rng = load("res://core/rng_service.gd").new() + rng.set_master_seed(20260914) + var reward_economy_factory = load("res://core/reward_economy.gd") + var eligible: Array = [] + for i in range(6): + eligible.append({"cell": Vector2i(i, 0)}) + var seen := {} + for rid in interval_rows.keys(): + seen[rid] = {} # rid → {roll 值集}(区间行随表注册) + var in_domain := true + var fixed_ok := true + for trial in range(24): + var reward_economy = reward_economy_factory.new(_db, rng) + if not reward_economy.roll_board(eligible): + continue + for e in eligible: + var snap: Dictionary = reward_economy.query_full_snapshot(e.cell) + var rid := String(snap.reward_id) + if interval_rows.has(rid): + var v := int(snap.power) + seen[rid][v] = true + if v < interval_rows[rid][0] or v > interval_rows[rid][1]: + in_domain = false + elif int(snap.power) != _row_power(rid): + fixed_ok = false # 定值行快照 power 必须仍是表值 + var cs: Dictionary = reward_economy.grant_clear() + var cv := int(cs.power) + var c_rid := String(cs.reward_id) + if not seen.has(c_rid): + seen[c_rid] = {} + seen[c_rid][cv] = true + if interval_rows.has(c_rid) and (cv < interval_rows[c_rid][0] or cv > interval_rows[c_rid][1]): + in_domain = false + Kit.check("24 板全区间行快照 power ∈ [power_min, power_max](含清图槽)", in_domain) + Kit.check("定值行快照 power 恒等表值——区间批零外溢", fixed_ok) + # 定值行(区间 lo==hi 的行,如 heal_minor)roll 恒等表值;区间行(lo 0 and not (samples == 1 and seen[rid].has(lo)): + fixed_rows_ok = false + elif samples >= 2 and seen[rid].size() < 2: + variance_ok = false + Kit.check("区间行上下阶实际流动(≥2 样本的区间行须 ≥2 个不同 roll 值)", variance_ok) + Kit.check("定值行(lo=hi)roll 恒等表值", fixed_rows_ok) + + +func _row_power(rid: String) -> int: + for row in _db.reward.rows: + if String(row.reward_id) == rid: + return int(row.power) + return -1 diff --git a/reports/批B-断言迁移账本-2026-10-22.md b/reports/批B-断言迁移账本-2026-10-22.md index d3a03fa1..907212bf 100644 --- a/reports/批B-断言迁移账本-2026-10-22.md +++ b/reports/批B-断言迁移账本-2026-10-22.md @@ -270,6 +270,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 连带——右支与降级比较均读该指标)。 +- `_smoke_power_interval`(5 条):4/5 验红+**1 条死断言候选(照迁禁删)**。变异点——reward.tres clear_blast 行 power 32→33(偏离 floor 中点;红「区间行配对齐全」红唯一 1/62);reward_economy.gd:85 清槽掷点 hi+5(红「24 板域内」红唯一——仅清槽支路格掷点不动故零连带);:353 _snapshot 定值行支路 `(int(row.power) + 1) if rolled_power < 0`(红「定值行零外溢」红唯一——区间行走 rolled 支路不受扰);:82+:85 双掷点恒取下界(**流动彻底消灭仍全绿=死断言取证**)——「区间行上下阶实际流动」守面 `elif samples >= 2 and seen[rid].size() < 2` 中 `samples` 与 `seen[rid].size()` 为同一字典的同一读数(`seen.get(rid, {})` 与 `seen[rid]` 同引用),条件恒假 variance_ok 不可置假;该缺陷系 smoke_all.gd 源码自带(非迁移引入),断言逐字照迁,死断言候选上报主会话裁;:82 格掷点 hi+1(红「定值行(lo=hi)roll 恒等表值」+「24 板域内」连带——heal_minor [2,2] 行任何失恒值必出域,两断言语义重叠连带不可避免)。 ## 十、支援线 9 项待裁闭合(2026-10-22 主会话裁)