初始展开收窄批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
@@ -28,7 +28,7 @@ func _initialize() -> void:
|
||||
quit(1)
|
||||
return
|
||||
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:
|
||||
var rd := {
|
||||
"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),
|
||||
"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),
|
||||
# 初始展开收窄批(迭代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()
|
||||
fdb.row = rd
|
||||
@@ -43,6 +46,7 @@ func _initialize() -> void:
|
||||
var safes: Array = []
|
||||
var r0s: Array = []
|
||||
var infs: Array = []
|
||||
var cap_rejs: Array = []
|
||||
for i in range(n):
|
||||
var rg := RandomNumberGenerator.new()
|
||||
rg.seed = 900000 + i
|
||||
@@ -53,12 +57,14 @@ func _initialize() -> void:
|
||||
safes.append(b.safe_cells().size())
|
||||
r0s.append(int(b.metrics.r0_count))
|
||||
infs.append(float(b.metrics.inferability))
|
||||
cap_rejs.append(int(b.metrics.get("r0_cap_rejected", 0)))
|
||||
if mines.is_empty():
|
||||
printerr("L%d d%d 生成全部失败" % [int(row.level_index), int(row.node_depth)])
|
||||
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),
|
||||
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)
|
||||
|
||||
|
||||
@@ -69,6 +75,26 @@ func _mean(a: Array) -> float:
|
||||
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:
|
||||
var b := a.duplicate()
|
||||
b.sort()
|
||||
|
||||
+36
-3
@@ -360,7 +360,9 @@ func _smoke_adventure() -> void:
|
||||
cand_ok = false
|
||||
var seen := {}
|
||||
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):
|
||||
cand_ok = false
|
||||
seen[ckey] = true
|
||||
@@ -1253,6 +1255,24 @@ func _smoke_board_generator() -> void:
|
||||
check(_board_dump(b2) == _board_dump(b3), "L%d 同种子两次生成逐格相同" % L)
|
||||
var b4 = board_generator.generate(L, 0, _mk_stream("board_gen", 778), _db)
|
||||
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:
|
||||
@@ -1313,6 +1333,15 @@ class _CountVariantRng extends RngServiceCore:
|
||||
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:
|
||||
print("--- 全局作用域变异 首发批(门控三维 + 替换制 + 资源面偏斜)---")
|
||||
# ① 跨字段互锁负样本(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 加算区轴,无百分比通道)")
|
||||
# 余额不足购买被拒(零副作用):hp_up 连购至不可负担后兜底拒绝
|
||||
var guard_drain := 20
|
||||
var hp_buys := 1 # 夹具前段已购 1 笔(购买 hp_up 受理断言)——总数 = 前段 + 本循环
|
||||
while guard_drain > 0:
|
||||
guard_drain -= 1
|
||||
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
|
||||
if not runner.buy_product("hp_up"):
|
||||
break
|
||||
hp_buys += 1
|
||||
var gp_dry: int = runner.gp
|
||||
var tier_dry: int = runner.purchased_tier("hp_up")
|
||||
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.pick_next_node(9) and runner.current_battle() != null, "选 Boss(节点 9)开战")
|
||||
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,
|
||||
"战斗开始参数 = 基础表值 + 加算区(atk %d = 2+1 / max_hp %d = 17+3)" % [int(snap["hero"].get("atk", -1)), int(snap["hero"].get("max_hp", -1))])
|
||||
# max_hp 期望按实际购买笔数推导(迭代14① T4 断言基线复核——棋盘换代改变战局 GP 流,可购笔数
|
||||
# 随经济漂移;断言语义=「加算区笔数×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 胜或败北——基线裸装口径任一结局)→ 钱包清零
|
||||
var fin_end := {}
|
||||
runner.level_finished.connect(func(p): fin_end["p"] = p)
|
||||
|
||||
Reference in new issue
Block a user