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 主会话裁)