コンテンツにスキップ

Rule Agent Planner (プラン先行スコアリング)

src/pca/rule_agents/planner.py — reactive scorer の上に載せる共有のターン内攻撃プランナー。2026-07-15 の全プール調査で、上位 agent 全て (garchomp_cynthia / starmie / archaludon / generic_multiply) が同型の構造を持ち、同一デッキ比較で reactive scorer を +14pt 上回る ことが判明したパターンの一般化。

目的

reactive scorer は各オプションを独立採点するため、サブ決定間の矛盾が起きる (攻撃にコミットしたのに捨札選択がコストを払わない、L と F が別々のアタッカーに分散、退却で上げた先が意図と違う等)。プランナーは「このターンのベスト攻撃」を 1 個確定し、全サブスコアラーがプランとの一致で採点することで矛盾を消す。

公開API

from pca.rule_agents.planner import plan_turn_attack, TurnAttackPlan

plan = plan_turn_attack(
    obs,
    base_damage_fn=view.base_damage,   # デッキ固有の動的打点を注入 (combat と同じ契約)
    energy_type_fn=attack_energy_type, # 弱点計算用
)  # -> TurnAttackPlan | None

TurnAttackPlan の主フィールド:

フィールド 意味
attacker / target obs 上の実オブジェクト (identity 比較可)
attack_id / damage / remain_hp / is_ko / is_winning 期待打点と KO 判定
needs_energy 今ターンの手張り 1 枚を前提にしたプラン
needs_promote アタッカーがベンチ (退却/交代が先)
needs_boss ターゲットが相手ベンチ (ボスの指令が先)

アルゴリズム

(自分の Active+ベンチ) × (使用可能ワザ、手張り 1 枚仮定込み) × (相手 Active + ボス可能時のみ相手ベンチ) を全列挙し、以下で採点した最良 1 件を返す:

winning KO (1e7)  >>  KO (1e5 + プライズ価値×1000)  >>  チップ (価値 × dmg/hp)
+ Active アタッカー/Active ターゲット微ボーナス (追加カード不要なプランを優先)

ボス列挙は「ボスの指令が手札 + サポート未使用」の時のみ (combat.ko_plan と同じ)。手張り仮定は「energyAttached 未使用 + 手札に基本エネ」の時のみ。コスト判定は combat.usable_attacks と同じ枚数近似 (エンジンが違法手を弾く)。

消費側の配線 (raging_bolt の実装例、6 フック)

フック 採点
RETREAT needs_promote かつ (KO or Active に打点プラン無し) → 昇格退却
SWITCH/TO_ACTIVE (自分) plan.attacker と一致 → 最優先昇格
ATTACH / エネ付与先 needs_energyplan.attacker → ボーナス
PLAY (ボスの指令) needs_boss → プレイ (KO なら高)
SWITCH (相手 = ボス対象) plan.target と一致 → ボーナス
ATTACK plan.attack_id と一致 → 微ボーナス

すべて params.yaml plan.* で係数化 (0 でフック無効)。

落とし穴 (スモークで実測した反例)

退却フックだけ配線して昇格フックを配線しないと、退却→意図しないポケモンが昇格→また退却のスラッシュで攻撃回数が崩壊する (2.8→0.7 回/game)。退却と昇格は必ず対で配線し、退却側は「プランが KO」か「Active に打点プランが無い」場合にゲートする。

設計判断

  • combat.py と別モジュール: combat は「事実の計算」(KO 可能性、被リーサル)、planner は「意図の決定」(このターン何をするか)。消費の仕方が違う
  • 1 決定 1 プラン、obs にキャッシュ: per-option の stateless scorer から何度でも参照できる (multiply はグローバル変数 + ターン番号で同等のことをする)
  • プランは ordinal: score はプラン候補間の比較専用。オプションスコアへは agent 側の params 係数で写像する

既知の制約

  • 昇格の実行可能性 (退却コスト等) は列挙時に確認しない (エンジン任せ)
  • 2 ターン以上の計画 (「今ターンは貯めて次で 2 体取る」) は表現できない —その先は search (cg.api.search_begin、現在は旧シグネチャで全 agent 不使用) か ML/ISMCTS の領域

テスト

tests/rule_agents/test_planner.py — needs_energy 仮定の on/off、ボス列挙のゲート、ベンチアタッカー、winning KO 優先、動的打点注入。