Files
gplan-2/game/data/schemas/board_gen_table.gd
T
DKChan 9a72394652 chore(代码卫生): 头注存量清偿批——82 文件按两类白名单改写为 ## 文档注释载体
按 code-conventions §1.4.1 第三轮定稿执行:core 22+schemas 18+presentation 根 14+views 28,全部头注 #→##、删日期/变更叙事/GDD 与架构反向链接/字段与域清单/机制描述,保留职责摘要+真实使用约束(防事故禁令/单一入口/信号契约每信号一行)。main.gd 31→5 行、save_manager 45→5 行、adventure_runner 37→5 行为最大单件。子代理分模块执行(波一 core+schemas、波二 presentation+views,并发≤2)。验收=tools/verify_comment_only_change.py 逐字节校验(82 文件头注区外逐行一致=零行为变更)+audit_file_headers 全绿;纯注释批免冒烟(先例 5843270)
2026-10-16 23:28:07 +08:00

82 lines
4.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## VERTICAL SLICE - NOT FOR PRODUCTION
## 棋盘生成表 schema:逐 (level_index, node_depth) 行生成参数的类型化读取(垂直切片验证:完整战斗逐行归因)。
## validate() 违例加载期致命(fail-fast);solver_rules 结构冻结 single_subset——可解性/成本护栏随行校验强制。
class_name BoardGenTable
extends Resource
@export var rows: Array[Dictionary] = [] # Array[Dictionary]
const SOLVER_RULES := ["single", "single_subset"]
const COST_BUDGET := 16384 # F2c provisional 量级护栏(禁墙钟逃生)
const TARGET_ABS_FLOOR := 0.85 # 战斗结算 修订——target 域下限(P1 绝对锚)
const BOARD_TYPE_VOCABULARY := ["dungeon", "underdark", "deep_underdark"] # 图类型词表 v1.1(2026-09-20 L3 内容批 +deep_underdark 灰矮人矿道;玩家侧显示名「地图类型」)
func validate() -> Array:
var errs: Array[Dictionary] = []
if rows.is_empty():
errs.append({"category": "empty_table", "message": "BoardGenTable 为空"})
return errs
var levels := {}
var anchor_ok := {}
for row in rows:
var L: int = int(row.get("level_index", 0))
var D: int = int(row.get("node_depth", -1))
var key := "%d_%d" % [L, D]
if levels.has(key):
errs.append({"category": "dup_key", "message": "BoardGen 键重复: %s" % key})
levels[key] = true
if L < 1:
errs.append({"category": "domain", "message": "level_index 须 ≥1"})
if D < 0:
errs.append({"category": "domain", "message": "node_depth 须 ≥0"})
var w: int = int(row.get("board_width", 0))
var h: int = int(row.get("board_height", 0))
if w < 8 or w > 64 or h < 8 or h > 64:
errs.append({"category": "domain", "message": "(%d,%d) 尺寸越域 [8,64]" % [L, D]})
var d: float = float(row.get("mine_density", 0.0))
if d <= 0.0 or d > 0.5:
errs.append({"category": "domain", "message": "(%d,%d) mine_density 越域 (0,0.5]" % [L, D]})
var t: float = float(row.get("inferability_target", 0.0))
if t < TARGET_ABS_FLOOR or t > 1.0:
errs.append({"category": "domain", "message": "(%d,%d) inferability_target 越域 [0.85,1](P1 绝对锚)" % [L, D]})
if not SOLVER_RULES.has(row.get("solver_rules", "")):
errs.append({"category": "enum", "message": "(%d,%d) solver_rules 出域" % [L, D]})
if row.get("solver_rules", "") != "single_subset":
errs.append({"category": "frozen", "message": "(%d,%d) solver_rules 冻结 single_subset" % [L, D]})
var ms: int = int(row.get("min_safe_count", 0))
if ms < 1 or ms > 999:
errs.append({"category": "domain", "message": "(%d,%d) min_safe_count 越域 [1,999]" % [L, D]})
var att: int = int(row.get("max_gen_attempts", 0))
if att < 1 or att > 32:
errs.append({"category": "domain", "message": "(%d,%d) max_gen_attempts 越域 [1,32]" % [L, D]})
# 布雷数下限(R3)——零雷板拒绝(−9 = 出生区格数,常量单点 BoardData.SPAWN_AREA_CELLS——2026-10-02 修复批)
var n_mines := int(round(d * float(w * h - BoardData.SPAWN_AREA_CELLS)))
if n_mines < 1:
errs.append({"category": "cross_field", "message": "(%d,%d) 布雷数下限违例 round(d×(W×H−9)) ≥ 1" % [L, D]})
# F2b min_safe 可行性
if w * h - n_mines < ms:
errs.append({"category": "cross_field", "message": "(%d,%d) min_safe_feasible 违例" % [L, D]})
# F2c 成本可行性
if att * w * h > COST_BUDGET:
errs.append({"category": "cross_field", "message": "(%d,%d) cost_feasible 违例 attempts×W×H ≤ %d" % [L, D, COST_BUDGET]})
# 图类型词表 v1.0(2026-09-19 用户拍板定稿:dungeon=地牢基线 / underdark=幽暗地域;扩词随内容批走修订)
var bt: String = str(row.get("board_type", ""))
if not BOARD_TYPE_VOCABULARY.has(bt):
errs.append({"category": "cross_field", "message": "(%d,%d) board_type 越词表: %s" % [L, D, bt]})
# 初始展开收窄批两参数(迭代14① T1——加载期校验违例致命;缺省 shave=1 现行投值 / cap=0 闸关防御口径)
var sr: int = int(row.get("shave_ring_radius", 1))
if sr < 0 or sr > 2:
errs.append({"category": "domain", "message": "(%d,%d) shave_ring_radius 越域 [0,2]: %d" % [L, D, sr]})
var r0_cap: int = int(row.get("r0_max_cap", 0))
if r0_cap > 0:
# 护栏(需求卡片 §二):cap ≥ 出生格数 9(BoardData.SPAWN_AREA_CELLS)、cap ≤ 板格数一半
if r0_cap < BoardData.SPAWN_AREA_CELLS:
errs.append({"category": "cross_field", "message": "(%d,%d) r0_max_cap 低于出生保障面 %d: %d" % [L, D, BoardData.SPAWN_AREA_CELLS, r0_cap]})
if r0_cap > (w * h) / 2:
errs.append({"category": "cross_field", "message": "(%d,%d) r0_max_cap 超板格数一半 %d: %d" % [L, D, (w * h) / 2, r0_cap]})
anchor_ok[L] = anchor_ok.get(L, false) or D == 0
for L in anchor_ok.keys():
if not anchor_ok[L]:
errs.append({"category": "anchor", "message": "level %d 缺 depth-0 锚行(EC15)" % L})
return errs