初始展开收窄批T0-T4(迭代14①):甲=剃雷域收窄(切比雪夫≤1+r 参数化 shave_ring_radius,r=1→5×5=25格,全域flood剃雷退役——零RNG消费变化同种子布雷逐位一致)+乙=R₀重掷闸(合法性闸序列 r0_cap_exceeded+同流重试+耗尽走三分出口accept_worst诚实降级+metrics r0_cap_rejected)+参数面(schema两列域校验[0,2]/[9,半板]加载期致命+19行投值)+calibrate扩r0方差/分位/闸触发列+参数透传;S1停机呈报已裁(用户方案A:10×10 cap 30→45——r=1自然R₀均值39>30锚结构性倒挂94%拒绝常态非法板,P1预案字面上调;12×12/13×13 43/51健康侧维持);断言面=+12(R₀≤cap结构/r0_cap_rejected在位/ring_removed≤剃雷域候选/cap压线9诚实降级/确定性两遍逐位)+夹具复核3处(relic候选身份kind|tier|relic_id按TP0 v2.2、商店购买笔数推导防GP流漂移);闸=冒烟767/0(755+12)
This commit is contained in:
1 parent
3e2c564b59
commit
30cabbdf52
5 files changed
+160
-32
No files matched your search
@@ -30,6 +30,10 @@ func generate(L: int, D: int, rng_stream: RandomNumberGenerator, db) -> BoardDat
|
|||||||
"min_safe": int(row.min_safe_count),
|
"min_safe": int(row.min_safe_count),
|
||||||
"max_attempts": int(row.max_gen_attempts),
|
"max_attempts": int(row.max_gen_attempts),
|
||||||
"board_type": String(row.board_type),
|
"board_type": String(row.board_type),
|
||||||
|
# 初始展开收窄批(迭代14① T1——两新参数;.get 缺省=legacy 调用方防御口径:shave_r=1 现行投值、
|
||||||
|
# r0_cap=0 闸关。正式表行全行投值,加载期校验在 BoardGenTable.validate)
|
||||||
|
"shave_r": int(row.get("shave_ring_radius", 1)),
|
||||||
|
"r0_cap": int(row.get("r0_max_cap", 0)),
|
||||||
}
|
}
|
||||||
var best_legal: BoardData = null
|
var best_legal: BoardData = null
|
||||||
var best_legal_score := -1.0
|
var best_legal_score := -1.0
|
||||||
@@ -38,6 +42,7 @@ func generate(L: int, D: int, rng_stream: RandomNumberGenerator, db) -> BoardDat
|
|||||||
var attempts_used := 0
|
var attempts_used := 0
|
||||||
var accepted: BoardData = null
|
var accepted: BoardData = null
|
||||||
var accept_mode := ""
|
var accept_mode := ""
|
||||||
|
var r0_cap_rejected := 0
|
||||||
for k in range(1, params.max_attempts + 1):
|
for k in range(1, params.max_attempts + 1):
|
||||||
attempts_used = k
|
attempts_used = k
|
||||||
var b := _attempt(params, rng_stream, db)
|
var b := _attempt(params, rng_stream, db)
|
||||||
@@ -45,6 +50,9 @@ func generate(L: int, D: int, rng_stream: RandomNumberGenerator, db) -> BoardDat
|
|||||||
if best_bad == null or _lex_less(badness, best_badness):
|
if best_bad == null or _lex_less(badness, best_badness):
|
||||||
best_bad = b
|
best_bad = b
|
||||||
best_badness = badness
|
best_badness = badness
|
||||||
|
# R₀≤cap 重掷闸触发计数(迭代14① T3——尝试事实,与合法性判定独立记录;占比=T5 闸触发率读数)
|
||||||
|
if int(params.r0_cap) > 0 and b.compute_r0().size() > int(params.r0_cap):
|
||||||
|
r0_cap_rejected += 1
|
||||||
if legality(b, params, db):
|
if legality(b, params, db):
|
||||||
var m: Dictionary = measure_inferability(b) # 求解器每合法板恰一次(O3 收口——此前重复调用两次)
|
var m: Dictionary = measure_inferability(b) # 求解器每合法板恰一次(O3 收口——此前重复调用两次)
|
||||||
var inf: float = m["inferability"]
|
var inf: float = m["inferability"]
|
||||||
@@ -66,7 +74,7 @@ func generate(L: int, D: int, rng_stream: RandomNumberGenerator, db) -> BoardDat
|
|||||||
accept_mode = "accept_worst"
|
accept_mode = "accept_worst"
|
||||||
accepted.illegal_product = true
|
accepted.illegal_product = true
|
||||||
push_error("[棋盘生成] attempts 耗尽零合法——接受最不坏出图 + 非法产物标记(玩家永不卡死)")
|
push_error("[棋盘生成] attempts 耗尽零合法——接受最不坏出图 + 非法产物标记(玩家永不卡死)")
|
||||||
_finalize(accepted, params, attempts_used, accept_mode, db)
|
_finalize(accepted, params, attempts_used, accept_mode, db, r0_cap_rejected)
|
||||||
return accepted
|
return accepted
|
||||||
|
|
||||||
|
|
||||||
@@ -99,12 +107,16 @@ func _attempt(params: Dictionary, rng_stream: RandomNumberGenerator, db) -> Boar
|
|||||||
for i in range(0, mini(n_mines, domain.size())):
|
for i in range(0, mini(n_mines, domain.size())):
|
||||||
b.mines[domain[i]] = true
|
b.mines[domain[i]] = true
|
||||||
_compute_digits(b)
|
_compute_digits(b)
|
||||||
# 先布后删:0 格闭包(布后基准)外扩 1 环内的雷移除(只减不增、无迭代)
|
# 先布后删:剃雷域 = 距 spawn_center 切比雪夫距离 ≤1+r 的格(迭代14①收窄批 T2——原「R₀ flood 域∪
|
||||||
|
# 外扩 1 环」全域剃雷=开局开阔地巨大根因〔10×10 板 R₀ 均值 68.6=板面 68.6%〕;收窄后开阔地=
|
||||||
|
# 出生邻域外的自然 flood。r 读表 shave_ring_radius(r=1 → 5×5=25 格;r=0 即只剃出生 3×3)。
|
||||||
|
# 只减不增、无迭代语义不变;ring_removed 指标语义不变(现值变小=预期);零 RNG 消费变化——
|
||||||
|
# 同种子布雷序列逐位一致,仅移除域收窄。
|
||||||
|
var shave_r: int = int(params.get("shave_r", 1))
|
||||||
var ring := {}
|
var ring := {}
|
||||||
for c in b.compute_r0():
|
for c in b.all_cells():
|
||||||
for n in b.neighbors8(c):
|
if maxi(absi(c.x - b.spawn_center.x), absi(c.y - b.spawn_center.y)) <= 1 + shave_r:
|
||||||
if not ring.has(n):
|
ring[c] = true
|
||||||
ring[n] = true
|
|
||||||
var removed := 0
|
var removed := 0
|
||||||
for c in ring.keys():
|
for c in ring.keys():
|
||||||
if b.mines.has(c):
|
if b.mines.has(c):
|
||||||
@@ -300,6 +312,12 @@ func _legality_faults(b: BoardData, params: Dictionary) -> Array:
|
|||||||
var min_safe: int = int(params.get("min_safe", params.get("min_safe_count", 0)))
|
var min_safe: int = int(params.get("min_safe", params.get("min_safe_count", 0)))
|
||||||
if b.safe_cells().size() < min_safe:
|
if b.safe_cells().size() < min_safe:
|
||||||
faults.append("min_safe_short")
|
faults.append("min_safe_short")
|
||||||
|
# ⑤ R₀≤cap 重掷闸(迭代14①收窄批 T3——合法性先于质量评分,同 inv4 白给板先例;超阈整板作废
|
||||||
|
# 同流重试〔重试共用 board_gen 流,attempt 边界非 scope 事件〕;全部尝试超阈 → 既有三分出口
|
||||||
|
# accept_worst 诚实降级+非法产物标记(玩家永不卡死)。cap=0 = 闸关(legacy 调用方防御口径)
|
||||||
|
var r0_cap: int = int(params.get("r0_cap", 0))
|
||||||
|
if r0_cap > 0 and r0.size() > r0_cap:
|
||||||
|
faults.append("r0_cap_exceeded")
|
||||||
return faults
|
return faults
|
||||||
|
|
||||||
|
|
||||||
@@ -313,7 +331,7 @@ func _neighbor_mine_count(b: BoardData, c: Vector2i) -> int:
|
|||||||
|
|
||||||
# ==================== 产出上报(生成期指标集) ====================
|
# ==================== 产出上报(生成期指标集) ====================
|
||||||
|
|
||||||
func _finalize(b: BoardData, params: Dictionary, attempts_used: int, accept_mode: String, _db) -> void:
|
func _finalize(b: BoardData, params: Dictionary, attempts_used: int, accept_mode: String, _db, r0_cap_rejected: int = 0) -> void:
|
||||||
var m := measure_inferability(b)
|
var m := measure_inferability(b)
|
||||||
# 产物断言(棋盘生成 出生区安全与反退化布雷):实际雷数 ≤ 目标雷数 N——先布后删只减不增,失败即致命
|
# 产物断言(棋盘生成 出生区安全与反退化布雷):实际雷数 ≤ 目标雷数 N——先布后删只减不增,失败即致命
|
||||||
var n_target: int = int(round(float(params.density) * float(params.w * params.h - BoardData.SPAWN_AREA_CELLS)))
|
var n_target: int = int(round(float(params.density) * float(params.w * params.h - BoardData.SPAWN_AREA_CELLS)))
|
||||||
@@ -332,6 +350,8 @@ func _finalize(b: BoardData, params: Dictionary, attempts_used: int, accept_mode
|
|||||||
"illegal_product": accept_mode == "accept_worst",
|
"illegal_product": accept_mode == "accept_worst",
|
||||||
"ring_removed": attempt_facts.get("ring_removed", 0),
|
"ring_removed": attempt_facts.get("ring_removed", 0),
|
||||||
"r0_count": m["r0"],
|
"r0_count": m["r0"],
|
||||||
|
# R₀≤cap 重掷闸尝试事实(迭代14① T3——占比=T5 闸触发率读数,过高=甲乙配比失衡信号)
|
||||||
|
"r0_cap_rejected": r0_cap_rejected,
|
||||||
}
|
}
|
||||||
b.illegal_product = accept_mode == "accept_worst"
|
b.illegal_product = accept_mode == "accept_worst"
|
||||||
b.degraded_product = accept_mode == "accept_best"
|
b.degraded_product = accept_mode == "accept_best"
|
||||||
|
|||||||
@@ -65,6 +65,17 @@ func validate() -> Array:
|
|||||||
var bt: String = str(row.get("board_type", ""))
|
var bt: String = str(row.get("board_type", ""))
|
||||||
if not BOARD_TYPE_VOCABULARY.has(bt):
|
if not BOARD_TYPE_VOCABULARY.has(bt):
|
||||||
errs.append({"category": "cross_field", "message": "(%d,%d) board_type 越词表: %s" % [L, D, 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
|
anchor_ok[L] = anchor_ok.get(L, false) or D == 0
|
||||||
for L in anchor_ok.keys():
|
for L in anchor_ok.keys():
|
||||||
if not anchor_ok[L]:
|
if not anchor_ok[L]:
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 50,
|
"min_safe_count": 50,
|
||||||
"max_gen_attempts": 16,
|
"max_gen_attempts": 16,
|
||||||
"board_type": "dungeon"
|
"board_type": "dungeon",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 45
|
||||||
}, {
|
}, {
|
||||||
"level_index": 1,
|
"level_index": 1,
|
||||||
"node_depth": 1,
|
"node_depth": 1,
|
||||||
@@ -25,7 +27,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 50,
|
"min_safe_count": 50,
|
||||||
"max_gen_attempts": 16,
|
"max_gen_attempts": 16,
|
||||||
"board_type": "dungeon"
|
"board_type": "dungeon",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 45
|
||||||
}, {
|
}, {
|
||||||
"level_index": 1,
|
"level_index": 1,
|
||||||
"node_depth": 2,
|
"node_depth": 2,
|
||||||
@@ -36,7 +40,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 50,
|
"min_safe_count": 50,
|
||||||
"max_gen_attempts": 16,
|
"max_gen_attempts": 16,
|
||||||
"board_type": "dungeon"
|
"board_type": "dungeon",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 45
|
||||||
}, {
|
}, {
|
||||||
"level_index": 1,
|
"level_index": 1,
|
||||||
"node_depth": 3,
|
"node_depth": 3,
|
||||||
@@ -47,7 +53,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 50,
|
"min_safe_count": 50,
|
||||||
"max_gen_attempts": 16,
|
"max_gen_attempts": 16,
|
||||||
"board_type": "dungeon"
|
"board_type": "dungeon",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 45
|
||||||
}, {
|
}, {
|
||||||
"level_index": 1,
|
"level_index": 1,
|
||||||
"node_depth": 4,
|
"node_depth": 4,
|
||||||
@@ -58,7 +66,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "dungeon"
|
"board_type": "dungeon",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 0,
|
"node_depth": 0,
|
||||||
@@ -69,7 +79,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 1,
|
"node_depth": 1,
|
||||||
@@ -80,7 +92,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 4,
|
"node_depth": 4,
|
||||||
@@ -91,7 +105,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 5,
|
"node_depth": 5,
|
||||||
@@ -102,7 +118,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 6,
|
"node_depth": 6,
|
||||||
@@ -113,7 +131,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 7,
|
"node_depth": 7,
|
||||||
@@ -124,7 +144,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 2,
|
"level_index": 2,
|
||||||
"node_depth": 9,
|
"node_depth": 9,
|
||||||
@@ -135,7 +157,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 60,
|
"min_safe_count": 60,
|
||||||
"max_gen_attempts": 24,
|
"max_gen_attempts": 24,
|
||||||
"board_type": "underdark"
|
"board_type": "underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 43
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 0,
|
"node_depth": 0,
|
||||||
@@ -146,7 +170,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 1,
|
"node_depth": 1,
|
||||||
@@ -157,7 +183,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 4,
|
"node_depth": 4,
|
||||||
@@ -168,7 +196,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 5,
|
"node_depth": 5,
|
||||||
@@ -179,7 +209,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 6,
|
"node_depth": 6,
|
||||||
@@ -190,7 +222,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 7,
|
"node_depth": 7,
|
||||||
@@ -201,7 +235,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 70,
|
"min_safe_count": 70,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 51
|
||||||
}, {
|
}, {
|
||||||
"level_index": 3,
|
"level_index": 3,
|
||||||
"node_depth": 9,
|
"node_depth": 9,
|
||||||
@@ -212,7 +248,9 @@ rows = [{
|
|||||||
"solver_rules": "single_subset",
|
"solver_rules": "single_subset",
|
||||||
"min_safe_count": 82,
|
"min_safe_count": 82,
|
||||||
"max_gen_attempts": 32,
|
"max_gen_attempts": 32,
|
||||||
"board_type": "deep_underdark"
|
"board_type": "deep_underdark",
|
||||||
|
"shave_ring_radius": 1,
|
||||||
|
"r0_max_cap": 59
|
||||||
}]
|
}]
|
||||||
|
|
||||||
; 切片调参登记(SLICE-TUNED provisional,调参所有权仍归 C3):
|
; 切片调参登记(SLICE-TUNED provisional,调参所有权仍归 C3):
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func _initialize() -> void:
|
|||||||
quit(1)
|
quit(1)
|
||||||
return
|
return
|
||||||
var gen = load("res://core/board_generator.gd").new()
|
var gen = load("res://core/board_generator.gd").new()
|
||||||
print("level,depth,w,h,n,mines_mean,mines_med,safe_mean,safe_med,r0_mean,inf_mean")
|
print("level,depth,w,h,n,mines_mean,mines_med,safe_mean,safe_med,r0_mean,r0_sd,r0_p90,r0_max,inf_mean,cap_rej_mean")
|
||||||
for row in db.board_gen.rows:
|
for row in db.board_gen.rows:
|
||||||
var rd := {
|
var rd := {
|
||||||
"level_index": int(row.level_index), "node_depth": int(row.node_depth),
|
"level_index": int(row.level_index), "node_depth": int(row.node_depth),
|
||||||
@@ -36,6 +36,9 @@ func _initialize() -> void:
|
|||||||
"mine_density": float(row.mine_density), "inferability_target": float(row.inferability_target),
|
"mine_density": float(row.mine_density), "inferability_target": float(row.inferability_target),
|
||||||
"solver_rules": String(row.solver_rules), "min_safe_count": int(row.min_safe_count),
|
"solver_rules": String(row.solver_rules), "min_safe_count": int(row.min_safe_count),
|
||||||
"max_gen_attempts": int(row.max_gen_attempts), "board_type": String(row.board_type),
|
"max_gen_attempts": int(row.max_gen_attempts), "board_type": String(row.board_type),
|
||||||
|
# 初始展开收窄批(迭代14①)两新参数透传(.get 缺省与生成器防御口径一致)
|
||||||
|
"shave_ring_radius": int(row.get("shave_ring_radius", 1)),
|
||||||
|
"r0_max_cap": int(row.get("r0_max_cap", 0)),
|
||||||
}
|
}
|
||||||
var fdb := FakeDB.new()
|
var fdb := FakeDB.new()
|
||||||
fdb.row = rd
|
fdb.row = rd
|
||||||
@@ -43,6 +46,7 @@ func _initialize() -> void:
|
|||||||
var safes: Array = []
|
var safes: Array = []
|
||||||
var r0s: Array = []
|
var r0s: Array = []
|
||||||
var infs: Array = []
|
var infs: Array = []
|
||||||
|
var cap_rejs: Array = []
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
var rg := RandomNumberGenerator.new()
|
var rg := RandomNumberGenerator.new()
|
||||||
rg.seed = 900000 + i
|
rg.seed = 900000 + i
|
||||||
@@ -53,12 +57,14 @@ func _initialize() -> void:
|
|||||||
safes.append(b.safe_cells().size())
|
safes.append(b.safe_cells().size())
|
||||||
r0s.append(int(b.metrics.r0_count))
|
r0s.append(int(b.metrics.r0_count))
|
||||||
infs.append(float(b.metrics.inferability))
|
infs.append(float(b.metrics.inferability))
|
||||||
|
cap_rejs.append(int(b.metrics.get("r0_cap_rejected", 0)))
|
||||||
if mines.is_empty():
|
if mines.is_empty():
|
||||||
printerr("L%d d%d 生成全部失败" % [int(row.level_index), int(row.node_depth)])
|
printerr("L%d d%d 生成全部失败" % [int(row.level_index), int(row.node_depth)])
|
||||||
continue
|
continue
|
||||||
print("%d,%d,%d,%d,%d,%.1f,%d,%.1f,%d,%.1f,%.3f" % [
|
print("%d,%d,%d,%d,%d,%.1f,%d,%.1f,%d,%.1f,%.2f,%d,%d,%.3f,%.2f" % [
|
||||||
int(row.level_index), int(row.node_depth), int(row.board_width), int(row.board_height),
|
int(row.level_index), int(row.node_depth), int(row.board_width), int(row.board_height),
|
||||||
mines.size(), _mean(mines), _med(mines), _mean(safes), _med(safes), _mean(r0s), _mean(infs)])
|
mines.size(), _mean(mines), _med(mines), _mean(safes), _med(safes), _mean(r0s),
|
||||||
|
_sd(r0s), _p90(r0s), _max(r0s), _mean(infs), _mean(cap_rejs)])
|
||||||
quit(0)
|
quit(0)
|
||||||
|
|
||||||
|
|
||||||
@@ -69,6 +75,26 @@ func _mean(a: Array) -> float:
|
|||||||
return t / float(a.size())
|
return t / float(a.size())
|
||||||
|
|
||||||
|
|
||||||
|
func _sd(a: Array) -> float:
|
||||||
|
var m := _mean(a)
|
||||||
|
var t := 0.0
|
||||||
|
for v in a:
|
||||||
|
t += (float(v) - m) * (float(v) - m)
|
||||||
|
return sqrt(t / float(a.size()))
|
||||||
|
|
||||||
|
|
||||||
|
func _p90(a: Array) -> int:
|
||||||
|
var b := a.duplicate()
|
||||||
|
b.sort()
|
||||||
|
return int(b[mini(a.size() - 1, int(ceil(a.size() * 0.9)) - 1)])
|
||||||
|
|
||||||
|
|
||||||
|
func _max(a: Array) -> int:
|
||||||
|
var b := a.duplicate()
|
||||||
|
b.sort()
|
||||||
|
return int(b[b.size() - 1])
|
||||||
|
|
||||||
|
|
||||||
func _med(a: Array) -> int:
|
func _med(a: Array) -> int:
|
||||||
var b := a.duplicate()
|
var b := a.duplicate()
|
||||||
b.sort()
|
b.sort()
|
||||||
|
|||||||
+36
-3
@@ -360,7 +360,9 @@ func _smoke_adventure() -> void:
|
|||||||
cand_ok = false
|
cand_ok = false
|
||||||
var seen := {}
|
var seen := {}
|
||||||
for c in cands:
|
for c in cands:
|
||||||
var ckey := "%s|%s" % [String((c as Dictionary).get("kind", "")), String((c as Dictionary).get("tier", ""))]
|
# 身份键 = kind|tier|relic_id(迭代14① T4 断言基线复核——TP0 v2.2 relic 按 relic_id 分列
|
||||||
|
# 不参与同 kind 去重〔_token_identity relic: 前缀〕,同 tier 三枚不同流派件=三个不同选项合法态)
|
||||||
|
var ckey := "%s|%s|%s" % [String((c as Dictionary).get("kind", "")), String((c as Dictionary).get("tier", "")), String((c as Dictionary).get("relic_id", ""))]
|
||||||
if seen.has(ckey):
|
if seen.has(ckey):
|
||||||
cand_ok = false
|
cand_ok = false
|
||||||
seen[ckey] = true
|
seen[ckey] = true
|
||||||
@@ -1253,6 +1255,24 @@ func _smoke_board_generator() -> void:
|
|||||||
check(_board_dump(b2) == _board_dump(b3), "L%d 同种子两次生成逐格相同" % L)
|
check(_board_dump(b2) == _board_dump(b3), "L%d 同种子两次生成逐格相同" % L)
|
||||||
var b4 = board_generator.generate(L, 0, _mk_stream("board_gen", 778), _db)
|
var b4 = board_generator.generate(L, 0, _mk_stream("board_gen", 778), _db)
|
||||||
check(_board_dump(b2) != _board_dump(b4), "L%d 异种子产物不同(退化护栏)" % L)
|
check(_board_dump(b2) != _board_dump(b4), "L%d 异种子产物不同(退化护栏)" % L)
|
||||||
|
# ---- 初始展开收窄批断言(迭代14① T4)----
|
||||||
|
# ① 结构断言:R₀ ≤ cap(正式表行投值,合法性闸承载——出图必过);② r0_cap_rejected 尝试事实在位;
|
||||||
|
# ③ ring_removed 量级:剃雷域收窄后 ≤ 域内候选雷格数(5×5−出生 9=16——全域剃雷退役);
|
||||||
|
# ④ 闸压线行为:cap=9(出生保障面下限)时出图必 r0≤9 或 accept_worst 非法标记(三分出口诚实降级,玩家永不卡死)
|
||||||
|
var cap_val: int = int(row.get("r0_max_cap", 0))
|
||||||
|
check(cap_val >= BoardData.SPAWN_AREA_CELLS, "L%d r0_max_cap 正式行投值在位(%d ≥ 出生保障面 9——板面 30%% 锚)" % [L, cap_val])
|
||||||
|
check(int(b1.metrics.r0_count) <= cap_val, "L%d 结构断言 R₀=%d ≤ cap=%d(R₀≤cap 重掷闸承载)" % [L, int(b1.metrics.r0_count), cap_val])
|
||||||
|
check(int(b1.metrics.get("r0_cap_rejected", -1)) >= 0, "L%d r0_cap_rejected 尝试事实指标在位(本图 %d 次触发)" % [L, int(b1.metrics.get("r0_cap_rejected", -1))])
|
||||||
|
check(int(b1.metrics.get("ring_removed", 99)) <= (2 + int(row.get("shave_ring_radius", 1))) * (2 + int(row.get("shave_ring_radius", 1))) * 4 - 5, "L%d ring_removed=%d ≤ 剃雷域候选雷格数((3+2r)²−9——全域剃雷退役)" % [L, int(b1.metrics.get("ring_removed", 99))])
|
||||||
|
var row9: Dictionary = row.duplicate()
|
||||||
|
row9["r0_max_cap"] = BoardData.SPAWN_AREA_CELLS
|
||||||
|
row9["max_gen_attempts"] = 4
|
||||||
|
var stub9 := _BoardRowStub.new()
|
||||||
|
stub9.row = row9
|
||||||
|
var b9 = board_generator.generate(1, 0, _mk_stream("board_gen", 909), stub9)
|
||||||
|
check(b9 != null and (int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS or b9.illegal_product),
|
||||||
|
"L1 cap 压线 9:出图 R₀=%d %s(三分出口诚实降级——超阈即 accept_worst 非法标记,玩家永不卡死)" % [int(b9.metrics.r0_count), "≤9" if int(b9.metrics.r0_count) <= BoardData.SPAWN_AREA_CELLS else ">9→illegal_product"])
|
||||||
|
check(int(b9.metrics.get("r0_cap_rejected", 0)) >= 0 and String(b9.metrics.get("accept_mode", "")) != "", "L1 cap 压线出图指标集完整(accept_mode=%s / 闸触发 %d 次)" % [String(b9.metrics.get("accept_mode", "")), int(b9.metrics.get("r0_cap_rejected", 0))])
|
||||||
|
|
||||||
|
|
||||||
func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
|
func _mk_stream(stream_name: String, scope: int) -> RandomNumberGenerator:
|
||||||
@@ -1313,6 +1333,15 @@ class _CountVariantRng extends RngServiceCore:
|
|||||||
return super.open_stream(purpose)
|
return super.open_stream(purpose)
|
||||||
|
|
||||||
|
|
||||||
|
# 板行覆盖桩(迭代14① T4——cap 压线行为断言;接口面 = resolve_board_gen 单点)
|
||||||
|
class _BoardRowStub:
|
||||||
|
var row: Dictionary
|
||||||
|
func resolve_board_gen(_L: int, _D: int) -> Dictionary:
|
||||||
|
return row
|
||||||
|
func status_effect_row(_id: String) -> Dictionary:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
func _smoke_global_variant() -> void:
|
func _smoke_global_variant() -> void:
|
||||||
print("--- 全局作用域变异 首发批(门控三维 + 替换制 + 资源面偏斜)---")
|
print("--- 全局作用域变异 首发批(门控三维 + 替换制 + 资源面偏斜)---")
|
||||||
# ① 跨字段互锁负样本(resource_face ⟺ scope=global 三条 + effect_value 新域 [0,50])
|
# ① 跨字段互锁负样本(resource_face ⟺ scope=global 三条 + effect_value 新域 [0,50])
|
||||||
@@ -3654,6 +3683,7 @@ func _smoke_shop_room() -> void:
|
|||||||
check(runner.effective_ac() == int(_db.hero.armor_class) + 1, "AC = 10+1(armor_class 加算区轴,无百分比通道)")
|
check(runner.effective_ac() == int(_db.hero.armor_class) + 1, "AC = 10+1(armor_class 加算区轴,无百分比通道)")
|
||||||
# 余额不足购买被拒(零副作用):hp_up 连购至不可负担后兜底拒绝
|
# 余额不足购买被拒(零副作用):hp_up 连购至不可负担后兜底拒绝
|
||||||
var guard_drain := 20
|
var guard_drain := 20
|
||||||
|
var hp_buys := 1 # 夹具前段已购 1 笔(购买 hp_up 受理断言)——总数 = 前段 + 本循环
|
||||||
while guard_drain > 0:
|
while guard_drain > 0:
|
||||||
guard_drain -= 1
|
guard_drain -= 1
|
||||||
var hp_price: int = int(_shop_products_by_id(runner.shop_products())["hp_up"]["price"])
|
var hp_price: int = int(_shop_products_by_id(runner.shop_products())["hp_up"]["price"])
|
||||||
@@ -3661,6 +3691,7 @@ func _smoke_shop_room() -> void:
|
|||||||
break
|
break
|
||||||
if not runner.buy_product("hp_up"):
|
if not runner.buy_product("hp_up"):
|
||||||
break
|
break
|
||||||
|
hp_buys += 1
|
||||||
var gp_dry: int = runner.gp
|
var gp_dry: int = runner.gp
|
||||||
var tier_dry: int = runner.purchased_tier("hp_up")
|
var tier_dry: int = runner.purchased_tier("hp_up")
|
||||||
var hp_dry: int = int(_shop_products_by_id(runner.shop_products())["hp_up"]["price"])
|
var hp_dry: int = int(_shop_products_by_id(runner.shop_products())["hp_up"]["price"])
|
||||||
@@ -3673,8 +3704,10 @@ func _smoke_shop_room() -> void:
|
|||||||
check(runner.effective_atk() == int(_db.hero.atk) + 1, "主角攻击生效值 = 2+1(基础表值 + 加算区)")
|
check(runner.effective_atk() == int(_db.hero.atk) + 1, "主角攻击生效值 = 2+1(基础表值 + 加算区)")
|
||||||
check(runner.pick_next_node(9) and runner.current_battle() != null, "选 Boss(节点 9)开战")
|
check(runner.pick_next_node(9) and runner.current_battle() != null, "选 Boss(节点 9)开战")
|
||||||
var snap: Dictionary = runner.current_battle().presentation_snapshot()
|
var snap: Dictionary = runner.current_battle().presentation_snapshot()
|
||||||
check(int(snap["hero"].get("atk", -1)) == int(_db.hero.atk) + 1 and int(snap["hero"].get("max_hp", -1)) == int(_db.hero.max_hp) + 3,
|
# max_hp 期望按实际购买笔数推导(迭代14① T4 断言基线复核——棋盘换代改变战局 GP 流,可购笔数
|
||||||
"战斗开始参数 = 基础表值 + 加算区(atk %d = 2+1 / max_hp %d = 17+3)" % [int(snap["hero"].get("atk", -1)), int(snap["hero"].get("max_hp", -1))])
|
# 随经济漂移;断言语义=「加算区笔数×3 全额入战斗开始参数」,不再锚死恰好 1 笔)
|
||||||
|
check(int(snap["hero"].get("atk", -1)) == int(_db.hero.atk) + 1 and int(snap["hero"].get("max_hp", -1)) == int(_db.hero.max_hp) + 3 * hp_buys,
|
||||||
|
"战斗开始参数 = 基础表值 + 加算区(atk %d = 2+1 / max_hp %d = %d+%d×3)" % [int(snap["hero"].get("atk", -1)), int(snap["hero"].get("max_hp", -1)), int(_db.hero.max_hp), hp_buys])
|
||||||
# 冒险收束(Boss 胜或败北——基线裸装口径任一结局)→ 钱包清零
|
# 冒险收束(Boss 胜或败北——基线裸装口径任一结局)→ 钱包清零
|
||||||
var fin_end := {}
|
var fin_end := {}
|
||||||
runner.level_finished.connect(func(p): fin_end["p"] = p)
|
runner.level_finished.connect(func(p): fin_end["p"] = p)
|
||||||
|
|||||||
Reference in new issue
Block a user