标识符面:flag_*→seal_ 族(含 Godot 信号 flag_judged→seal_judged 与连接/回调同名、 FACTS 两键 flags_count→seals_count/dug_under_flag→dug_under_seal 全链、 .tres 键名与 schema .gd 同批同步);显式豁免零改动=size_flags_*(Godot 布局属性)+_fatal_flag。 中文面:金币→GP(金币袋→GP 袋)/插旗→封印/雷格→危险格/惩罚格→危险格/旗→封印·封印印记族, game/ 内 *.gd/.tres/.md/.json 四类禁用词与 flag 双双零命中(V1/V4)。 守卫字面量不动(被检查的禁字不是使用):smoke_all V21 零「雷/旗」检查面、 ui_font_asset_test 字形集攻/雷/旗/封 保持原断言逻辑。 代拍板:板面单字槽 glyph「旗」→「封」(禁字纪律+单字位宽,消费面四处同名随动)。 素材换代(2026-10-18 用户裁案甲):assets/art/board/flag_seal.png→seal_mark.png(素材不入 git, 盘上改名+导入重刷),代码两处 res:// 字符串+COL_FLAG/CURSOR_FLAG 常量同步, 闸件四处随批(run_all_gates.sh/render_gate.sh/golden_baseline_refresh.sh/path_check.py)。 anchor.json 键名手改,重锚与改前改后 diff 随本卡收口(同裁案甲)。 基线读数(改前,主区 ed2dfaf6):冒烟 1151 检查 0 失败/单元 34 套全绿/探针 --click 存量红仅 screen_flow_probe(user:// 断点污染在册已知项)。 改后同批读数(本 worktree):冒烟 1151 检查 0 失败/探针 --click 同一存量红、其余全绿。
112 lines
4.1 KiB
GDScript
112 lines
4.1 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## 棋盘产物数据契约:生成器产出、排雷玩法消费的格子事实集(垂直切片验证:战斗内棋盘事实逐行归因)。
|
||
## 生成后不可变——消费方持引用只读,禁原地改写;跨类「棋盘事实不可变」约定由本不可变性承载。
|
||
class_name BoardData
|
||
extends RefCounted
|
||
|
||
# 出生 3×3 区格数(2026-10-02 修复批 T2 魔法数结构化——W×H−9 布雷域基的双落点收口单点:
|
||
# 棋盘生成 _attempt/_finalize 与 BoardGenTable 布雷数下限校验共用;与 spawn_cells() 的 3×3 几何同源)
|
||
const SPAWN_AREA_CELLS := 9
|
||
|
||
var width: int = 0
|
||
var height: int = 0
|
||
var spawn_center := Vector2i.ZERO
|
||
var mines := {} # Vector2i → true
|
||
var digits := {} # Vector2i → int(安全格恒有值;数字恒真 = 8 邻雷数)
|
||
var variants := {} # Vector2i → Array[String](生成期快照,抗表重载)
|
||
var board_variants: Array[String] = [] # 板级变异 id 集(scope=global 整图作用域——全局作用域变异批 2026-10-04:
|
||
# 战斗编排装板决议写入,随图生灭同 variants;普通图恒空)
|
||
var board_type := "" # 图类型标签(词表 v1.0:dungeon/underdark;玩家侧显示名「地图类型」)
|
||
var level_index: int = 1
|
||
var node_depth: int = 0
|
||
var metrics := {} # 生成期指标集(键清单单点定义在 board_generator._finalize)
|
||
var illegal_product := false # 非法产物标记(接受最不坏出口——零合法板诚实降级)
|
||
var degraded_product := false # 降级产物标记(接受最优出口——有合法板但无一达标;与 illegal_product 对称)
|
||
|
||
|
||
func in_bounds(c: Vector2i) -> bool:
|
||
return c.x >= 0 and c.y >= 0 and c.x < width and c.y < height
|
||
|
||
|
||
# 行主序排序键(2026-10-02 修复批——排雷玩法 封印判定批与 地图战斗资源 资格规范化两处手抄收口单点):
|
||
# y×1000+x 字典序 = 行主序;板宽域 [8,64] 远小于 1000,x 不跨行、键值不碰撞。
|
||
static func row_major_key(c: Vector2i) -> int:
|
||
return c.y * 1000 + c.x
|
||
|
||
|
||
func is_mine(c: Vector2i) -> bool:
|
||
return mines.has(c)
|
||
|
||
|
||
func is_safe(c: Vector2i) -> bool:
|
||
return in_bounds(c) and not mines.has(c)
|
||
|
||
|
||
func digit_of(c: Vector2i) -> int:
|
||
return digits.get(c, -1)
|
||
|
||
|
||
func variant_ids(c: Vector2i) -> Array:
|
||
return variants.get(c, [])
|
||
|
||
|
||
# 板级变异只读出口(scope=global 行集——呈现快照/断言消费;空 = 无全局型合法态)
|
||
func board_variant_ids() -> Array[String]:
|
||
return board_variants
|
||
|
||
|
||
# 中和格变异(迭代 12 T6 净化工兵——伤害型地形格变普通格;🔴 R4 甲仅限伤害型的过滤在调用方)
|
||
func neighbors8(c: Vector2i) -> Array:
|
||
var out: Array[Vector2i] = []
|
||
for dy in range(-1, 2):
|
||
for dx in range(-1, 2):
|
||
if dx == 0 and dy == 0:
|
||
continue
|
||
var n := Vector2i(c.x + dx, c.y + dy)
|
||
if in_bounds(n):
|
||
out.append(n)
|
||
return out # 行主序(规范序的邻接枚举基序)
|
||
|
||
|
||
func spawn_cells() -> Array:
|
||
var out: Array[Vector2i] = []
|
||
for dy in range(-1, 2):
|
||
for dx in range(-1, 2):
|
||
var c := Vector2i(spawn_center.x + dx, spawn_center.y + dy)
|
||
if in_bounds(c):
|
||
out.append(c)
|
||
return out
|
||
|
||
|
||
func all_cells() -> Array:
|
||
var out: Array[Vector2i] = []
|
||
for y in height:
|
||
for x in width:
|
||
out.append(Vector2i(x, y))
|
||
return out
|
||
|
||
|
||
func safe_cells() -> Array:
|
||
var out: Array[Vector2i] = []
|
||
for c in all_cells():
|
||
if is_safe(c):
|
||
out.append(c)
|
||
return out
|
||
|
||
|
||
# R₀ = 出生 3×3 ∪ (出生 3×3 经 0 格的 flood 闭包)——与 排雷玩法 F3 逐字同构(棋盘生成 F1 求解器初始态)。
|
||
func compute_r0() -> Array:
|
||
var b3 := spawn_cells()
|
||
var r0 := {}
|
||
for c in b3:
|
||
r0[c] = true
|
||
var queue: Array[Variant] = b3.duplicate()
|
||
while not queue.is_empty():
|
||
var c: Vector2i = queue.pop_front()
|
||
if is_safe(c) and digit_of(c) == 0: # 变异死分支退役(2026-09-18 用户拍板删——与 排雷玩法 展开实现口径归一;变异定稿批按正式语义重接)
|
||
for n in neighbors8(c):
|
||
if is_safe(n) and not r0.has(n):
|
||
r0[n] = true
|
||
queue.append(n)
|
||
return r0.keys()
|