iter9-numfix-c: 普通档 v3.2-v3.4 失误模型校准(卡死赌挖+概率启发+空闲早赌)
- v3.2:卡死赌挖替代刷新/停手(用户实证口径「看不到数字也盲挖」;普通档不刷新=用户自报全程 未用刷新);choose_dig 行主序=概率最差格,实证 199/200 死第二战——退役 - gamble_pick(auto_player):概率启发选格=对邻接已证数字约束取(余雷/未知)比最小值——真人 「挑看起来最安全的一格」单步近似;纯查询面零 RNG 确定性保回放 - v3.3:标雷误挖 0.22→0.10(22% 全旗误挖=保底命中非真人失误形态,普通档 0/100 全灭实证) - v3.4:空闲提前赌挖 0.10(完美系把不确定性攒到残局 hazard→1=扫雷;真人早赌滚信息)+ _gamble_action 组装抽出 - 读数轨迹(N=100,种子 910003 起,route min):v3.3=0%(L1 2%)/v3.4=0%(L1 2%)—— 死因改判:非失误率而是 L1 四连战无治疗夹缝(雷伤+垫刀双压),表值刀归调参批
This commit is contained in:
1 parent
a2f72f9d9e
commit
cc2d75d396
2 files changed
+78
-8
No files matched your search
@@ -208,3 +208,45 @@ static func _row_major(cells: Dictionary) -> Array:
|
||||
var out: Array = cells.keys()
|
||||
out.sort_custom(func(a, b): return a.y * 1000 + a.x < b.y * 1000 + b.x)
|
||||
return out
|
||||
|
||||
|
||||
# 卡死赌挖选格(普通档 v3.1 2026-10-01——模拟档位重构):概率启发近似真人「挑看起来最安全的一格」。
|
||||
# 危险度 = 该格对每个邻接已证数字约束取(余雷数/未知数)比值中的最小值(= 任一邻数字视角下的
|
||||
# 最低雷占比——single 已证安全格在进入本函数前已被 perfect_action 消化,故卡死态比值恒 >0);
|
||||
# 同危险度行主序先到先得。纯查询面零 RNG(确定性保回放);寻路同 choose_dig(目标已开 8 邻
|
||||
# 首个可达者为 hero_cell)。
|
||||
static func gamble_pick(minesweeper) -> Dictionary:
|
||||
var cons := _constraints(minesweeper, minesweeper.current_board(), {})
|
||||
var best_h := 2.0
|
||||
var best := Vector2i(-1, -1)
|
||||
var revealed: Array = minesweeper.revealed_cells()
|
||||
var revealed_set := {}
|
||||
for c in revealed:
|
||||
revealed_set[c] = true
|
||||
var board = minesweeper.current_board()
|
||||
for y in board.height:
|
||||
for x in board.width:
|
||||
var c := Vector2i(x, y)
|
||||
if minesweeper.is_revealed(c) or minesweeper.has_flag(c):
|
||||
continue
|
||||
var adj := false
|
||||
for n in board.neighbors8(c):
|
||||
if revealed_set.has(n):
|
||||
adj = true
|
||||
break
|
||||
if not adj:
|
||||
continue
|
||||
var h := 1.0
|
||||
for con in cons:
|
||||
if (con["unknown"] as Dictionary).has(c):
|
||||
var ratio := float(con["mines"]) / float((con["unknown"] as Dictionary).size())
|
||||
h = minf(h, ratio)
|
||||
if h < best_h - 0.0001:
|
||||
best_h = h
|
||||
best = c
|
||||
if best.x < 0:
|
||||
return {}
|
||||
for n in board.neighbors8(best):
|
||||
if minesweeper.is_revealed(n) and (n == minesweeper.hero_pos() or not minesweeper.compute_move_path(n).is_empty()):
|
||||
return {"dig_cell": best, "hero_cell": n}
|
||||
return {}
|
||||
@@ -34,10 +34,14 @@ extends RefCounted
|
||||
const AutoPlayer := preload("res://smoke/auto_player.gd") # O4 收口:自动玩家策略单一实现
|
||||
|
||||
# ── 普通档 v3 失误注入参数(2026-10-01 用户规格:踩雷期望=完美+2/板、每板少挖几个正确格)──
|
||||
# 标雷→误挖转化率:每板已证雷 ~9-14 颗 × p ≈ 2-3 次踩雷(目标完美+2/板±0.3——首测读数后校准此值)
|
||||
const NORMAL_MINE_SLIP_P := 0.22
|
||||
# 标雷→误挖转化率:v3.2 实证 0.22 时普通档 0/100 全灭(首轮大量已证旗=保底命中,非真人失误
|
||||
# 形态——真人几乎不挖自己插旗的格);降 0.10 = 偶发真手滑,主踩雷源=卡死赌挖(不确定性概率命中)
|
||||
const NORMAL_MINE_SLIP_P := 0.10
|
||||
# 安全挖跳过率:每板安全格 ~70-90 × p ≈ 3-5 次漏挖(信息与推进双损失)
|
||||
const NORMAL_SKIP_DIG_P := 0.05
|
||||
# 空闲提前赌挖率(v3.4):已证安全格在手时小概率先赌一格——完美系把不确定性攒到残局
|
||||
# (残局 hazard→1=扫雷),真人早赌滚信息(低 hazard 期吃掉不确定性);p×~40 安全 AP/板 ≈ 4 次
|
||||
const NORMAL_IDLE_GAMBLE_P := 0.10
|
||||
|
||||
|
||||
static func run_level(db, seed_val: int, level_index: int, atk_pct: int, hp_pct: int, collect_rows: bool = false, logger = null, policy: String = "normal", route: String = "min", template_pick: int = -1) -> Dictionary:
|
||||
@@ -376,7 +380,7 @@ static func _autoplay_battle(runner, settlement, st: Dictionary, logger) -> void
|
||||
action_guard -= 1
|
||||
var act: Dictionary
|
||||
if bool(st.get("adv", false)):
|
||||
act = _apply_normal_slips(AutoPlayer.perfect_action(settlement.minesweeper, settlement), st) # v3:完美+失误
|
||||
act = _apply_normal_slips(AutoPlayer.perfect_action(settlement.minesweeper, settlement), settlement, st) # v3:完美+失误
|
||||
else:
|
||||
act = AutoPlayer.novice_action(settlement.minesweeper) # 单关机制夹具:v2 新手画像保持
|
||||
var kind := String(act.get("kind", "stop"))
|
||||
@@ -405,12 +409,15 @@ static func _autoplay_battle(runner, settlement, st: Dictionary, logger) -> void
|
||||
logger.log_action("stop", Vector2i(-1, -1), _accepted(out_s), {"round": start_round})
|
||||
|
||||
|
||||
# 普通档 v3 失误注入(2026-10-01 用户规格):只在完美策略的两类动作上出手——
|
||||
# 普通档 v3 失误注入(2026-10-01 用户规格):三类——
|
||||
# ①标雷误挖:把「标旗已证雷」动作直接转成「挖该格」(真人手滑原型:知道是雷、位置点错,
|
||||
# 踩雷吃伤且该雷奖励报废);期望踩雷增量 ≈ 每板已证雷数 × NORMAL_MINE_SLIP_P(目标完美+2/板)
|
||||
# ②安全挖跳过:把「挖已证安全格」动作转成本轮停手(少挖几个正确的雷——信息与推进双损失)
|
||||
# ③卡死赌挖:完美档无已证动作时刷新/停手拖轮次吃敌方垫刀(实证=完美档 41% 通关全败于慢玩
|
||||
# 垫刀非踩雷)——真人会按概率赌一个边界格(用户实证口径「有些地方因为我看不到数字,也是盲挖
|
||||
# 的」);普通档不刷新(用户自报全程没用刷新),赌挖替代刷新/停手
|
||||
# 失误流 = st.prng(策略流 RNG,种子派生自局种子——同种子逐位可回放;核心七流零消费零扰动)
|
||||
static func _apply_normal_slips(act: Dictionary, st: Dictionary) -> Dictionary:
|
||||
static func _apply_normal_slips(act: Dictionary, settlement, st: Dictionary) -> Dictionary:
|
||||
var prng: RandomNumberGenerator = st.get("prng")
|
||||
if prng == null:
|
||||
return act
|
||||
@@ -418,12 +425,33 @@ static func _apply_normal_slips(act: Dictionary, st: Dictionary) -> Dictionary:
|
||||
if kind == "flag" and prng.randf() < NORMAL_MINE_SLIP_P:
|
||||
st.mine_slips = int(st.get("mine_slips", 0)) + 1
|
||||
return {"kind": "dig", "cell": act.get("cell")}
|
||||
if kind == "dig" and prng.randf() < NORMAL_SKIP_DIG_P:
|
||||
st.skip_digs = int(st.get("skip_digs", 0)) + 1
|
||||
return {"kind": "stop"}
|
||||
if kind == "dig":
|
||||
var roll := prng.randf()
|
||||
if roll < NORMAL_SKIP_DIG_P:
|
||||
st.skip_digs = int(st.get("skip_digs", 0)) + 1
|
||||
return {"kind": "stop"}
|
||||
if roll < NORMAL_SKIP_DIG_P + NORMAL_IDLE_GAMBLE_P:
|
||||
var idle := AutoPlayer.gamble_pick(settlement.minesweeper)
|
||||
if not idle.is_empty():
|
||||
return _gamble_action(idle, settlement)
|
||||
if kind == "refresh" or kind == "stop":
|
||||
var plan := AutoPlayer.gamble_pick(settlement.minesweeper) # v3.2:概率启发赌挖(choose_dig 行主序=概率最差格,实证 199/200 死第二战——退役)
|
||||
if not plan.is_empty():
|
||||
return _gamble_action(plan, settlement)
|
||||
return act
|
||||
|
||||
|
||||
# 赌挖动作组装(v3.4 抽出):目标邻接=直接挖,否则先移到目标的已开邻格(下一拍再挖)
|
||||
static func _gamble_action(plan: Dictionary, settlement) -> Dictionary:
|
||||
var ms = settlement.minesweeper
|
||||
var hero: Vector2i = ms.hero_pos()
|
||||
var target: Vector2i = plan.dig_cell
|
||||
var d := Vector2i(absi(target.x - hero.x), absi(target.y - hero.y))
|
||||
if maxi(d.x, d.y) == 1:
|
||||
return {"kind": "dig", "cell": target}
|
||||
return {"kind": "move", "cell": plan.hero_cell}
|
||||
|
||||
|
||||
# 完美策略档战斗驱动(2026-09-14):单步决策循环——move/dig/flag 经 排雷玩法 settle_batch 提交,
|
||||
# refresh 经 settlement.player_request_refresh(战斗结算 核心编排:行动经济 扣 RAP + 退役 + 当场换新板),
|
||||
# stop 出内环走统一停手提交。连续拒绝 ≥3 = 编排违约防御(fail-fast 语义,停手防死循环)。
|
||||
|
||||
Reference in new issue
Block a user