Files
gplan-2/game/data/schemas/board_gen_table.gd
T

73 lines
4.1 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
# Validation Question: 玩家能否无指导在一场完整战斗中经历「开战→挖掘规划→轮末结算逐行兑现→胜/负」并逐行归因(P2)
# Date: 2026-09-10
# 数据配置 BoardGenTable schema(棋盘生成 回填值;键 (level_index, node_depth)——首个进度键表)。
# 依据 design/archive/gdd-2026-09-14/a1-board-generation.md "BoardGenTable Schema 定稿" + F2/F2b/F2c 谓词。
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]})
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