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
@@ -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", "", "")
|
||||
|
||||
|
||||
Reference in new issue
Block a user