raging_bolt_ogerpon トレース診断と 3 つの構造バグ修正 (2026-07-10)¶
前日のチューニングラウンド は
「80 trial 探索しても現行 params を超えない、全 config 勝率 2〜8%」で終わり、
ボトルネックがパラメータでなくロジックにあることを示した。本ノートは
その敗因診断 (pca.analysis behavior + records の behavior trace) と修正の記録。
診断手順¶
- raging_bolt vs dragapult の 2 体 pool で 60 games、records JSONL を収集
python -m pca.analysis behaviorで行動サマリ + readable game logs- records の
meta.legal_option_trace / selected_option_trace / board_traceを集計 (提示された攻撃 vs 選択された攻撃、リトリート機会、手張り先の型)
発見した構造バグ (重症度順)¶
1. ワザ ID が全て None (言語ミスマッチ)¶
_find_attack_id("きょくらいごう") は ALL_ATTACKS を日本語名で全走査するが、
エンジンのワザ名は英語 ("Bellowing Thunder")。11 個の A_* 定数が全て None
に落ち、動的ダメージ計算が死んでいた:
- Bellowing Thunder は静的 damage=0 (可変打点) → score_attack が常に effect_only (500) → PLAY (1000〜22000) に常敗 → フィニッシャーが 60 games で 0 回発射 (提示は 49 回あった)
- 修正: カード自身のワザリストからコスト長で構造的に解決 (
_attack_of)、 名前は日英両対応のフォールバック。回帰テスト (AttackIdResolutionTest) で全定数の解決を lock
2. score_retreat がほぼ全ての合法リトリートをブロック¶
エネ準備完了の Bolt がベンチにいる状態で RETREAT 合法 106 回中、実行 15 回。
原因は heuristics.proactive_retreat_score の
energy_count(active) < retreat_cost → None — エンジンが合法と判定済みの
オプション (Latias スカイラインの無料逃げ含む) を手動再チェックで却下していた。
heuristics は凍結共有のため触らず、raging_bolt の score_retreat を自前化:
- KO ロック (
retreat.lock_ko25000) / {L}{F} 準備完了 Bolt の昇格 (retreat.promote_ready_bolt21000、型チェック付き) / 被弾フォールバック - 教訓: 合法オプションのスコアリングでコスト・合法性を再チェックしない (エンジンが既に保証している)
3. 手張り・エネサーチが Grass 偏重で {L}{F} が揃わない¶
Bolt ex への手張り実績: Grass 60 / Lightning 35 / Fighting 17。 Bellowing Thunder のコストは {L}{F} 固定なのに、score_attach は Lightning +5000 / Grass +2500 / Fighting +0 だった。さらに Crispin (アカマツ) のエネ選択も全型フラット 13000 で Grass が先頭優先。
- 修正: 「欠けているコスト型を埋める手張り」を最優先
(
attach_energy.cost_complete_bonus8000)、Crispin 選択もコスト完成型を 15000 に昇格 - 併せて attach_energy.* params が main.py 未参照だった乖離を解消 (tuning 空間がこの 3 キーを回しても無効だった — SKILL の「よくあるミス」そのもの)
結果 (A/B、同一 seed)¶
| 指標 (vs dragapult 22 games) | 修正前 | 修正後 (3 つ込み) |
|---|---|---|
| 勝率 | 0% | 9% |
| Bellowing Thunder 発射 | 0 回 | 8/22 games |
| 攻撃回数/game | 1.68 | 2.50 |
6 体プール 400 games (tuning と同一相手、seed 123): 完走勝率 6.9% → 12% (raging_bolt は 51 games しか出ないため ±7% 級の ノイズ、有意差は主張しない)、攻撃 4.06 回/game。ミラーは山切れ 7/8 → 攻撃 14 回/game の実ゲーム化。
追記 (2026-07-11): Bellowing 非 KO ガード¶
上記修正で Bellowing が撃てるようになった副作用として、KO に届かない Bellowing (例 280 vs 320HP) がエネを全捨てして発射される局面が現れた。 tier システムは生ダメージ値しか見ないため表現できない劣位手。score_attack に ガードを追加:
- 非 KO の Bellowing は
attack.bellowing.non_ko_skip_score(-500, END より下) → 次ターンの KO まで貯める - 次ターン Active を失う (
combat.opponent_can_ko_me+ ベンチ KO 不在) 時のみdesperation_score(6000) でチップ発射を許可 (エネはどうせ失うため)
A/B (同一 2 体 60g seed 0): vs dragapult 勝率は 9% → 5% (22 games、 ±10% でノイズ範囲)。ガードは劣位手を除去する正しい修正だが、勝率の ボトルネックはセットアップ速度であり単独では動かない (下記残課題 1)。 tier を狭めて非 KO 発射を抑えた前回 tuning best.yaml とも整合するため、 ガードをコードで恒久化し params 化して tuning に委ねた。
追記 (2026-07-11): 0 打点 Bellowing ループ (unfinished の主因)¶
トレース (pca.analysis behavior + records) で raging_bolt ミラーが 50-70
ターンの無限ループになり max-steps 引分になる原因を特定:
score_attackは Bellowing の打点を「場の基本エネを全捨て」前提 (70×6=420) で計算 → KO 圏と判断し ATTACK を選択- しかし直後の
SelectContext.DISCARD_ENERGY_CARD(どのエネを捨てるか) は 汎用score_discardに流れ、エネは「keep = -2000」で 0 枚選択 rank_optionsは score<0 を min_count まで捨てるため 0 枚 → 実打点 70×0 = 0 → 相手 HP 満タンのまま毎ターン同じ → max-steps ループ
score_attack の全捨て前提と discard 選択の温存が矛盾していた。
score_bellowing_discard を追加し DISCARD_ENERGY_CARD では全捨て
(attack.bellowing.discard_score = 20000, rank_options が全選択) にして
前提と一致させた。このデッキの DISCARD_ENERGY_CARD は Bellowing のコスト
専用 (相手強制の捨札は相手の選択) なので安全。
検証: ミラー 40g で DISCARD_ENERGY_CARD 73/73 でエネ選択 (修正前 0)、 最長ターン 32 に収束 (修正前 47/53/69)。6 体プールで raging_bolt の unfinished は 実相手 5 種すべて 0、残るのは vs iono のみ (iono は凍結・自身のミラーで 21/22 停滞 = iono 側の問題、範囲外)。
教訓: 動的打点ワザは「打つ判断」と「コスト支払いの選択」が別コンテキストに 分かれる。両者の前提を一致させないと 0 打点空撃ちになる (attack を選ぶ score と discard/number を選ぶ score の整合性を必ず確認)。
追記 (2026-07-11): セットアップ速度の調査結論 — ロジックは概ね正常¶
vs dragapult 19 games の序盤トレースを定量化した結果、セットアップの 主要ロジックは正しく機能していることが判明 (当初「速度が主犯」と仮説を 立てたが、単一の修正可能バグは残っていない):
- 手張り先: 85 回中 72 回 (85%) が Raging Bolt (ex/基本) に。誤爆は Kangaskhan 3 / Fezandipiti 3 等の少数で、多くは Bolt 不在時の消化的手張り
- 先発: Ogerpon (エンジン) 65 / Raging Bolt ex 7 / Iron Leaves 6 — Ogerpon 先発が大半 (正しいプラン)。Fezandipiti 先発の事故手は稀
- Ogerpon 特性: 発動できる局面で発動。3 エネ貯める前に退却して Bolt を 昇格させる (正しいエンジン運用) ので、まんようしぐれ未使用も設計通り
- アカマツ (Crispin): 提示 7 回中 6 回プレイ (86%)。引けた時は撃つ
Bellowing 初発射は良い試合で自分の 3-4 ターン目。これはデッキの自然な 速度であり、dragapult (2-3 ターン目に KO 開始) への遅れはアーキタイプ 固有の速度不利。残る勝率差 (~5-12%) はこの 6 体メタでの遅い後手デッキの 天井に近く、ルールの微調整では 2 倍にはならない。
次アクション (優先順を更新)¶
- 再チューニング — 今日までの修正で attach / retreat / tier / bellowing / prize_race の各 params が実際に挙動へ効くようになった (以前は死んでいた)。 これらを回すのが最も費用対効果が高い
- ベンチ構成 / プライズ献上の抑制 — 場が ex だらけで相手のサイドレースが 速い。非 ex 基本 Raging Bolt を壁に使う判断は turn planner (フェーズ認識) 領域。中規模
- メタ再考 — raging_bolt がこの環境で構造的に不利なら、agent の投資先 としての優先度自体を ryo さんと再検討する余地
参考: iono_bellibolt の停滞 (範囲外だが要記録)¶
iono_bellibolt (凍結) は自身のミラーで 22 戦中 21 引き分け = agent 自体が
停滞する。raging_bolt の vs iono unfinished 8/11 はこの iono 側の問題。
凍結のため本タスクでは触れないが、提出プールに入れると全体の unfinished 率を
押し上げるため、ryo さん判断で configs/rule_agents.yaml の match_weight を
下げる / enabled: false にする検討余地がある。
教訓 (他 agent にも適用すべき)¶
- ワザ/カード名でのマッチングは言語依存で壊れる。ID は構造 (カード → ワザリスト、コスト長) から解決する。raging_bolt 以外に該当 agent は無いことを grep で確認済み
- 合法オプションの再合法性チェックは書かない
- params.yaml のキーを main.py が本当に読んでいるかは
grep 'PARAMS.get' main.pyで機械的に検証できる (tuning 空振りの早期検出)