iter56-卡2:封印动作改版(迭代56卡2·受理即揭示): 规则核心(target_sealed挖封印格拒/清图口径=挖开∪封印/能清图的封最优先/notify_cleared清图收轮/sealed_identity撤出→BoardData.cell_identity——上限20用户裁)+结算面dug_under_seal删净+破封一击退役+呈现层(地板+身份字形+印记不依赖揭示态+文案四件)+探针V8-V10+sim域(标空封印剔除约束增强+错触直挖补偿注入0.10)+golden三图换代; MC同批重锚50/档=100局(2026-11-08用户批准)三方对照无结构性恶化; 高档审计通过(17行全量·审计后勘误2项闭环)
This commit is contained in:
1 parent
908e518306
commit
5ec4a311bb
34 files changed
+589
-164
No files matched your search
@@ -142,6 +142,15 @@ func _spend_cost_and_arbitrate(cost: int, clears_map: bool) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
# 封印路径清图事实上报(排雷玩法 _do_seal_place 受理后清图判定成立时调用):
|
||||
# 轮末仲裁与 request_dig 的 cleared 语义同源——剩余 AP 当场清零作废、不进 RAP(EC7/EC10),
|
||||
# 同帧 cleared > ap_exhausted 胜出(覆盖写 _last_round_end)。封印不产挖掘计费,
|
||||
# 清图事实经独立上报口进入仲裁(硬塞 request_dig 会引入假挖掘记账)。
|
||||
func notify_cleared() -> void:
|
||||
_ap = 0
|
||||
_finish_round("cleared", "new_board")
|
||||
|
||||
|
||||
func _spend_and_arbitrate(action_kind: String, clears_map: bool) -> bool:
|
||||
var cost := _cost(action_kind)
|
||||
if _ap < cost:
|
||||
|
||||
@@ -43,6 +43,14 @@ func is_safe(c: Vector2i) -> bool:
|
||||
func digit_of(c: Vector2i) -> int:
|
||||
return digits.get(c, -1)
|
||||
|
||||
## 格身份事实(封闭枚举):kind = "mine"(digit 恒 -1)| "safe"(digit = 邻雷数)。
|
||||
## 封印受理即揭示的消费形态 = 呈现/测量侧按封印态(MinesweeperRules.has_seal)取本读数拼装——
|
||||
## 身份事实单点在板数据(is_mine/digit_of 同源),禁消费方各自拼 kind 枚举。
|
||||
func cell_identity(c: Vector2i) -> Dictionary:
|
||||
if is_mine(c):
|
||||
return {"kind": "mine", "digit": -1}
|
||||
return {"kind": "safe", "digit": digit_of(c)}
|
||||
|
||||
|
||||
func variant_ids(c: Vector2i) -> Array:
|
||||
return variants.get(c, [])
|
||||
|
||||
@@ -52,12 +52,12 @@ const EFFECT_KINDS := ["add_ticket_rider", "modify_ticket", "damage_mult", "open
|
||||
|
||||
## fact 条件词汇(封闭枚举——payload 同名键直读面〔fact 取值序 payload
|
||||
## 优先——effect_engine._fact_value 既有机制〕。new_resource_type=首开资源类型〔地质学家〕;
|
||||
## is_edge_cell=边缘格〔边陲矿工〕;is_blank_zero=空白连锁〔跳格采掘〕;dug_under_seal=被挖格
|
||||
## 当时有封印〔破封一击〕;ap_exhausted_last=上轮 AP 耗尽〔一滴不剩〕;hp_ratio=生命比例〔背水
|
||||
## is_edge_cell=边缘格〔边陲矿工〕;is_blank_zero=空白连锁〔跳格采掘〕;ap_exhausted_last=上轮
|
||||
## AP 耗尽〔一滴不剩〕;hp_ratio=生命比例〔背水
|
||||
## 06 前置条兑付〕;amount=单次伤害量〔保险丝〕;ap_left=停手剩余 AP〔弃图兑换〕)
|
||||
const FACTS := ["matchup", "is_first_dig_of_battle", "terrain_kind", "target_armor_class",
|
||||
"seals_count", "nest_count", "round_index", "counter",
|
||||
"new_resource_type", "is_edge_cell", "is_blank_zero", "dug_under_seal",
|
||||
"new_resource_type", "is_edge_cell", "is_blank_zero",
|
||||
"ap_exhausted_last", "hp_ratio", "amount", "ap_left", "pct",
|
||||
"battle_index"] # 关卡域战斗序(1 基,enc 携带;开局姿态组「每关首轮窗」条件面)
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ extends RefCounted
|
||||
## 揭示事实流:每格首次进入已开集恰发一次(已开格零事件)。
|
||||
## 载荷键集(四处发射位并集):cell: Vector2i/kind: "safe"|"mine"/digit: int(安全格邻雷数;危险格 -1)/
|
||||
## variant_ids: Array(地形变异身份,危险格空集)/channel: "initial"|"dig"|"chain"|"fx_reveal"/
|
||||
## resource: bool(格面资源兑付资格:initial=false,其余 true)/dug_under_seal: bool(首格带封印直挖标记——
|
||||
## initial 通道不发此键)。
|
||||
## resource: bool(格面资源兑付资格:initial=false,其余 true)。
|
||||
## 发送时点:initial=install_board 初始展开逐格;dig/chain=_do_dig 揭示闭包内(本格 AP 扣费在其后);
|
||||
## fx_reveal=fx_reveal 闭包内(零 AP 消耗零相位要求)。
|
||||
## 消费方依赖:战斗结算 _on_cell_revealed 以 resource 分流缓冲(fx_reveal 由兑付点直入账,禁二次缓冲)、
|
||||
@@ -94,14 +93,16 @@ func has_seal(c: Vector2i) -> bool:
|
||||
return _seals.has(c)
|
||||
|
||||
|
||||
|
||||
func revealed_cells() -> Array:
|
||||
return _revealed.keys()
|
||||
|
||||
|
||||
func _safe_remaining() -> int:
|
||||
# 清图口径 = 已挖 ∪ 已封印(封印受理即揭示改版——封掉的安全格计入完成)
|
||||
var n := 0
|
||||
for c in _board.safe_cells():
|
||||
if not _revealed.has(c):
|
||||
if not _revealed.has(c) and not _seals.has(c):
|
||||
n += 1
|
||||
return n
|
||||
|
||||
@@ -266,25 +267,41 @@ func settle_batch(intents: Array) -> Array:
|
||||
|
||||
func _classify(intent: Dictionary) -> int:
|
||||
# 0 = C_dig(执行后清图——真模拟,禁计数器捷径);1 = C_stop;2 = C_other
|
||||
# 清图口径 = 已挖 ∪ 已封印(封印受理即揭示改版——「能清图的挖或封」同归最先类)
|
||||
if intent.get("action", "") == "dig":
|
||||
var c: Vector2i = intent.get("cell", Vector2i(-9, -9))
|
||||
if _board_face_dig(c) == "" and not _board.is_mine(c):
|
||||
# 模拟 Chain(O, c) 后清图判定——挖封印格同口径:本格封印视为已隐式退役(其余封印照挡)
|
||||
var sim_seals: Dictionary[Variant, Variant] = _seals.duplicate()
|
||||
sim_seals.erase(c)
|
||||
var chain := _chain_closure(c, sim_seals) # 与真实执行同口径——空封印集捷径会在封印挡连锁时误判 C_dig(排雷玩法:真模拟)
|
||||
# 模拟 Chain(O, c) 后清图判定——真模拟禁计数器捷径(连锁不越封印,真封印集口径)
|
||||
var chain := _chain_closure(c, _seals)
|
||||
var remaining := 0
|
||||
for sc in _board.safe_cells():
|
||||
if not _revealed.has(sc) and not chain.has(sc):
|
||||
if not _revealed.has(sc) and not chain.has(sc) and not _seals.has(sc):
|
||||
remaining += 1
|
||||
if remaining == 0:
|
||||
return 0
|
||||
return 2
|
||||
if intent.get("action", "") == "seal_place":
|
||||
return _classify_seal(intent.get("cell", Vector2i(-9, -9)))
|
||||
if intent.get("action", "") == "stop":
|
||||
return 1
|
||||
return 2
|
||||
|
||||
|
||||
# 封印意图的清图预判分类(批次语义序「能清图的封」取数面——受理合法性模拟与清图口径模拟)
|
||||
func _classify_seal(c: Vector2i) -> int:
|
||||
if not _board.in_bounds(c) or is_revealed(c) or has_seal(c) or _removed.has(c):
|
||||
return 2
|
||||
if _board.is_mine(c):
|
||||
return 2 # 封危险格不清图(封印受理即揭示——身份当场可见但安全格分母不减)
|
||||
# 模拟封印受理后清图判定(换装口径:安全格完成 = 已揭示 ∪ 已封印)
|
||||
var sim_seals: Dictionary[Variant, Variant] = _seals.duplicate()
|
||||
sim_seals[c] = true
|
||||
for sc in _board.safe_cells():
|
||||
if not _revealed.has(sc) and not sim_seals.has(sc):
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
func _execute(intent: Dictionary) -> Dictionary:
|
||||
match intent.get("action", ""):
|
||||
"dig":
|
||||
@@ -305,16 +322,8 @@ func _do_dig(c: Vector2i) -> Dictionary:
|
||||
var sub := _board_face_dig(c)
|
||||
if sub != "":
|
||||
return _outcome(false, "rejected", "board_face", sub)
|
||||
# 挖封印格(封印不可逆):本格封印事务内隐式退役——链闭包按「本格无封印、其余封印照挡」
|
||||
# 计算(封印格为 0 时连锁照常外扩);request_dig 被拒则封印原地保留(事务性),受理后该封印轮末不判
|
||||
# (发射面基线 = 在场封印——标中/标空兑付让位于挖掘本体结局,四情况②④)。
|
||||
var was_sealed := has_seal(c)
|
||||
var eff_seals: Dictionary[Variant, Variant] = _seals
|
||||
if was_sealed:
|
||||
eff_seals = _seals.duplicate()
|
||||
eff_seals.erase(c)
|
||||
# 真模拟连锁与清图(F2/F1——单一实现两名字)
|
||||
var chain := _chain_closure(c, eff_seals)
|
||||
# 真模拟连锁与清图(F2/F1——单一实现两名字;连锁不越封印,挖封印格已被合法性表拒绝)
|
||||
var chain := _chain_closure(c, _seals)
|
||||
var clears: bool = _cleared_after(chain)
|
||||
# F2 口径:chain_size = |O′ ∖ (O ∪ {c})|——闭包含已开集 O,只数新开格(不含首格)
|
||||
var chain_size := 0
|
||||
@@ -325,10 +334,8 @@ func _do_dig(c: Vector2i) -> Dictionary:
|
||||
if not action_economy.request_dig(chain_size, clears):
|
||||
return _outcome(false, "rejected", "resource_face", "")
|
||||
# 事务内执行:首格 + 连锁新格揭示(BFS 规范序,零特判);事件 = O′ ∖ O
|
||||
if was_sealed:
|
||||
_seals.erase(c)
|
||||
var reveal_order: Array[Variant] = _chain_reveal_order(c, eff_seals)
|
||||
_reveal_chain(c, reveal_order, was_sealed)
|
||||
var reveal_order: Array[Variant] = _chain_reveal_order(c, _seals)
|
||||
_reveal_chain(c, reveal_order)
|
||||
if action_economy.phase != action_economy.PHASE_ACTIVE:
|
||||
_emit_round_end_seals_and_payload()
|
||||
return _outcome(true, "executed", "", "")
|
||||
@@ -337,8 +344,7 @@ func _do_dig(c: Vector2i) -> Dictionary:
|
||||
## 连锁揭示域:首格+连锁新格揭示(BFS 规范序——cell_revealed 发射序即链序,整体随段搬迁)。
|
||||
## 格面资源资格:chain/dig 恒 true——安全格与危险格一视同仁(危险格亦携带,
|
||||
## 负向兑付归 战斗结算 极性路由);initial(封锁格)恒 false。资源本体与极性不在本系统。
|
||||
## dug_under_seal = 首格带封印直挖标记(战斗结算 情况④兑付改判消费;连锁格恒 false——连锁不越封印)
|
||||
func _reveal_chain(c: Vector2i, reveal_order: Array, was_sealed: bool) -> void:
|
||||
func _reveal_chain(c: Vector2i, reveal_order: Array) -> void:
|
||||
for rc in reveal_order:
|
||||
if _revealed.has(rc):
|
||||
continue # 闭包可穿过已开区——已开格零事件(cell_revealed × |O′ ∖ O|)
|
||||
@@ -348,14 +354,12 @@ func _reveal_chain(c: Vector2i, reveal_order: Array, was_sealed: bool) -> void:
|
||||
cell_revealed.emit({
|
||||
"cell": rc, "kind": "mine", "digit": -1,
|
||||
"variant_ids": [], "channel": channel, "resource": true,
|
||||
"dug_under_seal": was_sealed and rc == c,
|
||||
})
|
||||
else:
|
||||
_revealed[rc] = {"kind": "safe", "digit": _board.digit_of(rc)}
|
||||
cell_revealed.emit({
|
||||
"cell": rc, "kind": "safe", "digit": _board.digit_of(rc),
|
||||
"variant_ids": _board.variant_ids(rc), "channel": channel, "resource": true,
|
||||
"dug_under_seal": was_sealed and rc == c,
|
||||
})
|
||||
|
||||
|
||||
@@ -366,9 +370,10 @@ func _board_face_dig(c: Vector2i) -> String:
|
||||
return "not_adjacent"
|
||||
if is_revealed(c):
|
||||
return "target_revealed"
|
||||
if has_seal(c):
|
||||
return "target_sealed" # 封印受理即揭示、不可再挖开(封印承诺 = 对该格的最终处置——改判路径已退役)
|
||||
if _removed.has(c):
|
||||
return "target_removed" # 中立移除格不可交互(拒绝先于消耗,pattern 1 board_face 腿)
|
||||
# 封印不拦挖掘(封印不可逆):有封印格直接挖 = 对承诺的兑现,兑付改判归 战斗结算。
|
||||
return ""
|
||||
|
||||
|
||||
@@ -387,17 +392,14 @@ func fx_reveal(c: Vector2i) -> bool:
|
||||
cell_revealed.emit({
|
||||
"cell": rc, "kind": "safe", "digit": _board.digit_of(rc),
|
||||
"variant_ids": _board.variant_ids(rc), "channel": "fx_reveal", "resource": true,
|
||||
"dug_under_seal": false,
|
||||
})
|
||||
return true
|
||||
|
||||
|
||||
## 挖一格→真实翻开集只读预览(sim 信息面出口——与 _classify 同口径:本格封印视为已隐式退役、
|
||||
## 其余封印照挡;复用 _chain_closure 闭包;零状态写入、零事件发射)
|
||||
## 挖一格→真实翻开集只读预览(sim 信息面出口——与 _classify 同口径:连锁不越封印、
|
||||
## 真封印集口径;复用 _chain_closure 闭包;零状态写入、零事件发射)
|
||||
func preview_reveal(c: Vector2i) -> Array[Vector2i]:
|
||||
var sim_seals := _seals.duplicate()
|
||||
sim_seals.erase(c)
|
||||
var closure := _chain_closure(c, sim_seals)
|
||||
var closure := _chain_closure(c, _seals)
|
||||
var out: Array[Vector2i] = []
|
||||
for cc in closure.keys():
|
||||
if cc != c and not _revealed.has(cc):
|
||||
@@ -436,34 +438,44 @@ func _chain_reveal_order(start: Vector2i, seal_set: Dictionary) -> Array:
|
||||
|
||||
|
||||
func _cleared_after(chain: Dictionary) -> bool:
|
||||
# 清图口径 = 已挖 ∪ 已封印(与 _safe_remaining 同源——私有共享口径单点,禁第三处重复实现)
|
||||
for c in _board.safe_cells():
|
||||
if not _revealed.has(c) and not chain.has(c):
|
||||
if not _revealed.has(c) and not chain.has(c) and not _seals.has(c):
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
# ---- 封印 ----
|
||||
|
||||
func _do_seal_place(c: Vector2i) -> Dictionary:
|
||||
var sub := ""
|
||||
# 封印棋盘面合法性(board_face 拒绝情形序:目录外/不相邻/已开/已有封印/已移除——与挖掘合法性同构分域)
|
||||
func _seal_face_reject(c: Vector2i) -> String:
|
||||
if not _board.in_bounds(c):
|
||||
sub = "out_of_catalog"
|
||||
elif not (seal_range_free or _adjacent_to_hero(c)):
|
||||
sub = "not_adjacent" # 信标网络装配时豁免(封印不限相邻——封印动作仍按标准价计费,规则放宽仅可达性)
|
||||
elif is_revealed(c):
|
||||
sub = "target_revealed"
|
||||
elif has_seal(c):
|
||||
sub = "seal_present"
|
||||
elif _removed.has(c):
|
||||
sub = "target_removed" # 中立移除格不可交互
|
||||
return "out_of_catalog"
|
||||
if not (seal_range_free or _adjacent_to_hero(c)):
|
||||
return "not_adjacent" # 信标网络装配时豁免(封印不限相邻——封印动作仍按标准价计费,规则放宽仅可达性)
|
||||
if is_revealed(c):
|
||||
return "target_revealed"
|
||||
if has_seal(c):
|
||||
return "seal_present"
|
||||
if _removed.has(c):
|
||||
return "target_removed" # 中立移除格不可交互
|
||||
return ""
|
||||
|
||||
|
||||
func _do_seal_place(c: Vector2i) -> Dictionary:
|
||||
var sub := _seal_face_reject(c)
|
||||
if sub != "":
|
||||
return _outcome(false, "rejected", "board_face", sub)
|
||||
if not action_economy.try_spend("seal_place"):
|
||||
return _outcome(false, "rejected", "resource_face", "")
|
||||
_seals[c] = true # 封印动作零格子事件外发(发射面封闭;反馈经调用返回值命令式驱动)
|
||||
if _cleared_after({}):
|
||||
# 封印受理即揭示改版:封掉最后安全格 = 清图完成——轮末仲裁走 cleared(行动经济
|
||||
# notify_cleared 独立上报口,与 request_dig 的 cleared 语义同源;同帧覆盖 ap_exhausted)
|
||||
action_economy.notify_cleared()
|
||||
if action_economy.phase != action_economy.PHASE_ACTIVE:
|
||||
# 封印动作花完末点 AP 同样终结轮次(行动经济 三出口——AP 用完与动作种类无关;缺漏使 round_end
|
||||
# 永不发出、战斗结算 的 Waiting 结算点永不到达 = 整局软锁)
|
||||
# 永不发出、战斗结算 的 Waiting 结算点永不到达 = 整局软锁);清图收轮同此出口发判定批
|
||||
_emit_round_end_seals_and_payload()
|
||||
return _outcome(true, "executed", "", "")
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ func _safe_dig_open(v: Dictionary) -> Dictionary:
|
||||
for c_v in v.resolved:
|
||||
var c := Vector2i(c_v)
|
||||
if fx_host.minesweeper.has_seal(c):
|
||||
continue
|
||||
continue # 封印格不代开(封印受理即揭示——天眼揭示绕开承诺格,零动作)
|
||||
if fx_host.minesweeper.fx_reveal(c):
|
||||
opened_any = true
|
||||
if not opened_any:
|
||||
|
||||
@@ -93,15 +93,12 @@ func _reveal_batch(ri: int) -> void:
|
||||
_reveal_mine(evt, snap, ri)
|
||||
|
||||
|
||||
# safe 事件兑付(封印不可逆四情况④:插安全格再挖开 = 零惩罚零奖励——正向兑付作废〔归因行在案〕;
|
||||
# 标空判定已随封印擦除自然缺席——被挖的封印不在轮末在场基线。dig_reveal 发射+施加序:
|
||||
# safe 事件兑付(封印受理即揭示改版:挖封印格已被规则合法性表拒绝——改判路径整体退役,
|
||||
# 本函数只受理真实揭示的 safe 事件。dig_reveal 发射+施加序:
|
||||
# 乘区收集 → 正向兑付 → 施加面〔计数器/揭示入队/追加产出/奥术矢〕。
|
||||
# payload 携 is_edge_cell〔边陲矿工〕/is_blank_zero〔跳格采掘〕/
|
||||
# new_resource_type〔地质学家——快照 cell_type 首见判定,见后集登记〕)
|
||||
func _reveal_safe(evt: Dictionary, snap: Dictionary, ri: int) -> void:
|
||||
if bool(evt.get("dug_under_seal", false)):
|
||||
emit_row_cb.call({"type": "reward_ineffective", "source_class": "safe_cell", "origin_cell": evt.cell}, ri, "奖励作废(封印格直接挖开——零惩罚零奖励)", 0, {})
|
||||
return
|
||||
var board_b: BoardData = minesweeper.current_board()
|
||||
var ctype := String(snap.get("cell_type", ""))
|
||||
var is_new_type := fx_host.mark_new_resource_type(ctype)
|
||||
@@ -145,12 +142,12 @@ func _reveal_safe_apply(dr_hits: Array, evt: Dictionary, ri: int) -> void:
|
||||
|
||||
|
||||
# mine 事件兑付(封印不可逆四情况②:插危险格再挖开 = 只受挖雷一层惩罚——mine_hit 照常兑付惊动巢穴,
|
||||
# 标中不发〔封印已随挖掘擦除、不入轮末判定基线〕。mine_hit 发射+施加序:施加面收集 → 减伤落快照 →
|
||||
# mine_hit 发射+施加序:施加面收集 → 减伤落快照 →
|
||||
# 计数器 → 揭示入队 → 负向兑付〔带减半系数〕→ 反打开单)
|
||||
func _reveal_mine(evt: Dictionary, snap: Dictionary, ri: int) -> void:
|
||||
var mine_power := int(snap.get("power", 0))
|
||||
var mh_hits := fx_host.fx_emit("mine_hit", {"cell": evt.cell, "round": ri,
|
||||
"damage": mine_power, "dug_under_seal": bool(evt.get("dug_under_seal", false)),
|
||||
"damage": mine_power,
|
||||
"hp_ratio": int(round(100.0 * float(int(units.hero_unit().get("hp", 0))) / float(maxi(1, int(units.hero_unit().get("max_hp", 1))))))})
|
||||
var applied := _reveal_mine_apply(mh_hits, snap, evt.cell, ri)
|
||||
if int(applied["mine_reduce"]) > 0:
|
||||
@@ -201,8 +198,8 @@ func _reveal_mine_apply(mh_hits: Array, snap: Dictionary, cell: Vector2i, ri: in
|
||||
|
||||
# 地形变异 兑付批(授予段尾——触发枚举 on_open:挖开即伤、chain 通道同口径;伤害单据案C 暂存到
|
||||
# 战斗段末兑付〔案C〕;信息型 hide_number 不进结算——呈现层读取,见 board_view 数字遮蔽;
|
||||
# 危险格恒无变异——布置段排除,双层叠罚不存在;封印格直挖照吃变异伤害——地形后果同 mine_hit 口径,
|
||||
# 非奖励不作废;吞噬流资源兑付〔荆棘编织/地脉补偿〕中伤害形态行同样经案C闸暂存,非伤害形态照常当场)
|
||||
# 危险格恒无变异——布置段排除,双层叠罚不存在;封印格不可挖(封印受理即揭示——变异伤害只随
|
||||
# 真实揭示兑付);吞噬流资源兑付〔荆棘编织/地脉补偿〕中伤害形态行同样经案C闸暂存,非伤害形态照常当场)
|
||||
func _terrain_batch(ri: int) -> void:
|
||||
for evt in facts.reveals:
|
||||
var vids: Array[Variant] = evt.get("variant_ids", [])
|
||||
|
||||
@@ -619,30 +619,6 @@ rows = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"feat_id": "breaker_strike",
|
||||
"display_name": "破封一击",
|
||||
"rarity": "excellent",
|
||||
"cap": 1,
|
||||
"desc": "挖开带封印的危险格:+1 层(疼痛记忆同账)",
|
||||
"triggers": [
|
||||
{
|
||||
"on": "mine_hit",
|
||||
"when": [
|
||||
{
|
||||
"fact": "dug_under_seal",
|
||||
"op": "eq",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"do": {
|
||||
"kind": "counter_add",
|
||||
"counter_id": "pain_layers",
|
||||
"value": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"feat_id": "map_exchange",
|
||||
"display_name": "弃图兑换",
|
||||
|
||||
@@ -176,7 +176,8 @@ static func outcome_text(outcome: Dictionary) -> String:
|
||||
"not_adjacent": "不能执行:目标与小人不相邻",
|
||||
"target_revealed": "不能执行:目标已开",
|
||||
"target_concealed": "不能移动:目标未开",
|
||||
"seal_present": "不能封印:此格已有封印印记(封印为一次性承诺——相邻时左键直接挖开)",
|
||||
"target_sealed": "不能挖:此格已封印(封印受理即揭示——不可再挖开)",
|
||||
"seal_present": "不能封印:此格已有封印印记(封印受理即揭示——印记随图存续)",
|
||||
"no_path": "不能移动:已探明区不连通",
|
||||
"out_of_catalog": "无效目标",
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func _apply_hover_visuals(c: Vector2i) -> void:
|
||||
_show_path_preview(c)
|
||||
elif adjacent:
|
||||
u.face.hl_visible = true
|
||||
u.face.hl_color = COL_HL_TARGET # 挖掘目标格边框(相邻封印格同此——左键直接挖)
|
||||
u.face.hl_color = COL_HL_TARGET # 挖掘目标格边框(已封印格不入 _diggable——落下方封印禁入分支)
|
||||
_set_cursor_shape(c, CURSOR_DIG)
|
||||
elif seal:
|
||||
u.face.hl_visible = true
|
||||
|
||||
@@ -300,8 +300,8 @@ func refresh() -> void:
|
||||
var hero: Vector2i = _minesweeper.hero_pos()
|
||||
_diggable.clear()
|
||||
for n in _board.neighbors8(hero):
|
||||
if not _minesweeper.is_revealed(n) and not _minesweeper.is_removed(n):
|
||||
_diggable[n] = true
|
||||
if not _minesweeper.is_revealed(n) and not _minesweeper.is_removed(n) and not _minesweeper.has_seal(n):
|
||||
_diggable[n] = true # 已封印格不入可挖域(封印受理即揭示——挖封印格被拒)
|
||||
_recompute_glow(hero)
|
||||
for y in _board.height:
|
||||
for x in _board.width:
|
||||
@@ -474,14 +474,15 @@ func _on_cell_input(c: Vector2i, ev: InputEvent) -> void:
|
||||
if ev.button_index == MOUSE_BUTTON_LEFT:
|
||||
if _minesweeper.is_revealed(c):
|
||||
action_requested.emit(c, "move")
|
||||
elif _minesweeper.has_seal(c):
|
||||
pass # 已封印格零动作(封印受理即揭示——挖封印格被拒,左右键同零意图)
|
||||
else:
|
||||
action_requested.emit(c, "dig")
|
||||
_hover_comp.detect_chord(c)
|
||||
elif ev.button_index == MOUSE_BUTTON_RIGHT:
|
||||
if not _minesweeper.has_seal(c):
|
||||
action_requested.emit(c, "seal_place")
|
||||
# 封印 = 一次性承诺:右键对封印格零动作(无撤封印);
|
||||
# 左键相邻封印格直接挖(规则引擎放行)。
|
||||
# 封印 = 受理即揭示的最终承诺:右键对封印格零动作(无撤封印),左键同零动作。
|
||||
|
||||
|
||||
# ---- 奖励徽章(已开格身份 icon——封印之下、纹带之上、不进数字区) ----
|
||||
@@ -536,20 +537,22 @@ func _paint_cell(c: Vector2i, hero: Vector2i) -> void:
|
||||
var seal: bool = _minesweeper.has_seal(c)
|
||||
var removed: bool = _minesweeper.is_removed(c) # 中立移除格(退色降档)
|
||||
var is_hero: bool = c == hero
|
||||
# 封印印记下发(卡④ 法阵化):封印格=未开且未移除 → CellUnit 封印子件绘制(着色器参数化);
|
||||
# 其余格撤子件。层序与迷雾门控在 CellUnit 侧承载(seal_mark_layer/fog_state 联动)。
|
||||
u.seal_on = seal and not revealed
|
||||
# 封印印记下发(卡④ 法阵化+封印受理即揭示改版):封印格(未移除)→ CellUnit 封印子件绘制
|
||||
# (着色器参数化)——印记可见性不依赖揭示态(已揭示格承载=新组合态);其余格撤子件。
|
||||
# 层序与迷雾门控在 CellUnit 侧承载(seal_mark_layer/fog_state 联动)。
|
||||
u.seal_on = seal
|
||||
if removed:
|
||||
revealed = false # 移除格固定未开呈现基座(退色暗幕层承载;危险格本无数字,周边数字冻结)
|
||||
seal = false
|
||||
u.seal_on = false
|
||||
# 绘制层五段(字形与色牌→基底瓦片→立面投影→秘宝/变异叠加→迷雾)——段间交换经单元状态面
|
||||
#(u.base/u.face 域件与 u.glyph/u.glyph_color),唯一例外=基底色 bg 经 ink 段返回值交 base 段(无单元场域承载)
|
||||
var shown: bool = revealed or seal # 呈现揭示态(封印受理即揭示——地板瓦片/身份字形/迷雾开启)
|
||||
var bg: Color = _paint_cell_ink(c, u, revealed, seal)
|
||||
_paint_cell_base(c, u, revealed, is_hero, bg)
|
||||
_paint_cell_facade(c, u, revealed)
|
||||
_paint_cell_base(c, u, shown, is_hero, bg)
|
||||
_paint_cell_facade(c, u, shown)
|
||||
_paint_cell_overlays(c, u, revealed)
|
||||
_paint_cell_fog(c, u, revealed, hero)
|
||||
_paint_cell_fog(c, u, shown, hero)
|
||||
u.face.removed_dim = removed
|
||||
u.queue_redraw()
|
||||
|
||||
@@ -575,11 +578,19 @@ func _paint_cell_ink(c: Vector2i, u: Node2D, revealed: bool, seal: bool) -> Colo
|
||||
else:
|
||||
glyph = str(d)
|
||||
digit_col = _digit_ink(d) # 数字墨三档色温(§4.1)
|
||||
elif seal:
|
||||
# 封印受理即揭示:身份字形按板事实当场可见(cell_identity 单点——不用等轮末判定;
|
||||
# 数字遮蔽不适用——遮蔽打脸受理即揭示)。
|
||||
bg = COL_FLOOR
|
||||
var ident: Dictionary = _board.cell_identity(c)
|
||||
if String(ident.get("kind", "")) == "mine":
|
||||
glyph = "危"
|
||||
digit_col = UiKit.RED_MINE
|
||||
elif int(ident.get("digit", 0)) > 0:
|
||||
glyph = str(int(ident.get("digit", 0)))
|
||||
digit_col = _digit_ink(int(ident.get("digit", 0)))
|
||||
else:
|
||||
if seal:
|
||||
bg = COL_BRICK # 封印印记由 CellUnit 封印子件绘制(卡④ 法阵化——缺图字形回退随贴图路径退役)
|
||||
else:
|
||||
bg = COL_BRICK
|
||||
bg = COL_BRICK
|
||||
u.glyph = glyph
|
||||
u.glyph_color = digit_col
|
||||
# 色牌后备(数字直画退牌;「危」/「?」维持牌载保读性)+ v3.4:双峰纹理板
|
||||
@@ -588,7 +599,7 @@ func _paint_cell_ink(c: Vector2i, u: Node2D, revealed: bool, seal: bool) -> Colo
|
||||
if plate_digit:
|
||||
digit_col = COL_DIGIT # 牌上深墨族(素牌 12:1——双峰纹理免疫)
|
||||
u.glyph_color = digit_col
|
||||
u.plate = revealed and (glyph == "危" or glyph == "?" or plate_digit)
|
||||
u.plate = (revealed or seal) and (glyph == "危" or glyph == "?" or plate_digit)
|
||||
return bg
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ func _build_board_children(board_area: Control, vb: VBoxContainer) -> void:
|
||||
hint.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
hint.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
vb.add_child(hint)
|
||||
var hl := UiKit.label("左键 挖掘 / 移动 · 右键 封印(不可逆) · 同格双击 快开",UiKit.FS_CAPTION, false, UiKit.WARM_FAINT)
|
||||
var hl := UiKit.label("左键 挖掘 / 移动 · 右键 封印(受理即揭示·不可逆)",UiKit.FS_CAPTION, false, UiKit.WARM_FAINT)
|
||||
hint.add_child(hl)
|
||||
# 信号转发(组合根只接线一处)
|
||||
board_view.action_requested.connect(_forward_action)
|
||||
|
||||
@@ -8,7 +8,7 @@ signal closed
|
||||
const ENTRIES := [
|
||||
["#C9AF83", "完整覆尘地砖", "未开格——左键挖开(1AP,须相邻)· 右键封印(1AP)"],
|
||||
["#B39A78", "碎裂裸土", "已开 0 格——可通行,左键移动(免费)"],
|
||||
["#000000", "封印", "封印印记(呈现名·不能拔)——轮末自动判定标中;标空可左键直接挖开(安全格零奖励、危险格受挖掘惩罚)"],
|
||||
["#000000", "封印", "封印印记(受理即揭示——落定当场可见格下身份,随图存续不能拔)——轮末自动判定标中/标空;已封印格零动作(不可再挖开)"],
|
||||
["#2e86de", "小人", "探险者——8 向相邻未开格常驻微光 = 可挖域"],
|
||||
["#F0A828", "金徽章", "已开格奖励身份 icon(封印之下、数值之上,不进数字区)"],
|
||||
["#F0A828", "九徽章解码", "攻=攻击 · 守=护甲 · 爆=爆裂 · 医=回复 · 弱=削弱 · 穿=穿刺 · 魔=魔法 · 行=行动点 · 金=GP"],
|
||||
|
||||
@@ -142,7 +142,7 @@ func _ready() -> void:
|
||||
# 全拒则免邻接旗标+任意未开格重试,AP 不足先 grant_ap 兜底;拒绝全数=取证段红)----
|
||||
var seal_cell := Vector2i(-9, -9)
|
||||
for c in settlement.minesweeper.current_board().safe_cells():
|
||||
if settlement.minesweeper.has_seal(c) and not settlement.minesweeper.is_revealed(c):
|
||||
if settlement.minesweeper.has_seal(c): # 取证选择器换代〔封印改 V8〕——印记可见性不依赖揭示态(受理即揭示)
|
||||
seal_cell = c
|
||||
break
|
||||
if seal_cell.x < 0:
|
||||
|
||||
@@ -20,7 +20,6 @@ var _stall_frames := 0
|
||||
var _closed_via_abandon := false # T17——预算耗尽经放弃路径收口(断点段返回断言豁免位)
|
||||
var _done := false
|
||||
var _rand := RandomNumberGenerator.new()
|
||||
var _seals_placed: Array = []
|
||||
var _ap_spent_this_round := 0
|
||||
var _problems: Array = [] # 新增覆盖的问题收集(退出码合并判定)
|
||||
var _tested_legend := false
|
||||
@@ -37,6 +36,7 @@ var _tested_map_status := false # 地图屏角标一次性 case(选路态
|
||||
var _inter_confirms := 0 # 大奖励屏确认计数(冒险推进停点——首见确认推进 L2,再见 = L2 关卡完成收口)
|
||||
var _settlement_confirms := 0 # 卡⑥ 胜利结算框确认计数(观测面——每场普通战斗胜利恰一)
|
||||
var _route_clicks := 0 # 选路覆盖层点击计数(岔路使用率观测面)
|
||||
var _seals_placed: Array = [] # 随机封印簿记(行为①仍在役;行为②撤封印已退役——dump 读数面保留)
|
||||
var _locktest_state := 0 # T1 D1 锁期/重放断言状态机(0=待注入 1=等重放 2=完结)——每 run 一次
|
||||
var _locktest_cell := Vector2i(-9, -9)
|
||||
var _locktest_frames := 0
|
||||
@@ -827,7 +827,6 @@ func _ready() -> void:
|
||||
_done = true
|
||||
print("[click_probe] 第二关大奖励屏(L2 关卡完成)——探针收口 · 选路口点击 %d 次" % _route_clicks)
|
||||
break
|
||||
_seals_placed.clear()
|
||||
continue
|
||||
if main.ui.modals.run.end_overlay.is_open() and main.run_scope.settlement_stop_timer.is_armed():
|
||||
# 战斗胜利总结结算框(真实信号路径——每场普通胜利到达):断言已拍板面后点「下一节点」
|
||||
@@ -1216,8 +1215,9 @@ func _run_modal_probes_once() -> void:
|
||||
for e in main.ui.modals.run.legend_overlay.ENTRIES:
|
||||
if String(e[1]) == "封印":
|
||||
legend_has_seal = true
|
||||
# 图例封印行换代断言(迭代36 卡A wa5——真实 AP 条图例钮开层路径)
|
||||
if not String(e[2]).contains("标空") or not String(e[2]).contains("受挖掘惩罚") or String(e[2]).contains("插错") or String(e[2]).contains("挖雷"):
|
||||
# 图例封印行换代断言〔封印改 V10〕(迭代36 卡A wa5 载体——真实 AP 条图例钮开层路径):
|
||||
# 新口径=受理即揭示/已封印格零动作;旧「受挖掘惩罚」句随改判路径退役,雷字清零照守
|
||||
if not String(e[2]).contains("受理即揭示") or not String(e[2]).contains("零动作") or String(e[2]).contains("插错") or String(e[2]).contains("挖雷") or String(e[2]).contains("雷格"):
|
||||
_problems.append("图例封印行旧词残留(wa5——%s)" % String(e[2]).replace("
|
||||
", "|"))
|
||||
if not legend_has_seal:
|
||||
@@ -1391,12 +1391,8 @@ func _play_one_action() -> void:
|
||||
_seals_placed.append(target)
|
||||
_ap_spent_this_round += 1
|
||||
return
|
||||
# 行为②:随机撤封印(右键已封印格),约 10% 轮次
|
||||
if _rand.randf() < 0.1 and not _seals_placed.is_empty():
|
||||
var fc: Vector2i = _seals_placed.pop_back()
|
||||
if minesweeper.has_seal(fc) and not minesweeper.is_revealed(fc):
|
||||
main.ui.battle.board_zone.board_view.click_cell(fc, MOUSE_BUTTON_RIGHT)
|
||||
_ap_spent_this_round += 1
|
||||
# 行为②撤封印退役〔封印改 V9 波及面——test-conventions §5.5 同生死〕:右键已封印格零动作
|
||||
# (封印受理即揭示——撤封印路径不存在),随机撤封印行为段整体摘除;_seals_placed 簿记随段退役。
|
||||
return
|
||||
# 行为③:随机无效点击(非相邻格/已开格),约 8% 轮次
|
||||
if _rand.randf() < 0.08:
|
||||
@@ -1500,7 +1496,7 @@ func _locktest_tick() -> void:
|
||||
b.width, b.height, str(settlement.minesweeper.hero_pos())])
|
||||
_problems.append("重放断言:锁期缓存点击未受理恰一次(封印未置位——零发或双发)")
|
||||
_locktest_state = 2
|
||||
main.ui.battle.board_zone.board_view.click_cell(_locktest_cell, MOUSE_BUTTON_RIGHT) # 撤封印恢复现场(尽力而为不判定)
|
||||
# 撤封印恢复现场调用随行为②退役〔封印改 V9〕——右键已封印格零动作(改判路径不存在)
|
||||
|
||||
|
||||
func _locktest_pick_cell(minesweeper) -> Vector2i:
|
||||
|
||||
@@ -271,7 +271,7 @@ func _ready() -> void:
|
||||
if bv.mouse_default_cursor_shape != Input.CURSOR_ARROW:
|
||||
_problems.append("case③ 移动光标缺失(%d)" % bv.mouse_default_cursor_shape)
|
||||
# ---- case④ 右键封印:seal_place 到达组合根 + 核心封印态落位 ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 封印受理与印记随挖消失(case④/④b)
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:52 封印受理即揭示、受理零兑付零事件(case④/④b——受理即揭示改版换代)
|
||||
_push_click(_pos(bv, seal_t), MOUSE_BUTTON_RIGHT)
|
||||
await get_tree().process_frame
|
||||
if not _has_action(seal_t, "seal_place"):
|
||||
@@ -284,6 +284,32 @@ func _ready() -> void:
|
||||
var seal_unit = bv.cells_probe().get(seal_t)
|
||||
if seal_unit == null or not seal_unit.seal_on:
|
||||
_problems.append("case④b 封印印记未下发(seal_on=%s)" % ["无单元" if seal_unit == null else str(seal_unit.seal_on)])
|
||||
# ---- case④c(V9 新增)已封印格零动作:真输入左/右键 → action_requested 零发射、光标态=禁止 ----
|
||||
# 判据出处: design/ux/battle.md Interaction Map 已封印格行——已封印格无动作(左右键同零意图)
|
||||
var acts_before_v9: int = _actions.size()
|
||||
_push_motion(_pos(bv, seal_t))
|
||||
await get_tree().process_frame
|
||||
if bv.mouse_default_cursor_shape != Input.CURSOR_FORBIDDEN:
|
||||
_problems.append("case④c 悬停已封印格光标非禁止(%d)〔封印改 V9〕" % bv.mouse_default_cursor_shape)
|
||||
if bv.cells_probe()[seal_t].face.hl_color != bv.COL_SEAL:
|
||||
_problems.append("case④c 已封印格悬停未落封印禁入框(color=%s)〔封印改 V9〕" % str(bv.cells_probe()[seal_t].face.hl_color))
|
||||
_push_click(_pos(bv, seal_t), MOUSE_BUTTON_LEFT)
|
||||
await get_tree().process_frame
|
||||
_push_click(_pos(bv, seal_t), MOUSE_BUTTON_RIGHT)
|
||||
await get_tree().process_frame
|
||||
if _actions.size() != acts_before_v9:
|
||||
_problems.append("case④c 已封印格左右键仍发射意图(新增 %d——应零发射)〔封印改 V9〕" % (_actions.size() - acts_before_v9))
|
||||
if not ms.is_revealed(seal_t):
|
||||
pass # 封印格保持未开(零副作用同源佐证)
|
||||
else:
|
||||
_problems.append("case④c 已封印格被挖开(零副作用失守)〔封印改 V9〕")
|
||||
# 悬停说明在册:图例封印行承载悬停语义说明(受理即揭示口径——ENTRIES 在册断言)
|
||||
var legend_seal_line := ""
|
||||
for e in main.ui.modals.run.legend_overlay.ENTRIES:
|
||||
if String(e[1]) == "封印":
|
||||
legend_seal_line = String(e[2])
|
||||
if not legend_seal_line.contains("受理即揭示"):
|
||||
_problems.append("case④c 悬停说明在册缺新口径(图例封印行=%s)〔封印改 V9〕" % legend_seal_line)
|
||||
# ---- case⑤ 双击 chord:禁入格双左击(核心拒挖零副作用)→ chord_attempted ----
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:236 拒绝三源可辨、任何拒绝零副作用(case⑤ chord)
|
||||
_push_click(_pos(bv, forbid_t), MOUSE_BUTTON_LEFT)
|
||||
|
||||
@@ -174,7 +174,10 @@ static func _constraints(minesweeper, board, mines: Dictionary) -> Array:
|
||||
var known := 0
|
||||
for n in board.neighbors8(c):
|
||||
if minesweeper.has_seal(n):
|
||||
known += 1
|
||||
# 封印受理即揭示:封印格身份当场可查(测量侧镜像玩家可读信息——cell_identity 板事实单点)。
|
||||
# 标中(雷)计已知雷;标空(安全格)=已完成格,剔除出约束(旧口径一律计已知雷=失真)。
|
||||
if String(board.cell_identity(n).get("kind", "")) == "mine":
|
||||
known += 1
|
||||
elif not minesweeper.is_revealed(n):
|
||||
if mines.has(n):
|
||||
known += 1
|
||||
|
||||
@@ -25,7 +25,8 @@ const BattleDriver := preload("res://sim/battle_driver.gd") # 庚案收敛:
|
||||
# ── 普通档 v3 失误注入参数(踩雷期望=完美+2/板、每板少挖几个正确格)──
|
||||
# 标雷→误挖转化率:主踩雷源=卡死赌挖(不确定性概率命中),误挖只作偶发真手滑——
|
||||
# 真人几乎不挖自己封印的格(p 过高会让首轮已证封印变保底命中,非失误形态)
|
||||
const NORMAL_MINE_SLIP_P := 0.10
|
||||
const NORMAL_MISDIG_P := 0.10 # 错触直挖率(补偿注入——用户 2026-11-07 裁③:初值承旧注入 0.10,
|
||||
# 标定目标=改前锚普通档踩雷读数量级;同批同码态锚只采一次,偏差记实现决定)
|
||||
# 安全挖跳过率:每板安全格 ~70-90 × p ≈ 3-5 次漏挖(信息与推进双损失)
|
||||
const NORMAL_SKIP_DIG_P := 0.05
|
||||
# 空闲提前赌挖率:已证安全格在手时小概率先赌一格——完美系把不确定性攒到残局
|
||||
@@ -471,7 +472,7 @@ static func _autoplay_battle(runner, settlement, st: Dictionary, logger) -> void
|
||||
# 普通策略档 v3:完美策略 + 受控失误注入(标定依据=真人实证:
|
||||
# 零加成真人首通三关踩 23 雷)。
|
||||
# v3 语义 = 会玩的普通玩家:推理与完美档同源(subset 解算/封印/卡死刷新),失误只注入两手——
|
||||
# 标雷误挖(NORMAL_MINE_SLIP_P)+ 安全挖跳过(NORMAL_SKIP_DIG_P)。连续拒绝 ≥3 = 编排违约防御。
|
||||
# 错触直挖(NORMAL_MISDIG_P——标雷误挖换代名)+ 安全挖跳过(NORMAL_SKIP_DIG_P)。连续拒绝 ≥3 = 编排违约防御。
|
||||
# 完美策略档:单步决策循环——move/dig/seal 经 排雷玩法 settle_batch 提交,
|
||||
# refresh 经 settlement.player_request_refresh(战斗结算 核心编排:行动经济 扣 RAP + 退役 + 当场换新板),
|
||||
# stop 出内环走统一停手提交。连续拒绝 ≥3 = 编排违约防御(fail-fast 语义,停手防死循环)。
|
||||
@@ -503,9 +504,11 @@ static func _action_logger(st: Dictionary, logger) -> Callable:
|
||||
st.refreshes = int(st.refreshes) + 1
|
||||
elif ok and kind == "seal_place":
|
||||
st.seal_placed = int(st.get("seal_placed", 0)) + 1 # 封印数(η 分母=全部封印数〔Q5〕;失误注入转化封印不计数=转化后实为挖)
|
||||
# 普通档 v3 失误注入:三类——
|
||||
# ①标雷误挖:把「封印已证雷」动作直接转成「挖该格」(真人手滑原型:知道是雷、位置点错,
|
||||
# 踩雷吃伤且该雷奖励报废);期望踩雷增量 ≈ 每板已证雷数 × NORMAL_MINE_SLIP_P(目标完美+2/板)
|
||||
# 普通档 v3 失误注入:三类(封印受理即揭示改版换代——①标雷误挖退役,等价补偿注入=错触直挖,
|
||||
# 用户 2026-11-07 裁③)——
|
||||
# ①错触直挖:把「封印已证雷」动作按概率转成「挖该格」(真人错触原型:判雷正确、手指落点成挖;
|
||||
# 目标格当时未封未揭——新规则下挖未封格合法可执行,踩雷吃伤吃挖掘惩罚);期望踩雷增量 ≈
|
||||
# 每板已证雷数 × NORMAL_MISDIG_P(初值承旧注入 0.10——标定目标=改前锚普通档踩雷读数量级)
|
||||
# ②安全挖跳过:把「挖已证安全格」动作转成本轮停手(少挖几个正确的雷——信息与推进双损失)
|
||||
# ③卡死赌挖:完美档无已证动作时刷新/停手拖轮次吃敌方垫刀(实证=完美档 41% 冒险成功;全败于慢玩
|
||||
# 垫刀非踩雷)——真人会按概率赌一个边界格(用户实证口径「有些地方因为我看不到数字,也是盲挖
|
||||
@@ -516,8 +519,8 @@ static func _apply_normal_slips(act: Dictionary, settlement, st: Dictionary) ->
|
||||
if prng == null:
|
||||
return act
|
||||
var kind := String(act.get("kind", "stop"))
|
||||
if kind == "seal" and prng.randf() < NORMAL_MINE_SLIP_P:
|
||||
st.mine_slips = int(st.get("mine_slips", 0)) + 1
|
||||
if kind == "seal" and prng.randf() < NORMAL_MISDIG_P:
|
||||
st.mine_slips = int(st.get("mine_slips", 0)) + 1 # 计数字段沿用 mine_slips(锚对比列对齐)
|
||||
return {"kind": "dig", "cell": act.get("cell")}
|
||||
if kind == "dig":
|
||||
var roll := prng.randf()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 126 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 124 KiB |
@@ -13,10 +13,10 @@
|
||||
## Core Mechanic
|
||||
|
||||
3. 挖掘:单格 1 AP、数字亮起与 8 邻雷数一致、连锁免费撕开一片
|
||||
4. 封印/撤封印/挪封印:AP 价目正确、连锁止于封印(封印挡链)属正常
|
||||
4. 封印:AP 价目正确、连锁止于封印(封印挡链)属正常;封印受理即揭示(落定当场见格下身份)、已封印格零动作(不可再挖开)
|
||||
5. 移动:已开格瞬移、**已引爆危险格可通行可读**(工程债呈现半边)
|
||||
6. 停手:RAP 1:1 转存、下轮 AP 硬重置同图继续
|
||||
7. 轮末结算:明细逐行呈现、来源标注可读(P2——"这一行是我哪步扫雷带来的"可答)
|
||||
7. 轮末结算:FX 链逐拍兑现(弹道/飘字/站桩反馈)可读(P2——"这一战果是我哪步扫雷带来的"可答;明细带逐行文字已退役)
|
||||
8. 清图:清图奖励兑付 + 完美封印高光(零误标时双份)+ 换新图;未刷新的停手轮不换图
|
||||
9. 轮内刷新(方案 A):Active 当场换图、AP 保留、RAP 扣减、每轮 ≤2 次、跨图事实结算完整
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ func _init() -> void:
|
||||
# ---- 末点 AP 封印轮末结算(playtest 缺陷②回归:末点 AP 花在封印必须终结轮次进入下一轮)----
|
||||
|
||||
func _smoke_seal_ap_exhausted() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/排雷循环/行动经济.md:260 (末点 AP 耗尽即收轮组)
|
||||
print("--- 排雷玩法·封印动作耗尽末点 AP 回归 ---")
|
||||
var rng = load("res://core/rng_service.gd").new()
|
||||
@@ -111,11 +112,11 @@ func _find_seal_target(minesweeper, want_mine: bool) -> Dictionary:
|
||||
|
||||
|
||||
# ---- 封印不可逆四情况冒烟(禁撤封印 + 挖封印格兑付改判)----
|
||||
# 四情况:① 插危险格不动 = 标中奖励照常;② 插危险格再挖开 = 只受挖雷一层惩罚(mine_hit 照常)标中不发;
|
||||
# ③ 插安全格不动 = 标空惩罚照常;④ 插安全格再挖开 = 零惩罚零奖励(正向兑付作废、标空不判)。
|
||||
# 四情况(封印受理即揭示改版改判〔封印改 V2〕):① 插危险格不动 = 标中奖励照常;② 插危险格再挖开 = 挖封印格被拒(零动作零惩罚);
|
||||
# ③ 插安全格不动 = 标空惩罚照常;④ 插安全格再挖开 = 挖封印格被拒(零动作——标空判定照发)。
|
||||
# 拒绝面:seal_pull 出目录(out_of_catalog);重复封印仍 seal_present 拒绝。
|
||||
# 场景 A(④ + 拒绝面):标安全格 → seal_pull 拒绝 → 重复封印拒绝 → 直接挖开 → 收轮。
|
||||
# 场景 B(②):标危险格 → 直接挖开 → 收轮。
|
||||
# 场景 A(④ 改判〔封印改 V2〕+ 拒绝面):标安全格 → seal_pull 拒绝 → 重复封印拒绝 → 挖封印格被拒 → 收轮(标空判定照发)。
|
||||
# 场景 B(② 改判〔封印改 V2〕):标危险格 → 挖封印格被拒 → 收轮(标中判定照发)。
|
||||
# 场景 C(①③):标安全格 + 标危险格 → 不挖收轮 → 标空/标中判定照常。
|
||||
|
||||
|
||||
@@ -440,6 +441,7 @@ func _smoke_refresh_provenance_guard() -> void:
|
||||
|
||||
|
||||
func _smoke_polarity_routing() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:139 封印判定批与溢价兑付链照常(保留组——封印受理即揭示改版零改动)〔封印改 V5〕
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:366 (极性路由:正向只兑正向、负向只兑负向组)
|
||||
print("--- 极性路由(挖安全格正向 / 挖危险格负向 / 标中正向 / 标空负向)---")
|
||||
@@ -572,11 +574,11 @@ func _smoke_polarity_routing() -> void:
|
||||
|
||||
|
||||
# ---- 封印不可逆四情况冒烟(禁撤封印 + 挖封印格兑付改判)----
|
||||
# 四情况:① 插危险格不动 = 标中奖励照常;② 插危险格再挖开 = 只受挖雷一层惩罚(mine_hit 照常)标中不发;
|
||||
# ③ 插安全格不动 = 标空惩罚照常;④ 插安全格再挖开 = 零惩罚零奖励(正向兑付作废、标空不判)。
|
||||
# 四情况(封印受理即揭示改版改判〔封印改 V2〕):① 插危险格不动 = 标中奖励照常;② 插危险格再挖开 = 挖封印格被拒(零动作零惩罚);
|
||||
# ③ 插安全格不动 = 标空惩罚照常;④ 插安全格再挖开 = 挖封印格被拒(零动作——标空判定照发)。
|
||||
# 拒绝面:seal_pull 出目录(out_of_catalog);重复封印仍 seal_present 拒绝。
|
||||
# 场景 A(④ + 拒绝面):标安全格 → seal_pull 拒绝 → 重复封印拒绝 → 直接挖开 → 收轮。
|
||||
# 场景 B(②):标危险格 → 直接挖开 → 收轮。
|
||||
# 场景 A(④ 改判〔封印改 V2〕+ 拒绝面):标安全格 → seal_pull 拒绝 → 重复封印拒绝 → 挖封印格被拒 → 收轮(标空判定照发)。
|
||||
# 场景 B(② 改判〔封印改 V2〕):标危险格 → 挖封印格被拒 → 收轮(标中判定照发)。
|
||||
# 场景 C(①③):标安全格 + 标危险格 → 不挖收轮 → 标空/标中判定照常。
|
||||
func _smoke_seal_irreversible_quadrants() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:231 (封印不可逆四情况组)
|
||||
@@ -600,9 +602,10 @@ func _smoke_seal_irreversible_quadrants() -> void:
|
||||
Kit.check("四情况 A:seal_pull 出目录拒绝(撤封印退役)", not pull_out.is_empty() and not bool(pull_out[0].get("accepted", true)) and String(pull_out[0].get("sub_reason", "")) == "out_of_catalog")
|
||||
var dup_place: Array = ms_a.settle_batch([{"action": "seal_place", "cell": t_a.seal_cell}])
|
||||
Kit.check("四情况 A:重复封印仍被拒(seal_present)", not dup_place.is_empty() and not bool(dup_place[0].get("accepted", true)) and String(dup_place[0].get("sub_reason", "")) == "seal_present")
|
||||
# 改判〔封印改 V2〕——「挖封印格直挖受理/隐式退役」随封印受理即揭示退役:挖已封印格被拒
|
||||
var dig_a: Array = ms_a.settle_batch([{"action": "dig", "cell": t_a.seal_cell}])
|
||||
Kit.check("四情况 A:封印格直接挖开被受理(不再须先撤封印)", not dig_a.is_empty() and bool(dig_a[0].get("accepted", false)))
|
||||
Kit.check("四情况 A:封印随挖掘隐式退役(has_seal = false)", not ms_a.has_seal(t_a.seal_cell))
|
||||
Kit.check("四情况 A:挖已封印格被拒且原因可辨(target_sealed)", not dig_a.is_empty() and not bool(dig_a[0].get("accepted", true)) and String(dig_a[0].get("sub_reason", "")) == "target_sealed")
|
||||
Kit.check("四情况 A:封印不随挖掘退役(has_seal 保持——不可再挖开)", ms_a.has_seal(t_a.seal_cell) and not ms_a.is_revealed(t_a.seal_cell))
|
||||
ms_a.settle_batch([{"action": "stop"}])
|
||||
var target_a: Array = [t_a.seal_cell.x, t_a.seal_cell.y]
|
||||
var miss_a := 0
|
||||
@@ -617,9 +620,11 @@ func _smoke_seal_irreversible_quadrants() -> void:
|
||||
grant_a += 1
|
||||
if row.get("type", "") == "reward_ineffective":
|
||||
void_a += 1
|
||||
Kit.check("四情况 A:标空判定零兑付(×%d——封印已擦除不入轮末基线)" % miss_a, miss_a == 0)
|
||||
Kit.check("四情况 A:安全格正向兑付作废(×%d——零奖励)" % grant_a, grant_a == 0)
|
||||
Kit.check("四情况 A:兑付作废归因行恰一次(×%d——零惩罚零奖励留痕)" % void_a, void_a == 1)
|
||||
# 改判〔封印改 V2〕——封印在场入轮末基线:标空判定照发(受理即揭示不改判定批);
|
||||
# miss_a 口径=seal_miss 型行或来源行(判定行+标空负向兑付行同源)
|
||||
Kit.check("四情况 A:标空判定照发(×%d——封印在轮末基线;判定行+负向兑付行同源)" % miss_a, miss_a >= 1)
|
||||
Kit.check("四情况 A:安全格正向兑付为零(×%d——封印不兑付格面资源)" % grant_a, grant_a == 0)
|
||||
Kit.check("四情况 A:零兑付作废归因行(×%d——改判路径退役无作废行)" % void_a, void_a == 0)
|
||||
# 场景 B:危险格直挖(情况②)
|
||||
var rng_b = load("res://core/rng_service.gd").new()
|
||||
rng_b.set_master_seed(20260919)
|
||||
@@ -634,9 +639,10 @@ func _smoke_seal_irreversible_quadrants() -> void:
|
||||
if t_b.hero_cell != ms_b.hero_pos():
|
||||
ms_b.settle_batch([{"action": "move", "cell": t_b.hero_cell}])
|
||||
Kit.check("四情况 B:封印受理", ms_b.settle_batch([{"action": "seal_place", "cell": t_b.seal_cell}])[0].accepted)
|
||||
# 改判〔封印改 V2〕——挖危险封印格同被拒(封印格拒绝挖掘不分极性)
|
||||
var dig_b: Array = ms_b.settle_batch([{"action": "dig", "cell": t_b.seal_cell}])
|
||||
Kit.check("四情况 B:封印危险格直接挖开被受理", not dig_b.is_empty() and bool(dig_b[0].get("accepted", false)))
|
||||
Kit.check("四情况 B:危险格已揭示(挖雷本体照常)", ms_b.is_revealed(t_b.seal_cell) and ms_b.current_board().is_mine(t_b.seal_cell))
|
||||
Kit.check("四情况 B:挖已封印危险格被拒(target_sealed)", not dig_b.is_empty() and not bool(dig_b[0].get("accepted", true)) and String(dig_b[0].get("sub_reason", "")) == "target_sealed")
|
||||
Kit.check("四情况 B:危险格未揭示(封印格零动作)", not ms_b.is_revealed(t_b.seal_cell) and ms_b.current_board().is_mine(t_b.seal_cell))
|
||||
ms_b.settle_batch([{"action": "stop"}])
|
||||
var target_b: Array = [t_b.seal_cell.x, t_b.seal_cell.y]
|
||||
var mine_hit_b := 0
|
||||
@@ -648,8 +654,9 @@ func _smoke_seal_irreversible_quadrants() -> void:
|
||||
mine_hit_b += 1
|
||||
if row.get("type", "") == "seal_hit" or String(row.get("source_class", "")) == "seal_hit":
|
||||
hit_b += 1
|
||||
Kit.check("四情况 B:挖雷惩罚照常兑付(×%d——只受挖雷一层惩罚)" % mine_hit_b, mine_hit_b >= 1)
|
||||
Kit.check("四情况 B:标中不发(×%d——封印已擦除不判)" % hit_b, hit_b == 0)
|
||||
# 改判〔封印改 V2〕——封印在场入轮末基线:标中判定照发(含溢价兑付链)
|
||||
Kit.check("四情况 B:挖雷惩罚零发生(×%d——封印格未挖)" % mine_hit_b, mine_hit_b == 0)
|
||||
Kit.check("四情况 B:标中判定照发(×%d——封印在轮末基线)" % hit_b, hit_b >= 1)
|
||||
# 场景 C:不挖收轮(①③判定照常)
|
||||
var rng_c = load("res://core/rng_service.gd").new()
|
||||
rng_c.set_master_seed(20260919)
|
||||
|
||||
@@ -420,6 +420,8 @@ var _db
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:362 (结算接线同种子逐项 golden 对拍组)
|
||||
# 判据出处: design/gdd/systems/战斗循环/战斗结算.md:134 受理零兑付、改判路径死——流水零「奖励作废(封印格直接挖开)」行、
|
||||
# 同种子驱动序 golden 实测零漂移零重录(挖封印格被拒——驱动序不含该路径)〔封印改 V6〕
|
||||
_db = ConfigDBScript.new()
|
||||
var load_ok: bool = _db.load_tables("res://data/tables", true)
|
||||
Kit.check("前置:表加载零 error", load_ok and _db.diagnostics_count("error") == 0)
|
||||
|
||||
@@ -147,9 +147,11 @@ func _smoke_adventure() -> void:
|
||||
Kit.check("生成图每个战斗/Boss 节点经解析链命中敌行集与棋盘行(扫描 %d 节点,缺失 %d)〔fv24〕" % [cov_scan, cov_miss],
|
||||
cov_scan > 0 and cov_miss == 0)
|
||||
# ② 满配冒险成功 + ④ 三层奖励兑付(三选一恰 2 次 · 回血封顶 · 钥石逐杀 · 候选零重复)
|
||||
var st: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
# 种子换代〔退役改 V7 波及面——test-conventions §5.5 同生死〕:feats.tres 删破封一击行使
|
||||
# RNG 流消费序列变,42 路线漂移为 timeout(43 实跑 completed——钉值随表行集换代)
|
||||
var st: Dictionary = autoplay.run_adventure(_db, 43, 900, 400)
|
||||
var sum: Dictionary = st["summary"]
|
||||
Kit.check("满配冒险成功(42 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)", String(st["result"]) == "completed" and bool(sum.get("cleared", false)))
|
||||
Kit.check("满配冒险成功(43 / atk+900 / hp+400——cleared=true;v2 怪阶梯后旧 200/100 档不再满配)", String(st["result"]) == "completed" and bool(sum.get("cleared", false)))
|
||||
Kit.check("完成几关 = 3(levels_cleared)", int(sum.get("levels_cleared", -1)) == 3)
|
||||
var ks_exp := 0
|
||||
for li in range(1, int(_db.run.level.rows.size()) + 1):
|
||||
@@ -157,7 +159,7 @@ func _smoke_adventure() -> void:
|
||||
Kit.check("钥石合计 = ΣBoss 首杀行值(%d——逐杀掉落新口径;断点未注入恒首杀)" % int(sum.get("keystone_total", -1)), int(sum.get("keystone_total", -1)) == ks_exp)
|
||||
var drops: Array = sum.get("keystone_drops", []) as Array
|
||||
Kit.check("逐杀掉落明细恰 3 笔(L1/L2/L3——additive 摘要键 keystone_drops)", drops.size() == 3)
|
||||
Kit.check("摘要携带主种子(42)", int(sum.get("master_seed", -1)) == 42)
|
||||
Kit.check("摘要携带主种子(43)", int(sum.get("master_seed", -1)) == 43)
|
||||
var picks: Array = []
|
||||
var resolves: Array = []
|
||||
var node_picks := 0
|
||||
@@ -274,7 +276,7 @@ func _smoke_adventure() -> void:
|
||||
seq_ok = false
|
||||
Kit.check("各战上限入参 ∈ [基础, 基础+3×件值+购血余量](覆盖值通道——双渠道共享上限 3;模拟档贪心购血合法叠加〔数值修复批 v3.4〕;首战=基础 %d)" % exp_base, seq_ok)
|
||||
# ③ 种子域可复现(同种子两局:summary + 上限序列 + 行进序列 + 三选一停点载荷逐位一致)
|
||||
var st2: Dictionary = autoplay.run_adventure(_db, 42, 900, 400)
|
||||
var st2: Dictionary = autoplay.run_adventure(_db, 43, 900, 400)
|
||||
Kit.check("同种子两局逐位可复现(summary/上限序列/行进序列/三选一载荷——reward_pick 封闭流)",
|
||||
st2["summary"] == sum and st2["encounter_max_hp_seq"] == seq
|
||||
and st2["visited_ids"] == st["visited_ids"] and st2["reward_events"] == st["reward_events"])
|
||||
@@ -465,8 +467,8 @@ func _smoke_adventure() -> void:
|
||||
func _smoke_feats() -> void:
|
||||
# 判据出处: design/gdd/systems/冒险循环/奇物.md:465 (奇物授予与凭证保底组)
|
||||
print("--- 专长重设计实装(feat_table 四级 · 专长带池接线 · 订阅面逐件)---")
|
||||
# ① 现行表牌库构成:37 件全量入池——102 数值令牌+37 relic 令牌(四级 rarity 直映射)
|
||||
Kit.check("feat_table 已加载(37 件=基础 27+迁入 2+完美保险 1+迭代 46 换图系七件——换代)", _db.crossrun.feats != null and (_db.crossrun.feats.rows as Array).size() == 37)
|
||||
# ① 现行表牌库构成:36 件全量入池(破封一击随封印受理即揭示退役〔退役改 V7〕)——102 数值令牌+36 relic 令牌(四级 rarity 直映射)
|
||||
Kit.check("feat_table 已加载(36 件=基础 27+迁入 2+完美保险 1+迭代 46 换图系七件−破封一击退役〔退役改 V7〕——换代)", _db.crossrun.feats != null and (_db.crossrun.feats.rows as Array).size() == 36)
|
||||
Kit.check("feat_table.validate 零违例(四级 rarity/cap 域/trigger 词表/行键白名单全过)", _db.crossrun.feats.validate().is_empty())
|
||||
var a_r0 = load("res://core/adventure_runner.gd").new(_db, _fresh_rng(71))
|
||||
Kit.check("专长带场景:冒险启动(seed 71)", a_r0.start_adventure(71))
|
||||
@@ -477,7 +479,7 @@ func _smoke_feats() -> void:
|
||||
feat_tokens += 1
|
||||
var tk := String((t as Dictionary).get("tier", ""))
|
||||
tier_counts[tk] = int(tier_counts.get(tk, 0)) + 1
|
||||
Kit.check("专长带入池:37 件四级直映射(普通 14/优秀 13/稀有 10/传说 0)——牌库 102+37=139〔专长批 V2+迭代 46 换图系七件换代〕", feat_tokens == 37 and int(tier_counts.get("common", 0)) == 14 and int(tier_counts.get("excellent", 0)) == 13 and int(tier_counts.get("rare", 0)) == 10 and a_r0.deck().deck.size() == 139)
|
||||
Kit.check("专长带入池:36 件四级直映射(普通 14/优秀 12/稀有 10/传说 0)——牌库 102+36=138〔专长批 V2+迭代 46 换图系七件换代−破封一击退役〕", feat_tokens == 36 and int(tier_counts.get("common", 0)) == 14 and int(tier_counts.get("excellent", 0)) == 12 and int(tier_counts.get("rare", 0)) == 10 and a_r0.deck().deck.size() == 138)
|
||||
# ② 旧 27 件零残留钉面(V2——arcane_ember 系旧件表首行;全仓 grep 零残留归静态核查)
|
||||
Kit.check("旧 27 件已退役:arcane_ember/magma_body 表内零残留〔专长批 V2〕", _db.crossrun.feats.row_by_id("arcane_ember").is_empty() and _db.crossrun.feats.row_by_id("magma_body").is_empty())
|
||||
Kit.check("迁出收尾:treasure_items 无 venom_edge/seal_burst 行(同调目录自然收窄)〔专长批 V13〕", _db.crossrun.treasure_items.row_by_id("venom_edge").is_empty() and _db.crossrun.treasure_items.row_by_id("seal_burst").is_empty())
|
||||
@@ -717,11 +719,7 @@ func _smoke_feats() -> void:
|
||||
Kit.check("背水:生命≤50% 减伤·过半血反例零减伤〔专长批 V3〕",
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 1, "hp_ratio": 40}), "damage_reduce").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "damage_taken", {"kind": "enemy_skill", "amount": 5, "source": "s", "round": 2, "hp_ratio": 80}), "damage_reduce").is_empty())
|
||||
# 跨族桥
|
||||
fx.rebuild(["breaker_strike"], [], {})
|
||||
Kit.check("破封一击:挖开带封印危险格 +1 层·无封印反例零触发〔专长批 V3〕",
|
||||
_hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": true}), "counter_add").size() == 1
|
||||
and _hits_kind(fx.dispatch(orch.fx_host().counters_ctx, "mine_hit", {"dug_under_seal": false}), "counter_add").is_empty())
|
||||
# 跨族桥(破封一击随封印受理即揭示改版退役——dug_under_seal 事实词除名,改判路径不存在〔封印改 V7〕)
|
||||
# 节奏系
|
||||
fx.rebuild(["map_exchange"], [], {})
|
||||
var me_hits: Array = fx.dispatch(orch.fx_host().counters_ctx, "dig_stop", {"ap_left": 4})
|
||||
|
||||
@@ -21,10 +21,12 @@ func _init() -> void:
|
||||
Kit.check_quiet(EffectEngineScript.EFFECT_KINDS.has("grant_reserve_ap") and EffectEngineScript.EFFECT_KINDS.has("apply_discount"),
|
||||
"换图系新效果在册:grant_reserve_ap/apply_discount〔换图系批 V1〕")
|
||||
Kit.check_quiet(EffectEngineScript.FACTS.has("hp_ratio") and EffectEngineScript.FACTS.has("is_edge_cell")
|
||||
and EffectEngineScript.FACTS.has("new_resource_type") and EffectEngineScript.FACTS.has("dug_under_seal")
|
||||
and EffectEngineScript.FACTS.has("new_resource_type")
|
||||
and EffectEngineScript.FACTS.has("ap_exhausted_last") and EffectEngineScript.FACTS.has("ap_left")
|
||||
and EffectEngineScript.FACTS.has("is_blank_zero") and EffectEngineScript.FACTS.has("amount"),
|
||||
"新事实在册:hp_ratio/is_edge_cell/new_resource_type/dug_under_seal/ap_exhausted_last/ap_left/is_blank_zero/amount〔专长批 V1〕")
|
||||
"新事实在册:hp_ratio/is_edge_cell/new_resource_type/ap_exhausted_last/ap_left/is_blank_zero/amount〔专长批 V1——dug_under_seal 随破封一击退役除名,退役改 V7〕")
|
||||
Kit.check_quiet(not EffectEngineScript.FACTS.has("dug_under_seal"),
|
||||
"退役事实词出册:dug_under_seal(改判路径退役——词表除名防回潮)〔退役改 V7〕")
|
||||
Kit.check_quiet(EffectEngineScript.EFFECT_KINDS.has("heal") and EffectEngineScript.EFFECT_KINDS.has("ac_bonus")
|
||||
and EffectEngineScript.EFFECT_KINDS.has("damage_reduce") and EffectEngineScript.EFFECT_KINDS.has("bonus_delta")
|
||||
and EffectEngineScript.EFFECT_KINDS.has("blast_scaled") and EffectEngineScript.EFFECT_KINDS.has("preview_area")
|
||||
|
||||
@@ -42,6 +42,10 @@ func _init() -> void:
|
||||
_test_seal_place()
|
||||
_test_reject_out_of_catalog()
|
||||
_test_preview_reveal_readonly()
|
||||
_test_seal_reveal_identity()
|
||||
_test_dig_sealed_rejected()
|
||||
_test_clear_by_seal()
|
||||
_test_classify_seal_clears()
|
||||
quit(Kit.finish("minesweeper_rules_test"))
|
||||
|
||||
|
||||
@@ -133,12 +137,15 @@ func _test_preview_reveal_readonly() -> void:
|
||||
Kit.check("V14 形态A:preview 返回集(真板形态——%d 格)" % prev_a.size(), prev_a.size() >= 0)
|
||||
Kit.check("V14 形态A:调用前后零状态写入(revealed/seal 计数零变化)〔架构整改 V14〕",
|
||||
_rules.revealed_cells().size() == before_revealed and _rules.seal_count() == before_seals)
|
||||
# 形态 B:挖封印格——本格封印隐式退役只入模拟集,真实封印计数不动
|
||||
# 形态 B(改判〔封印改 V14B〕——挖封印格隐式退役前提随「封印受理即揭示」退役):
|
||||
# preview(封印格) 连锁不越封印——封印格自身零外扩返回空集,真实封印计数不动
|
||||
var seal_c := _unrevealed_safe()
|
||||
_rules.settle_batch([{"action": "seal_place", "cell": seal_c}])
|
||||
var sealed_before := _rules.seal_count()
|
||||
var prev_b: Array = _rules.preview_reveal(seal_c)
|
||||
Kit.check("V14 形态B:preview(封印格) 零状态写入(seal_count 不变——隐式退役只入模拟集)〔架构整改 V14〕",
|
||||
Kit.check("V14 形态B:preview(封印格) 零外扩(连锁不越封印——返回空集 %d 格)〔封印改 V14B〕" % prev_b.size(),
|
||||
prev_b.is_empty())
|
||||
Kit.check("V14 形态B:preview(封印格) 零状态写入(seal_count 不变)〔封印改 V14B〕",
|
||||
_rules.seal_count() == sealed_before)
|
||||
# 同口径对照:preview(c) = settle_batch(dig c) 后 revealed 差集 ∖ {c}(F2——不含首格与已开格)
|
||||
var dig_c := _unrevealed_safe()
|
||||
@@ -159,3 +166,163 @@ func _test_preview_reveal_readonly() -> void:
|
||||
var _pc: Array = _rules.preview_reveal(_unrevealed_safe())
|
||||
Kit.check("V14 零事件:preview 全程 cell_revealed 零发射(前后增量 0——实测 %d→%d)〔架构整改 V14〕" % [events_before_previews, events],
|
||||
events == events_before_previews)
|
||||
|
||||
# 未完成安全格集(清图口径=已挖∪已封印——未揭且未封;V3 阶段c/V4 夹具扫描口)
|
||||
func _incomplete_cells() -> Array:
|
||||
var out: Array = []
|
||||
for c in _board.safe_cells():
|
||||
if not _rules.is_revealed(c) and not _rules.has_seal(c):
|
||||
out.append(c)
|
||||
return out
|
||||
|
||||
|
||||
# 新板重装夹具(V3 阶段c/V4 干净局面——IDLE 装板→round_start 进 ACTIVE;封印/揭示随装板重置)
|
||||
func _fresh_board(seed_v: int) -> void:
|
||||
_ae._phase = 0 # Phase.IDLE——夹具直置(前置相位可能处 ACTIVE:fx_reveal 不经行动经济不收轮;notify_combat_end 相位守卫拒 ACTIVE)
|
||||
var rng := RngServiceScript.new()
|
||||
rng.set_master_seed(seed_v)
|
||||
rng.new_adventure(seed_v)
|
||||
_board = BoardGeneratorScript.new().generate(1, 0, rng.open_stream("board_gen"), _db)
|
||||
_rules.install_board(_board)
|
||||
_ae.notify_round_start()
|
||||
|
||||
|
||||
# ---- 封印受理即揭示改版(迭代 56 封印动作改版批 V1–V4——身份可查/挖封印格被拒/清图口径/批次语义序)----
|
||||
|
||||
# 未揭示且未封印的安全格(V1-V4 夹具对象选择口——排除已封印格)
|
||||
func _unrevealed_unsealed_safe() -> Vector2i:
|
||||
for c in _board.safe_cells():
|
||||
if not _rules.is_revealed(c) and not _rules.has_seal(c):
|
||||
return c as Vector2i
|
||||
return Vector2i(-1, -1)
|
||||
|
||||
|
||||
# V1 封印受理即揭示:身份当场可查(sealed_identity 与板事实逐位一致)、受理零事件零兑付
|
||||
func _test_seal_reveal_identity() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:52 封印受理那一刻身份当场可见、受理当场零兑付零事件
|
||||
_ae.grant_ap(20)
|
||||
_rules.seal_range_free = true
|
||||
var safe_c := _unrevealed_unsealed_safe()
|
||||
var events := 0
|
||||
_rules.cell_revealed.connect(func(_evt): events += 1) # 受理零事件哨兵
|
||||
var events_before := events
|
||||
_rules.settle_batch([{"action": "seal_place", "cell": safe_c}])
|
||||
Kit.check("V1 前提:安全格封印受理", _rules.has_seal(safe_c))
|
||||
# 身份揭示拼装(用户裁 2026-11-08 上限保持 20——sealed_identity 撤出 rules,
|
||||
# 身份事实=BoardData.cell_identity、封印态=has_seal,两段各归其主)
|
||||
Kit.check("V1 安全格封印身份 kind=safe 且 digit=板数字逐位一致(%s vs %d)〔封印改 V1〕" % [str(_board.cell_identity(safe_c).get("kind", "")), _board.digit_of(safe_c)],
|
||||
_rules.has_seal(safe_c) and String(_board.cell_identity(safe_c).get("kind", "")) == "safe"
|
||||
and int(_board.cell_identity(safe_c).get("digit", -9)) == _board.digit_of(safe_c))
|
||||
Kit.check("V1 受理零事件:cell_revealed 零发射(%d→%d)〔封印改 V1〕" % [events_before, events],
|
||||
events == events_before)
|
||||
# 危险格封印身份:找未开危险格封印 → kind=mine
|
||||
var mine_c := Vector2i(-1, -1)
|
||||
for c in _board.all_cells():
|
||||
if _board.is_mine(c) and not _rules.is_revealed(c) and not _rules.has_seal(c):
|
||||
mine_c = c
|
||||
break
|
||||
if mine_c != Vector2i(-1, -1):
|
||||
_rules.settle_batch([{"action": "seal_place", "cell": mine_c}])
|
||||
Kit.check("V1 危险格封印身份 kind=mine〔封印改 V1〕",
|
||||
_rules.has_seal(mine_c) and String(_board.cell_identity(mine_c).get("kind", "")) == "mine")
|
||||
Kit.check("V1 身份事实与揭示态独立:未封印格 has_seal=false 但身份可查(板事实恒在)〔封印改 V1〕",
|
||||
not _rules.has_seal(_unrevealed_unsealed_safe())
|
||||
and not _board.cell_identity(_unrevealed_unsealed_safe()).is_empty())
|
||||
|
||||
|
||||
# V2 挖已封印格被拒:原因可辨 target_sealed、封印/揭示/AP 三态零变化
|
||||
func _test_dig_sealed_rejected() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:56 动作合法性表——挖的拒绝情形含已封印
|
||||
var sealed_c := Vector2i(-1, -1)
|
||||
for c in _board.all_cells():
|
||||
if _rules.has_seal(c) and not _rules.is_revealed(c):
|
||||
sealed_c = c
|
||||
break
|
||||
Kit.check("V2 前提:已封印未开格在板", _rules.has_seal(sealed_c) and not _rules.is_revealed(sealed_c))
|
||||
_rules.dig_range_bonus = 99 # 夹具免邻接(公开属性直置——seal_range_free 先例同款;挖掘射程非判据面)
|
||||
_ae.grant_ap(20)
|
||||
var ap_before: int = _ae._ap
|
||||
var out: Array = _rules.settle_batch([{"action": "dig", "cell": sealed_c}])
|
||||
var o: Dictionary = (out[0] as Dictionary) if not out.is_empty() else {}
|
||||
Kit.check("V2 挖封印格被拒且原因可辨(sub_reason=target_sealed——实测 %s)〔封印改 V2〕" % String(o.get("sub_reason", "")),
|
||||
String(o.get("outcome", "")) == "rejected" and String(o.get("sub_reason", "")) == "target_sealed")
|
||||
Kit.check("V2 拒绝零副作用:封印态/揭示态/AP 三态零变化〔封印改 V2〕",
|
||||
_rules.has_seal(sealed_c) and not _rules.is_revealed(sealed_c) and _ae._ap == ap_before)
|
||||
_rules.dig_range_bonus = 0 # 还原射程(后续夹具不吃豁免)
|
||||
|
||||
|
||||
# V3 清图口径换代:封印可完成清图(封掉最后安全格→cleared 收束);非末封印不清图
|
||||
func _test_clear_by_seal() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:139 清图=全部安全格完成,完成=挖开或封印
|
||||
_ae.grant_ap(20)
|
||||
_rules.seal_range_free = true
|
||||
# 阶段 a:封一张非末安全格 → clear_map_cleared 仍 false(封印计入完成但未清完)
|
||||
var seal_c := _unrevealed_unsealed_safe()
|
||||
_rules.settle_batch([{"action": "seal_place", "cell": seal_c}])
|
||||
Kit.check("V3 阶段a 前提:封印受理", _rules.has_seal(seal_c))
|
||||
Kit.check("V3 阶段a:非末封印后清图未达成(clear_map_cleared=false)〔封印改 V3〕",
|
||||
not _rules.clear_map_cleared())
|
||||
# 阶段 b:fx_reveal 除 seal_c 外全部未完成安全格 → 唯一未完成格=已封印的 seal_c → 封印计入完成
|
||||
for c in _board.safe_cells():
|
||||
if c != seal_c and not _rules.is_revealed(c) and not _rules.has_seal(c):
|
||||
_rules.fx_reveal(c)
|
||||
Kit.check("V3 阶段b:唯一未完成格=已封印格 → clear_map_cleared=true〔封印改 V3〕",
|
||||
_rules.clear_map_cleared())
|
||||
# 阶段 c:另起干净新板——逐格封至清图(每封一批次真实入口):非末封零 round_end、
|
||||
# 末封恰发一条 path_tag=cleared 的轮末事件(封印后清图判定触发——轮末事件 carry 清图)
|
||||
_fresh_board(81003)
|
||||
_ae.grant_ap(60)
|
||||
_rules.seal_range_free = true
|
||||
var end_seen: Array = []
|
||||
_rules.round_end_board.connect(func(p): end_seen.append(String(p.get("path_tag", ""))))
|
||||
var guard := 0
|
||||
while not _rules.clear_map_cleared() and guard < 200:
|
||||
guard += 1
|
||||
var t: Vector2i = _incomplete_cells()[0] if not _incomplete_cells().is_empty() else Vector2i(-1, -1)
|
||||
if t == Vector2i(-1, -1):
|
||||
break
|
||||
_rules.settle_batch([{"action": "seal_place", "cell": t}])
|
||||
Kit.check("V3 阶段c:逐格封至清图达成(%d 封——封印可完成清图)〔封印改 V3〕" % guard,
|
||||
_rules.clear_map_cleared())
|
||||
Kit.check("V3 阶段c:清图收束恰一次且 path_tag=cleared(round_end 序列=%s)〔封印改 V3〕" % str(end_seen),
|
||||
end_seen.size() == 1 and String(end_seen[0]) == "cleared")
|
||||
|
||||
|
||||
# V4 批次语义序:同批「停手 + 能清图的封」提交 → 赢家=清图收束而非停手
|
||||
func _test_classify_seal_clears() -> void:
|
||||
# 判据出处: design/gdd/systems/排雷循环/排雷玩法.md:167 最先=能清图的挖或封——防耗尽优先把清图高光结算成最差结局
|
||||
# 收敛未完成格到恰 1 格(封它即清图;fx_reveal 连锁不可控——逐格揭至剩 1,连锁越格则换种子重试)
|
||||
var left: Array = []
|
||||
var last_c := Vector2i(-1, -1)
|
||||
for seed_i in range(3):
|
||||
_fresh_board(81004 + seed_i)
|
||||
_ae.grant_ap(60)
|
||||
_rules.seal_range_free = true
|
||||
left = _incomplete_cells()
|
||||
var guard2 := 0
|
||||
while left.size() > 1 and guard2 < 400:
|
||||
_rules.fx_reveal(left[0])
|
||||
left = _incomplete_cells()
|
||||
guard2 += 1
|
||||
if left.size() == 1:
|
||||
last_c = left[0]
|
||||
break
|
||||
Kit.check("V4 前提:未完成格收敛到恰 1 格(实测 %d——封它即清图)" % left.size(),
|
||||
left.size() == 1)
|
||||
if left.size() != 1:
|
||||
quit(Kit.finish("minesweeper_rules_test"))
|
||||
return
|
||||
var intents: Array = [{"action": "stop"}, {"action": "seal_place", "cell": last_c}]
|
||||
# 同批「停手+能清图的封」:末格封 cls 0 最先执行→cleared 收轮;stop cls 1 voided
|
||||
var end_seen: Array = []
|
||||
_rules.round_end_board.connect(func(p): end_seen.append(String(p.get("path_tag", "")))) # append 捕获引用(lambda 内重绑定不回写)
|
||||
var outcomes: Array = _rules.settle_batch(intents)
|
||||
Kit.check("V4 赢家=清图封:round_end path_tag=cleared 而非 stopped(round_end 序列=%s)〔封印改 V4〕" % str(end_seen),
|
||||
end_seen.size() == 1 and String(end_seen[0]) == "cleared")
|
||||
Kit.check("V4 清图封印受理(末格 %s 在封印态)〔封印改 V4〕" % str(last_c), _rules.has_seal(last_c))
|
||||
# outcomes 按执行序承载(cls 升序)——赢家=cls 0 的清图封居首;stop 与非末封在其后 voided
|
||||
var o_winner: Dictionary = (outcomes[0] as Dictionary) if not outcomes.is_empty() else {}
|
||||
Kit.check("V4 末格封意图受理(batch 赢家=清图封居执行序首——实测 %s)〔封印改 V4〕" % String(o_winner.get("outcome", "")),
|
||||
String(o_winner.get("outcome", "")) == "executed")
|
||||
Kit.check("V4 其余意图 voided(清图收轮后批次余项作废)〔封印改 V4〕",
|
||||
outcomes.size() >= 2 and String((outcomes[outcomes.size() - 1] as Dictionary).get("outcome", "")) == "voided")
|
||||
@@ -18,6 +18,11 @@ func check(cond: bool, msg: String) -> void:
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
# 判据出处: design/engineering/test-conventions.md:56 (判定上报通道——验证函数组)
|
||||
_smoke_settle_zero_rows()
|
||||
|
||||
|
||||
func _smoke_settle_zero_rows() -> void:
|
||||
# 判据出处: design/gdd/08-Alpha版本标准.md:154 战斗演出链(弹道 / 受击 / 血条 / 灰化)在役;
|
||||
# 逐行结算排播行已随 v1.29 退役——结算期 B 区零逐行文字、FX 排播链保持
|
||||
var main: Node = load("res://presentation/main.tscn").instantiate()
|
||||
|
||||
@@ -27,7 +27,8 @@ func _test_reject_text_by_reason() -> void:
|
||||
var cases := {
|
||||
"not_adjacent": "不能执行:目标与小人不相邻",
|
||||
"target_revealed": "不能执行:目标已开",
|
||||
"seal_present": "不能封印:此格已有封印印记(封印为一次性承诺——相邻时左键直接挖开)",
|
||||
"seal_present": "不能封印:此格已有封印印记(封印受理即揭示——印记随图存续)",
|
||||
"target_sealed": "不能挖:此格已封印(封印受理即揭示——不可再挖开)",
|
||||
}
|
||||
var bad: Array[String] = []
|
||||
for sub in cases:
|
||||
|
||||
@@ -76,7 +76,10 @@ func _sweep_legend() -> void:
|
||||
seal_row = e
|
||||
break
|
||||
Kit.check("图例封印行含「标空」(u4——与「标中」成对)〔wa5〕", String(seal_row[2] if seal_row.size() > 2 else "").contains("标空"))
|
||||
Kit.check("图例封印行含「受挖掘惩罚」(u4 雷字清零换代)〔wa5〕", String(seal_row[2] if seal_row.size() > 2 else "").contains("受挖掘惩罚"))
|
||||
# 文案换代〔封印改 V10〕——图例封印行新口径:受理即揭示、已封印格零动作(旧「受挖掘惩罚」句随改判路径退役)
|
||||
Kit.check("图例封印行含「受理即揭示」且零雷字(u4 清零换代〔封印改 V10〕)〔wa5〕",
|
||||
String(seal_row[2] if seal_row.size() > 2 else "").contains("受理即揭示")
|
||||
and not String(seal_row[2] if seal_row.size() > 2 else "").contains("雷"))
|
||||
for w in ["插错", "挖雷"]:
|
||||
Kit.check("图例封印行零「%s」〔wa5〕" % w,
|
||||
not String(seal_row[2] if seal_row.size() > 2 else "").contains(w))
|
||||
|
||||
@@ -14,6 +14,7 @@ func _init() -> void:
|
||||
_test_param_values()
|
||||
_test_shader_uniforms()
|
||||
_test_fog_gate()
|
||||
_test_seal_on_revealed_visible()
|
||||
quit(Kit.finish("seal_mark_params_test"))
|
||||
|
||||
|
||||
@@ -54,3 +55,16 @@ func _test_fog_gate() -> void:
|
||||
u.seal_on = false
|
||||
Kit.check("撤 seal_on 即撤子件〔seal批 V4〕", u._seal_layer == null)
|
||||
u.free()
|
||||
|
||||
|
||||
# R8 新组合态:seal_on 与已揭示同真时印记子件仍可见(封印受理即揭示改版——印记可见性不依赖
|
||||
# 揭示态;内部字段直查=受控例外同 _test_fog_gate——子件可见性无公开可观测面,对照表随行申报)
|
||||
func _test_seal_on_revealed_visible() -> void:
|
||||
# 判据出处: design/ux/battle.md「封印格呈现预览」受理即揭示——印记承载面换代(已揭示格承载合法)
|
||||
var u: Node2D = CELL_UNIT.new()
|
||||
u.seal_on = true
|
||||
Kit.check("R8 前提:seal_on 挂封印子件〔封印改 V8〕", u._seal_layer != null)
|
||||
u.fog_state = 0
|
||||
Kit.check("R8 新组合态:seal_on 与揭示同真印记仍可见(非雾态——承载面不因揭示态撤印)〔封印改 V8〕",
|
||||
u._seal_layer != null and u._seal_layer.visible == true)
|
||||
u.free()
|
||||
@@ -0,0 +1,46 @@
|
||||
# 迭代 56 代拍板追认单
|
||||
|
||||
> 2026-11-08 汇总(实现批代拍板随 commit 留痕,本单逐条呈用户追认——超白名单事项另见「实现决定记录」)。
|
||||
|
||||
## 卡1 白名单内代拍板(需求卡片-结算期文字列表退役批 §12)
|
||||
|
||||
| # | 白名单项 | 实际裁决 | 落点 |
|
||||
|---|---|---|---|
|
||||
| 1 | 新增测试函数命名与落点 | `battle_log_zero_text_test.gd`(presentation/)、`playtest_logger_step_fields_test.gd`(presentation/)、`reward_ineffective_reason_test.gd`(battle_settlement/)、`tools/analyze_parity_check.py`——全落卡内 §7 指定目录 | f0390714/T2/T3 提交 |
|
||||
| 2 | battle_log_view 去留二选一 | **选「只留摘要位」**:视图壳/摘要位/append_bb 叙述行/set_mode 保留;逐行流与行格式化域(_fmt_*/AGG 聚合/_round_rows)删净。整体退役分支否决原因=五处冒险叙述行无处可迁(迁置=改呈现面超卡) | f0390714 |
|
||||
| 3 | reason 四枚举键写法 | 照现役 _emit_row extra 模式**字面量直写**六发射点(零新 helper 零新常量);取值 full_layers/full_hp/no_enemy_alive/hero_down | T2 提交 |
|
||||
|
||||
## 卡2 白名单内代拍板(需求卡片-封印动作改版批 §11)
|
||||
|
||||
| # | 白名单项 | 实际裁决 | 落点 |
|
||||
|---|---|---|---|
|
||||
| 1 | 拒绝原因英文串定名 | `target_sealed`(保持卡串,零拼写微调) | 2d8a4d07 |
|
||||
| 2 | 拒绝/悬停 toast 与图例最终措辞 | seal_present 句「不能封印:此格已有封印印记(封印受理即揭示——印记随图存续)」;target_sealed 新句「不能挖:此格已封印(封印受理即揭示——不可再挖开)」;图例封印行「封印印记(受理即揭示——落定当场可见格下身份,随图存续不能拔)——轮末自动判定标中/标空;已封印格零动作(不可再挖开)」;提示条「左键 挖掘 / 移动 · 右键 封印(受理即揭示·不可逆)」 | T3 提交 |
|
||||
| 3 | 测试函数命名与断言组织 | 对照表点名函数名全数照用(_test_seal_reveal_identity/_test_dig_sealed_rejected/_test_clear_by_seal/_test_classify_seal_clears/_test_seal_on_revealed_visible);V14 形态 B 改判与 V9 case④c 为申报内改判的组织细节 | 2d8a4d07/T4 提交 |
|
||||
| 4 | 色牌/装饰渲染细节 | 取现行 ui_kit/art-bible 现行值(COL_FLOOR/COL_BRICK/SealMarkLayer 参数化),零新常量 | T3 提交 |
|
||||
| 5 | sim 补偿注入形态与常量初值 | 形态=「错触直挖」(封印已证雷意图按概率转同格挖——目标未封未揭,新规则下合法路径);初值 NORMAL_MISDIG_P=0.10(承旧注入 0.10——同构期望);计数字段沿用 mine_slips(锚对比列对齐)。**偏差读数已回填**:改前代码现跑踩雷 6.48/局 → 新锚 5.40/局(-1.08——含策略对齐合成效应非纯注入贡献;注入触发单局实测 slips=5) | T6 提交+实现报告 §四 |
|
||||
| 6 | mac golden 缺件处理 | mac 三件缺件记遗留(渲染闸 SKIP 不判红——T7 预案兑现) | T7 提交 |
|
||||
|
||||
## 实现决定记录(白名单外,凭规约条款自判——逐条列备案)
|
||||
|
||||
| # | 事项 | 判据与依据 | 落点 |
|
||||
|---|---|---|---|
|
||||
| 1 | **sealed_identity 落位重设计**(撤出 minesweeper_rules、BoardData 新增 cell_identity) | 用户裁决 2026-11-08「上限保持 20」覆盖卡2 §12 宿主指定;预检失实根因=写卡段「远低于 20」凭印象未实跑(基线恰 20 贴线);停机呈报后用户裁「你自己重新设计」 | T1b 提交 |
|
||||
| 2 | **S13 三条新违规拆 helper 修净**(_classify_seal/_seal_face_reject 私有 helper) | 卡2 §14「预期只降不升」+gdstyle「新码须修到基线口径内」——非阈值修订非基线新增,合规修复 | T1a 提交 |
|
||||
| 3 | **feat_vouchers_test A12 断言退役改写**(_format_row 不在位防回潮断言) | 申报外波及面;test-conventions §5.5 换代同生死(旧文案呈现路径摘除=断言对象退役);替代断言=退役态防回潮 | T1 提交 |
|
||||
| 4 | **pacing_queue_test 断言②改判**(「末行原文在明细带」→FX 链承接 _assert_fx_chain) | 卡1 §10 申报面(:108-120 文字呈现部分)——改写为退役后正向断言,FX 计数从行集独立推导(不镜像实现) | T1 提交 |
|
||||
| 5 | **theme_projection_test 行协议闸改写**(9 类逐型 FX 落拍闸) | 同 §5.5——格式化域摘除后盲区检测法(解析文本增长)等价迁移为落拍计数增长;原防「格式化炸结算段」的闸价值保留 | T1 提交 |
|
||||
| 6 | **ui_click_probe wr1-b 反转+开场行判定面换代**(最新行本体判定) | T1 波及(clear 移除破坏「全文本计数」判定前提+摘要功能退役使 wr1-b 语义反转)——断言意图保留、判定面换代 | f0390714 |
|
||||
| 7 | **adventure_feats_test 满配种子 42→43+表行数 37→36 判值换代** | feats 删行使 RNG 流消费序列变,42 路线漂移为 timeout(主区基线 42 绿对照坐实非行为回归);§5.5 同生死——种子钉值绑旧表行集 | T2+T5 提交 |
|
||||
| 8 | **ui_click_probe 行为②随机撤封印段摘除** | 卡2 T4 点名「行为②撤封印死路段清理」——申报内 | T4 提交 |
|
||||
| 9 | **R6 golden 实测零漂移零重录** | settlement_wiring_snapshot 内嵌 golden 在「挖+封+停」驱动序下与改前逐位一致(驱动序不含挖封印格——T1 后该路径被拒)——重录义务免除,读数绿在案 | T2 验收 |
|
||||
| 10 | **卡1 R4 判读等价基线快照重出**(改前分析器经 git show 提取补丁件跑出完整快照) | T0 落盘的历史锚快照被 head 管道 SIGPIPE 截断(60 行截断)——R4 读数①②需完整改前基线;改前分析器(master 字节)跑出 3394/149 行快照替换,sim-data 留盘 | T3 提交 |
|
||||
| 11 | **ui_probe:133-135 与 ui_click_probe:423/:473/:616/:798-844 零改动** | 卡1 §10 申报清单列名面实况核查:不依赖退役面(:133-135 读 pending_rows 与尺寸;:423/:473 savesel 段无 battle_log 引用;:616 全文本判首个冒险无残留仍安全)——无文字断言可改写=零改动 | 实现报告对照表登记 |
|
||||
|
||||
## 体验验证清单登记项(真人目检——登记不阻塞,实机目检后由用户销项)
|
||||
|
||||
1. 结算期 B 区零逐行文字(FX 排播链仍逐拍演出)——卡1 R1 体验面
|
||||
2. 伤害飘字/弹道/站桩反馈在新排播形态下的观感——卡1 R2 体验面
|
||||
3. 封印受理瞬间揭示的观感(地板+身份字形+法阵叠加)——卡2 R8 体验面
|
||||
4. 封印格悬停禁字与图例新句——卡2 R9/R10 体验面
|
||||
5. 清图高光在封印完成清图时触发——卡2 R3 体验面
|
||||
@@ -0,0 +1,28 @@
|
||||
# 迭代 56 反哺点清单
|
||||
|
||||
> 2026-11-08 采集(实现批产出——设计权威文档实现批禁写,逐条经用户裁决后由文档批落文)。
|
||||
> 卡2 预期零反哺点(设计面前置闭合)兑现:封印改版的设计条款无差异发现;下列各条全部来自卡1(逐行文字退役)与开工检查发现。
|
||||
|
||||
## 卡1 反哺点(结算期文字列表退役批)
|
||||
|
||||
| # | 文档与位置 | 现行句的问题 | 建议改写方向 | 依据 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | design/ux/battle.md:200(B 区组件表「结算明细带」行) | 「结算期逐行流水(9 类行协议);挖掘期收起为上轮摘要 1 行」——逐行流水已退役,现行句描述已不存在的呈现 | 明细带行改写为退役后形态:挖掘期摘要位+叙述行承载;逐行流水行删除或标注已退役(对照 08-Alpha v1.29 删「逐行结算排播」行的口径) | 卡1 §6 同步面(原卡锚 :199 漂移至此);用户裁定 2026-11-07 撤逐行滚动文字列表 |
|
||||
| 2 | design/ux/battle.md:364(交互矩阵「结算阶段」行) | 「明细带按结算期档展开(高读 log_band_h_settle)逐行滚动」——逐行滚动已退役 | 改写为:明细带 settle 展开保留(空带+叙述行),删除「逐行滚动」表述 | 同上;实现实况=set_mode 保留双态、settle 态零逐行内容 |
|
||||
| 3 | design/ux/battle.md:439(减动效选项行动效列) | 「动效:结算逐行兑现为信息载体不可整体跳过,可加倍」——「逐行兑现为信息载体」的文字承载面已退役 | 保留「演出不可整体跳过」语义,删除「为信息载体」措辞(FX 排播链仍是兑现呈现,非文字信息载体) | 卡1 R2 判据锚实际指向此行;FX 链退役文字后仍是演出载体 |
|
||||
| 4 | design/gdd/systems/表现与支撑/HUD框架.md:272 | 「结算逐行实时滚出且每行带来源标注;未生效类行聚合计数并带形状冗余;零值行不被吞」——逐行滚出与聚合计数均已随明细带退役 | 改写为:结算演出链逐行兑现(FX 载体);明细带行删除;「零值行不被吞」语义迁日志面(step 行零删减) | 卡1 R1 退役面;theme_projection 行协议闸改写后的实际形态 |
|
||||
| 5 | design/gdd/systems/战斗循环/战斗结算.md:87 | 「显示名等玩家可见文案是数据面字段:文案值登记在数据表行,代码按来源类别与效果身份读表拼行」——行协议保留 display_name(呈现面消费),但日志消费端已零文案 | 补一句消费端边界:日志落盘零文案(text/display_name 不落盘),文案仅呈现面消费 | 卡1 T2 落地实况;卡1 §6 已列此文档 |
|
||||
| 6 | design/gdd/systems/战斗循环/战斗结算.md:80 附近 | 「奖励未生效行」行型的产生面变化:封印作废行(封印格直接挖开)随改判路径退役——未生效行只剩四类(满层/满血/无存活敌人/主角已倒下),且带结构化 reason 键 | 未生效行清单换代(四类+reason 结构化说明);封印作废行除名 | 卡1 T2+卡2 T2(grant_segment:103 作废行块删除) |
|
||||
| 7 | design/gdd/systems/战斗循环/战斗表现.md:53/:99/:149 | 「结算逐行兑现是信息载体」「能说出这一行来自哪步操作」等句——文字行退役后兑现载体=FX 链 | 三处「逐行兑现」措辞按 FX 载体口径改写 | 卡1 §6 已列 |
|
||||
| 8 | design/gdd/08-Alpha版本标准.md:42 | 「战斗表现……Alpha 判据=受击闪白/死亡不瞬间消失/高光行/逐行排播四条可读」——「逐行排播」残留(v1.29 只删了「逐行结算排播」独立行,战斗表现条目的判据句漏改) | 判据句删「逐行排播」或改「演出链兑现可读」 | 开工检查发现(v1.29→v1.30 版本漂移核查);与本批裁定直接冲突的残留句 |
|
||||
| 9 | 体验验证清单.md(:86/:206/:220/:314/:315/:326/:442/:519 八处) | 逐行结算、明细带来源/行序/文案可读性、减半标签等目检项——呈现面已换代 | 逐条按退役后形态改写;新增两条目检项:结算期 B 区零逐行文字、封印受理瞬间揭示观感 | 卡1 §6 已列;卡2 §8 体验面四项(封印受理瞬间揭示、悬停禁字、图例新句、清图高光) |
|
||||
|
||||
## 卡2 反哺点
|
||||
|
||||
无(设计面前置闭合;实现与排雷玩法.md v2.0 等事实源零冲突)。
|
||||
|
||||
## 过程发现登记(非文档反哺,供流水线改进参考)
|
||||
|
||||
1. **判据出处行锚漂移**:卡1 复核轮 2 钉死的 ux/battle.md 锚(:199/:272/:347)被 2026-11-07「顶栏搬两侧」文档批修订冲漂(真锚 :200/:364/:439)——写卡段锚钉死后同日文档批仍会冲漂;建议:判据锚钉节锚形态(test-conventions §8.3 已有节锚两档——2026-11-07 架构收窄批立的防漂移机制,写卡段对易漂移文档改用节锚)。
|
||||
2. **卡2 §14 预检读数失实**:「两宿主现行公开方法数远低于 20 上限」系凭印象未实跑(minesweeper_rules 恰 20 贴线,+1 即越)——iter-plan 第 3 步预检的 S13 键读数义务应显式包含「新增公开方法的宿主余量实跑核对」。
|
||||
3. **流水线闸 ANCHOR_RE 不含中文路径**:待办清单在册条目(2026-11-05 登记),本批卡1 锚全为 ASCII 路径未触雷——非本批引入,留待办。
|
||||
@@ -0,0 +1,105 @@
|
||||
# 迭代 56 实现报告(结算期文字列表退役批+封印动作改版批)
|
||||
|
||||
> 2026-11-08。工作区 `../g-plan2-iter56`(分支 iter56,基线 a0ea828f)。两卡按 roadmap 卡序串行:卡1(结算期文字列表退役)→卡2(封印动作改版)。批性质=代码实现批;`design/`、根规则文件、`game/tests/README.md` 零写入。
|
||||
|
||||
## 一、各卡状态
|
||||
|
||||
| 卡 | 状态 | 提交序列 |
|
||||
|---|---|---|
|
||||
| 卡1 结算期文字列表退役批 | **完成**(T0-T3 落地;T4 随批末) | f0390714(T1 撤逐行文字)→T2(日志零文案+reason)→T3(分析工具+对拍载体) |
|
||||
| 卡2 封印动作改版批 | **完成**(T0-T7 落地) | 2d8a4d07(T1 规则核心)→T1a(S13 收敛)→T1b(落位重设计·用户裁)→T2+T5(结算退役+内容退役)→T3(呈现层)→T4(测试探针)→T6(sim 域)→T7(golden) |
|
||||
|
||||
## 二、实际改动—验收对照表(逐行结果读数)
|
||||
|
||||
### 卡1(R1-R5;对照表出处=需求卡片 §10)
|
||||
|
||||
| 需求点 | 验收测试(文件:函数) | 真实入口 | 判据绑定面 | 结果读数 |
|
||||
|---|---|---|---|---|
|
||||
| R1 结算期零逐行文字(ux/battle.md:200——原卡锚 :199 漂移,随批维护) | battle_log_zero_text_test.gd:_smoke_settle_zero_rows(新增) | main.tscn 组合根→真实停手→轮末结算→B 区场景树 | 三时点 parsed_text 冻结于进节点叙述基线(step_row 消费零追加——「不绑终屏态」口径) | **绿**(PASS,读数见 f0390714) |
|
||||
| R2 FX 与 toast 链不断(ux/battle.md:439——原卡锚 :347 漂移) | pacing_queue_test.gd:_assert_fx_chain(新增断言函数) | 真实行集驱动独立 RowPacer | on_step_row_fx 每行一拍+弹道/标出/色环/highlight 三路计数与行型分布逐位一致(期望独立推导);FX 链三函数零 diff=改前逐位一致凭证 | **绿**(PASS) |
|
||||
| R3 日志零文案、字段不缺(战斗结算.md:87) | playtest_logger_step_fields_test.gd:_assert_no_text_and_full_payload(新增) | LevelAutoplay.run_level 挂 logger→真实结算→落盘 JSONL 读回 | 零 text/display_name+公共七字段与平铺原件逐行在位+damage payload 并集抽样 | **绿**(PASS) |
|
||||
| R4 分析判读等价(test-conventions.md:133) | tools/analyze_parity_check.py(新增) | 三读数对拍 | ①历史锚改后分析器复跑 vs 改前分析器基线 3394 行逐位一致 ②改前种子日志双版本一致 ③改前 vs 改后同种子(71000)新日志逐位一致 | **绿**(三读数全一致,读数见 T3 提交) |
|
||||
| R5 未生效原因结构化(战斗结算.md:80) | reward_ineffective_reason_test.gd:_assert_four_reasons(新增) | 真实板身份快照→grant_routed 路由→轮末结账 | 四类 reason 逐一命中(full_hp/hero_down/full_layers=no_guard 堆层/no_enemy_alive=敌 hp=1+blast 双单 defer);两处受控例外直改(hero hp=0、敌 hp=1——无公开 setter,随行申报) | **绿**(PASS,四类全命中) |
|
||||
|
||||
**卡1 测试削弱申报兑现**:§10 点名的改写面全部落地——theme_projection(行协议闸→FX 链逐型闸)、player_copy_sweep(u6 消费半→退役防回潮)、ui_probe:133-135 与 ui_click_probe:423/:473/:616/:798-844(实况核查不依赖退役面——**零改动**,见追认单 #11)、pacing_queue:108-120(断言②改判 FX 承接)。**申报外波及面**(§5.5 同生死):feat_vouchers A12、wr1-b 反转、开场行判定面、ui_input_probe case④b 注记——均改写为退役后正向断言,无删除断言。
|
||||
|
||||
### 卡2(R1-R12;对照表出处=需求卡片 §8)
|
||||
|
||||
| # | 需求点 | 验收测试 | 真实入口 | 结果读数 |
|
||||
|---|---|---|---|---|
|
||||
| R1 | 封印受理即揭示(排雷玩法.md:52) | minesweeper_rules_test:_test_seal_reveal_identity〔封印改 V1〕 | MinesweeperRules.settle_batch() | **绿**(身份逐位+受理零事件+身份与揭示态独立断言) |
|
||||
| R2 | 挖封印格被拒(排雷玩法.md:56) | _test_dig_sealed_rejected〔V2〕+seal_polarity 四情况组改判〔V2〕 | settle_batch() | **绿**(target_sealed+三态零变化;四情况组标中/标空判定照发) |
|
||||
| R3 | 清图口径换代(排雷玩法.md:139) | _test_clear_by_seal〔V3〕 | settle_batch() | **绿**(非末封 false/封印计入完成 true/逐格封至清图 round_end 恰一条 cleared) |
|
||||
| R4 | 能清图的封最优先(排雷玩法.md:167) | _test_classify_seal_clears〔V4〕 | settle_batch() 同批 stop+清图封 | **绿**(赢家=清图封居执行序首、stop voided、round_end cleared) |
|
||||
| R5 | 判定批与溢价零改动(战斗结算.md:139) | seal_polarity 保留组原样+V5 注记行 | BattleOrchestrator 全轮驱动 | **绿**(76 pass——末点 AP/标中溢价/标空/完美封印双份原样) |
|
||||
| R6 | 受理零兑付、改判路径死(战斗结算.md:134) | settlement_wiring_snapshot 内嵌 golden〔V6〕 | BattleOrchestrator 真实驱动序 | **绿**——golden 实测零漂移零重录(驱动序不含挖封印格;流水零作废行) |
|
||||
| R7 | 破封一击退役、词除名(奇物.md:72) | adventure_feats/effect_words_t1 换代〔V7〕+grep | feats.tres 装载路径 | **绿**(grep dug_under_seal/breaker_strike 非测试面=0;词表出册防回潮断言;表 36 件装载绿) |
|
||||
| R8 | 封印格呈现三件套(ux/battle.md:170) | seal_mark_params:_test_seal_on_revealed_visible〔V8〕+board_shot 选择器+ui_input_probe case④b | 真实场景+push_input | **绿**(新组合态印记可见——受控例外随行申报;探针印记落位绿) |
|
||||
| R9 | 已封印格零动作(ux/battle.md:299) | ui_input_probe case④c〔V9〕 | push_input 左/右键 | **绿**(零发射+FORBIDDEN+禁入框+图例说明在册) |
|
||||
| R10 | 文案四件(ux/battle.md:284) | hud_presenter/player_copy_sweep 换代+click 图例〔V10〕 | 文案装配+真实场景 | **绿**(逐字断言换代+雷字清零守恒) |
|
||||
| R11 | sim 策略对齐+MC 同批重锚(排雷玩法.md:52) | MC 配对读数(测量面) | sim 采集链 master_seed 配对 | 代码面绿(试车 5 局健康);**新锚采集后台进行中,读数回填 §四** |
|
||||
| R12 | 渲染基线换代(ux/battle.md:170) | 渲染闸+golden 三图重制〔V12〕 | 真实渲染截图 | **绿**(board_shot 双帧取证 PASS+golden 三屏对比全绿;用户预览图人审 2026-11-07 在案;mac 三件缺件记遗留) |
|
||||
|
||||
**卡2 测试削弱申报兑现**:四处点名改判全落地(①四情况组②preview 形态 B③文案逐字④wiring golden——实测零漂移未重录)。**申报外波及面**:adventure_feats 满配种子 42→43+行数 37→36(feats 删行 RNG 流漂移——§5.5 同生死,主区基线对照坐实非行为回归);ui_click_probe 行为②摘除。其余旧断言零删除。
|
||||
|
||||
## 三、能力行名实核对(game/tests/README.md 批末核对——实现批零写入)
|
||||
|
||||
- :88 封印与极性路由(_smoke_seal_ap_exhausted/_smoke_seal_irreversible_quadrants/_smoke_polarity_routing)——**名实一致**(函数在位)
|
||||
- :117 挖/封印合法性与可辨拒绝(_test_dig_sealed_rejected/_test_classify_seal_clears 计划锚定)——**落地一致**
|
||||
- :119 封印受理即揭示(_test_seal_reveal_identity)——**落地一致**
|
||||
- :120 清图口径换代(_test_clear_by_seal)——**落地一致**
|
||||
- :121 棋盘封印印记呈现(_test_seal_on_revealed_visible 计划锚定)——**落地一致**
|
||||
- :137 结算期零逐行文字(_smoke_settle_zero_rows/_assert_fx_chain/standee_fx_sweep_test:_init)——**落地一致**
|
||||
- :138 日志 step 行零文案(_assert_no_text_and_full_payload/_assert_four_reasons)——**落地一致**
|
||||
- 改名面:无(零回表)
|
||||
|
||||
## 四、MC 同批重锚读数(R11——已落盘)
|
||||
|
||||
- **规模口径**:50/档=100 局(2026-11-08 用户批准——发起时呈报三档规模供裁,首采 800 局超一档硬闸被停采作废,重采按批准规模执行)
|
||||
- **新锚**:`runsum_iter56reanchor_81000_n50both_20261108.jsonl`(纯 RUNSUM 100 行、policy+seed 升序;全量明细 jsonl 不留盘)
|
||||
- **对照读数**(三方对照:改前锚 2026-10-03/改前代码 2026-11-08 现跑 50 局/改后新锚 50 局,同 seed0=81000):
|
||||
|
||||
| 指标 | 改前锚(旧代码读数) | 改前代码现跑 | 改后新锚 | 本批效应 |
|
||||
|---|---|---|---|---|
|
||||
| normal 通关率 | 0% | 0% | 0% | 无变化 |
|
||||
| normal 踩雷均值/局 | 6.72 | 6.48 | 5.40 | -1.08(错触注入替代旧滑失+策略对齐合成) |
|
||||
| normal 标中/标空/封印数 | 无字段 | 21.34/6.74/52.2 | 19.60/7.86/49.9 | 小幅漂移(标空剔除约束增强+清图口径) |
|
||||
| perfect 通关率 | 59% | **0%** | **4%** | **改前锚失实早有声明**(sim-data/README:10 代表性注记——两月代码演进使模拟行为漂移;改前代码现跑 0% 对照坐实与本批无关);本批效应方向=升(封印计入清图利好完美策略) |
|
||||
| perfect 踩雷均值 | 0 | 0 | 0 | 无变化 |
|
||||
| perfect 标中/封印数 | 无字段 | 45.96/91.1 | 48.28/96.1 | 小幅升(同上方向) |
|
||||
|
||||
- **结构性恶化判定**:无(normal 踩雷降、perfect 通关升——两方向均为改版利好或中性;标中/标空经济小幅漂移在策略对齐预期内)
|
||||
- **补偿注入验证**:单局实测 st.mine_slips=5 触发(RUNSUM 无 mine_slips 字段——解析口径注记已写入 sim-data/README);注入形态=错触直挖、初值 0.10——**踩雷读数 6.48→5.40 偏差 -1.08/局**——偏差来源含策略对齐合成效应,非纯注入贡献;偏差已记本节与追认单 #5(白名单 5 授权自判)
|
||||
- sim-data/README.md 现行锚指针已换代+改前锚迁历史锚节(随批合回)
|
||||
|
||||
## 五、实机目检总清单(登记不阻塞——真人目检后销项)
|
||||
|
||||
1. 结算期 B 区零逐行文字(FX 排播链仍逐拍演出)
|
||||
2. 伤害飘字/弹道/站桩反馈在排播新形态下的观感
|
||||
3. 封印受理瞬间揭示的观感(地板+身份字形+法阵叠加——「太忙/太糊」判定归待办「封印格观感细化」条)
|
||||
4. 封印格悬停禁字与图例新句
|
||||
5. 清图高光在封印完成清图时触发
|
||||
|
||||
## 六、遗留读数义务与遗留面
|
||||
|
||||
1. MC 新锚采集(后台)→R11 读数回填本报告+sim-data/README 指针换代+新锚 jsonl 携回主区(数据件不入 git——合并后手工拷贝)
|
||||
2. mac golden 三件缺件(渲染闸 SKIP 不判红)——Mac 环境随批补采或留待含代码面合回的远端 CI
|
||||
3. 独立验收审计(合并前必做——由未参与实现的子代理执行)
|
||||
|
||||
## 七、实现决定记录
|
||||
|
||||
见 `reports/iter56-代拍板追认单-2026-11-08.md`(白名单 9 项+实现决定 11 条+目检登记 5 项)。
|
||||
|
||||
## 八、反哺点
|
||||
|
||||
见 `reports/iter56-反哺点-2026-11-08.md`(卡1 九条+过程发现三条;卡2 零条)。
|
||||
|
||||
|
||||
## 九、独立验收审计结论与审计后勘误
|
||||
|
||||
**审计结论:通过**(reports/iter56-验收审计-2026-11-08.md——17 行对照表全量核对,14 干净通过、2 记账级缺漏,无申报外削弱、无同义反复判据;复跑 3 件全绿)。
|
||||
|
||||
审计两项缺漏的闭环(审计后勘误笔,同批提交):
|
||||
1. 卡1 R1 函数名:battle_log_zero_text_test.gd 断言体由 _init 内联拆出为 **_smoke_settle_zero_rows**(能力行 :137 点名函数——名实一致补齐;拆分后回归绿)。本报告 §三 R1 行「落地一致」记载在拆分前失实,本段勘误。
|
||||
2. 卡2 R6 尾缀载体:〔封印改 V6〕grep 载体缺失(golden 实测零漂移未重录、卡 F9 漏补载体豁免)——settlement_wiring_snapshot_test.gd 宿主 _init 补判据出处注记行(零行为改动,回归绿)。
|
||||
3. 观察项随手修:smoke/critical-paths.md 第 7 条「明细逐行呈现」残留旧口径改写;sim-data/README「历史锚」节标题重复去重;T4 提交说明「V5 三函数」实落 2 处(_smoke_seal_irreversible_quadrants 属改判组带 V2 尾缀,不在保留组——措辞勘误)。
|
||||
+9
-4
@@ -4,10 +4,15 @@
|
||||
|
||||
## 现行锚(分析取数唯一入口)
|
||||
|
||||
- 锚:`runsum_m3iter9exit_81000_n400_20261003.jsonl`(N=400/档=普通 v3.4+perfect;种子 81000 起逐局独立;route=min;taken=hero_dmg+mine_dmg,口径对齐真人分析端)
|
||||
- 读数:`读数_m3iter9exit81000_20261003.md`(k=0.60、完美战役全通 59.0%、结构位移存档)
|
||||
- 换代义务:M-4 数值批投值时本锚随批作废,批内自取改前/改后锚
|
||||
- 代表性注记:0 格连锁算子补齐改变模拟玩家行为(推理面增强),perfect/adv 档通关率预期上调——本锚读数对现行代码代表性下降,带值结论须注明「旧行为基线」口径;重跑归一档(用户发起),发起时批内自取改前/改后锚
|
||||
- 锚:`runsum_iter56reanchor_81000_n50both_20261108.jsonl`(N=50/档=普通+perfect;种子 81000 起逐局独立;route=min;taken=hero_dmg+mine_dmg,口径对齐真人分析端)
|
||||
- 规模口径:**50/档(2026-11-08 用户批准)**——95% CI 约 ±14pp(p≈0.5 处),结构级位移(≥25pp)可判;更细精度需下一次合法触发(如数值标定窗口)时由用户加采
|
||||
- 换代缘由:封印受理即揭示改版(迭代 56——挖封印格被拒/清图口径=挖开∪封印/sim 策略对齐)改变玩法行为,改前锚失效
|
||||
- 改前改后对照读数(迭代 56 R11——改前代码 2026-11-08 现跑 50 局 vs 新锚 50 局,同 seed0):normal 通关 0%→0%、踩雷均值 6.48→5.40、标中 21.34→19.60、标空 6.74→7.86、封印数 52.2→49.9;perfect 通关 0%→4%(封印计入清图的利好方向)、标中 45.96→48.28、封印数 91.1→96.1——无结构性恶化;错触直挖注入单局实测触发(st.mine_slips=5;RUNSUM 无此字段,解析口径注记)
|
||||
|
||||
## 历史锚(只读不判)
|
||||
|
||||
- `runsum_m3iter9exit_81000_n400_20261003.jsonl`(迭代 56 前任现行锚,N=400/档)——**其 perfect 通关 59% 系 2026-10-03 旧代码读数**:0 格连锁算子补齐等两月演进已使模拟行为漂移,改前代码 2026-11-08 现跑 50 局 perfect 通关 0%——带值引用须注明「旧行为基线」口径
|
||||
- 其余 23 份 `runsum_*.jsonl`,文件名=批+锚名+日期可辨。出度≤2 重建后旧锚结构已失义,仅留换代对照;处置挂中间产物死亡清单随批处理。
|
||||
|
||||
## 历史锚(只读不判)
|
||||
|
||||
|
||||
Reference in new issue
Block a user