97 lines
3.5 KiB
GDScript
97 lines
3.5 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# Date: 2026-09-11(2026-09-15 格面资源批重写:类型频次测量——供给控制器批口径随可选类删除退役)
|
||
# 奖励期望测量:逐深度实测 |非封锁格|(safe ∪ mines ∖ R₀)分布、格面资源类型频次
|
||
# (应涌现自正向行权重 attack 20 / defense 16 / blast 16 / heal 15 / weaken 12,合计 79)、
|
||
# 封锁格零泄漏(R₀ 格不在摇号清单)——走真实 地图战斗资源.roll_board 管线。
|
||
# 运行:Godot_console.exe --headless --path . --script res://smoke/reward_expectation.gd
|
||
extends SceneTree
|
||
|
||
const N := 200
|
||
|
||
|
||
func _initialize() -> void:
|
||
var db = load("res://core/config_db.gd").new()
|
||
if not db.load_tables("res://data/tables", false):
|
||
print("表加载失败")
|
||
quit(1)
|
||
return
|
||
var board_generator = load("res://core/board_generator.gd").new()
|
||
var reward_economy_factory = load("res://core/reward_economy.gd")
|
||
var rng_factory = load("res://core/rng_service.gd")
|
||
var types := ["attack", "defense", "heal", "blast", "weaken"]
|
||
print("=== 奖励期望测量(格面资源批 · N=%d 板/深度)===" % N)
|
||
print("depth | 非封锁格均/min/max | attack% | defense% | heal% | blast% | weaken% | 封锁格泄漏板")
|
||
for depth in range(5):
|
||
var elig: Array = []
|
||
var type_counts := {"attack": 0.0, "defense": 0.0, "heal": 0.0, "blast": 0.0, "weaken": 0.0}
|
||
var leak := 0
|
||
for i in range(N):
|
||
var rng = rng_factory.new()
|
||
rng.set_master_seed(90000 + depth * 1000 + i)
|
||
var board = board_generator.generate(1, depth, rng.open_stream("board_gen"), db)
|
||
if board == null:
|
||
continue
|
||
var r0 := {}
|
||
for c in board.compute_r0():
|
||
r0[c] = true
|
||
var eligible: Array = []
|
||
for c in board.safe_cells():
|
||
if not r0.has(c):
|
||
eligible.append(c)
|
||
for c in board.mines.keys():
|
||
if not r0.has(c):
|
||
eligible.append(c)
|
||
elig.append(eligible.size())
|
||
var reward_economy = reward_economy_factory.new(db, rng)
|
||
var list: Array = []
|
||
for c in eligible:
|
||
list.append({"cell": c})
|
||
if not reward_economy.roll_board(list):
|
||
continue
|
||
# 封锁格零泄漏:R₀ 格必不在映射(is_mapped 静默查询——零诊断噪音)
|
||
var r0_listed := false
|
||
for c in r0.keys():
|
||
if reward_economy.is_mapped(c):
|
||
r0_listed = true
|
||
if r0_listed:
|
||
leak += 1
|
||
for c in eligible:
|
||
var ident = reward_economy.query_identity(c)
|
||
if ident != null:
|
||
type_counts[String(ident.cell_type)] += 1.0
|
||
var total := 0.0
|
||
for t in types:
|
||
total += type_counts[t]
|
||
print("D%d %dx%d | %6.1f / %3d / %3d | %5.1f%% | %6.1f%% | %4.1f%% | %5.1f%% | %6.1f%% | %d" % [
|
||
depth, 10 if depth <= 1 else 12, 10 if depth <= 1 else 12,
|
||
_mean(elig), _min(elig), _max(elig),
|
||
100.0 * type_counts.attack / total, 100.0 * type_counts.defense / total,
|
||
100.0 * type_counts.heal / total, 100.0 * type_counts.blast / total,
|
||
100.0 * type_counts.weaken / total, leak])
|
||
print("(口径:类型频次 = 正向行权重涌现——attack 25.3%% / defense 20.3%% / blast 20.3%% / heal 19.0%% / weaken 15.2%%;")
|
||
print(" 非封锁格 = safe ∪ mines ∖ R₀,雷安同池同分布;封锁格泄漏 = R₀ 格 query_identity 非 null 的板数,恒应为 0)")
|
||
quit(0)
|
||
|
||
|
||
func _mean(a: Array) -> float:
|
||
if a.is_empty():
|
||
return 0.0
|
||
var t := 0.0
|
||
for v in a:
|
||
t += float(v)
|
||
return t / a.size()
|
||
|
||
|
||
func _min(a: Array) -> int:
|
||
var m := 99999
|
||
for v in a:
|
||
m = mini(m, int(v))
|
||
return m
|
||
|
||
|
||
func _max(a: Array) -> int:
|
||
var m := 0
|
||
for v in a:
|
||
m = maxi(m, int(v))
|
||
return m
|