Files
gplan-2/game/sim/calibrate_boards.gd
T

101 lines
3.5 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
# 棋盘口径校准(分析会话取数工具——冒险零加成完成度分母实证):
# 逐 board_gen 行真实生成 N 板,统计 实际雷数/安全格数/R₀ 初始展开占比——
# 生成期「先布后删+可推理率重试」使实际雷数远低于表口径 round(d×(W×H−9)),
# 日志侧只有清图板可反推 safe_total(未清图深度无样本),本工具给全网格精确分母。
# 运行:Godot_console.exe --headless --path . --script res://sim/calibrate_boards.gd -- [N]
# 输出:stdout CSV 行 level,depth,w,h,n,mines_mean,mines_med,safe_mean,safe_med,r0_mean,inf_mean
extends SceneTree
class FakeDB:
var row: Dictionary
func resolve_board_gen(_L: int, _D: int) -> Dictionary:
return row
func status_effect_row(_id: String) -> Dictionary:
return {}
func _initialize() -> void:
var args := OS.get_cmdline_user_args()
var n := 200
if args.size() >= 1 and args[0].is_valid_int():
n = maxi(10, int(args[0]))
var db = load("res://core/config_db.gd").new()
if not db.load_tables("res://data/tables", false):
print("表加载失败")
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,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),
"board_width": int(row.board_width), "board_height": int(row.board_height),
"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),
# 初始展开收窄两参数透传(.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
var mines: Array = []
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
var b = gen.generate(int(row.level_index), int(row.node_depth), rg, fdb)
if b == null:
continue
mines.append(b.mines.size())
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,%.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),
_sd(r0s), _p90(r0s), _max(r0s), _mean(infs), _mean(cap_rejs)])
quit(0)
func _mean(a: Array) -> float:
var t := 0.0
for v in a:
t += float(v)
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()
return int(b[b.size() / 2])