Rule Agent Planner (プラン先行スコアリング)¶
src/pca/rule_agents/planner.py — reactive
scorer の上に載せる共有のターン内攻撃プランナー。2026-07-15 の全プール調査で、上位 agent 全て (garchomp_cynthia
/ starmie / archaludon / generic_multiply) が同型の構造を持ち、同一デッキ比較で reactive
scorer を +14pt 上回る ことが判明したパターンの一般化。
- 調査: research/2026-07-15-rule-agent-algorithm-survey.md
- パイロット実測: raging_bolt_ogerpon で 3.87% → 5.40% (+1.53pt, z=2.00、1500g/側×2seed)
目的¶
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_energy の plan.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 優先、動的打点注入。