Rule-Based Agents 再設計 — 設計問題・実装方針・戦略思考¶
作成日: 2026-07-05
先行資料: 2026-06-29-rule-agent-bootstrap.md
概要¶
src/pca/rule_agents/ は Belief-Guided Neural
ISMCTS のブートストラップ・自己対戦相手プール・Elo 評価基準の 3 役を担う。現時点で 30 agent
/ 約 20k 行あり、以下の問題を抱える:
- 1 デッキ 1 モノリスで重複と非対称チューニングが混在
- スコアリング閾値はマジックナンバー、由来説明もチューニング機構もなし
- アルゴリズムが「その 1 手のスコア独立評価」に閉じており、ターン全体の計画・相手読み・複数手の連携を表現できない
- 勝率が 0.045 〜 0.676 の 15 倍差
本ドキュメントは:
- notebook 由来 agent (10 種) を 基準ベースラインとして凍結 した上で、
- 手書き agent (残り 20 種) を対象に 3 層アーキテクチャ + params.yaml + Trace + Golden test で再設計し、
- 加えて アルゴリズムそのものを「ターン計画 + 相手読み + 局所探索」に拡張 する方針を示す。
制約: notebook 由来 agent は基準として凍結¶
notebooks/rule-ai-agent/ の Kaggle
notebook を移植した agent は、Elo 評価と回帰基準として実装を保存する。ソースファイル冒頭に
# Auto-extracted from notebooks/... を持つものが該当する。
凍結対象 (10 agent、touch 禁止)¶
| agent_id | 出典 notebook |
|---|---|
alakazam_ex_not_psychic |
rule-based-not-psychic-alakazam-best-5th.ipynb |
archaludon_ex_metal |
a-sample-archaludon-75-wr-vs-my-1300-starmie.ipynb |
dragapult_ex_phantom_dive |
a-sample-rule-based-agent-dragapult-ex-deck.ipynb |
dragapult_ex_phantom_dive_or_go_home |
phantom-dive-or-go-home-a-dragapult-ex-deck.ipynb |
dragapult_ex_tempo |
dragapult-v3-tempo-ptcg-ai-battle-agent.ipynb |
garchomp_ex_cynthia |
a-sample-cynthia-garchomp-ex-deck.ipynb |
generic_advanced_notebook_heuristic |
pok-mon-tcg-advanced-heuristic-planning-agent.ipynb |
generic_mirror_setup_speed |
mirror-setup-speed.ipynb |
generic_multiply_agent |
multiply-agent-best-940-lb.ipynb |
iono_bellibolt_ex_lightning |
a-sample-rule-based-agent-iono-s-deck.ipynb |
mega_abomasnow_ex_water_grass |
a-sample-rule-based-agent-mega-abomasnow-ex-deck.ipynb |
mega_lucario_ex_fighting_gong |
a-sample-rule-based-agent-mega-lucario-ex-deck.ipynb |
mega_lucario_ex_v62 |
ptcg-mega-lucario-ex-v62.ipynb |
mega_venusaur_ex_grass_sustain |
mega-venusaur-ex-deck-v2-rule-based-agent.ipynb |
moltres_ex_removal |
japanese-ex-moltres-removal.ipynb |
starmie_ex_archaludon_counter |
japanese-ex.ipynb |
crustle_mysterious_rock_inn |
crustle-bot.ipynb |
これらの main.py は バグ修正・パフォーマンス改善を含めて改変しない。理由:
- Elo 基準の再現性。Neural agent の改善は「凍結 rule agent との勝率差分」で測る。基準側を触ると過去との比較が壊れる。
- notebook 版の元コード互換。提出時に notebook そのままの挙動を再現できるようにする。
- 回帰検出。共有 heuristics.py を触ったとき、凍結 agent の勝率が動いていないか自動テストする。
改変可能な agent (手書き系 20 種)¶
以下は本再設計の対象。既存の handwritten agent + city_top16 系列。
clefairy_ogerpon_fairy_zone,festival_lead_appletun,grafaiai_dark_spread,honchkrow_rocket_toolbox,raging_bolt_ogerpongarchomp_ex_cynthia_city_top16,mega_sharpedo_ex_city_top16,n_zoroark_ex_city_top16,slowking_psychic_city_top16,terastal_box_jewel_search_city_top16wugtrio_ex_tricolor_pump,generic_advanced_heuristic,generic_advanced_notebook_heuristic(このうち凍結指定を除く)
これらは自由にリファクタリング・archetype layer への切り出し・params.yaml 化する。
凍結境界を守るためのガード¶
src/pca/rule_agents/agents/<frozen>/main.pyの先頭に# FROZEN: do not edit. See docs/research/2026-07-05-rule-agents-redesign.mdを追加tests/rule_agents/test_frozen_hash.pyで SHA-256 をロックし、CI で改変検知- 共有
heuristics.pyの関数シグネチャを変えるときは、凍結 agent の import が壊れないか import test で確認
デッキ固有動作の設定機構¶
Yes, デッキごとに個別に設定できる。3 層構造で "共通/族/固有" を分離し、固有部分は 2 つのレベル (宣言的 = params.yaml / 手続的 = main.py override) で表現する。
設定の 2 レベル¶
Level A: params.yaml (宣言的、tuning 可能)
- スコア閾値、ボーナス、優先度など 数値 で表現できるものすべて
- tuning runner から grid / CMA-ES で自動最適化可能
- 例: "アカマツを手札に雷エネルギーがない時 22000 点"
Level B: main.py override (手続的、tuning 不可能)
- 条件分岐が複雑でコードで書いた方が明快な "そのデッキだけの動き"
- 100〜200 行を上限に据え、超えたら archetype layer に切り出す
- 例: "Iron Crown ex を bench に 1 手目で置く、Rapid Vernier でメガフシギバナのデバフを無効化"
具体例: raging_bolt_ogerpon¶
# src/pca/rule_agents/agents/raging_bolt_ogerpon/params.yaml
version: 1
archetype_layers:
- energy_engine # Ogerpon 系の共通エネ加速ロジック
- mega_setup # メガガルーラ準備
- draw_engine # メガガルーラのドロー特性
setup:
active_priority:
ogerpon: 100000 # T1 に確実に active (エンジン起動)
raging_bolt_ex: 60000 # フォールバック (メインアタッカー)
mega_kangaskhan_ex: 30000
latias_ex: 20000
attach_energy:
key_attacker_lightning_bonus: 5000
key_attacker_grass_bonus: 2500
engine_grass_bonus: 2000
overcap_penalty: -1000
supporter:
akamatsu_no_lightning_in_hand: 22000
akamatsu_no_grass_in_hand: 20000
akamatsu_generic: 9000
boss_lethal: 50000
items:
hyper_ball_empty_bench: 22000
hyper_ball_generic: 15000
glass_trumpet_no_basic_energy: 17000
opp_max_damage_overrides:
dragapult: 240
# src/pca/rule_agents/agents/raging_bolt_ogerpon/main.py
# 100〜200 行のデッキ固有ロジックのみ
from ..._shared import RulePipeline, AgentContext
def deck_specific_bench_priority(ctx: AgentContext, card_id: int) -> tuple[int, str] | None:
"""Iron Crown ex を必ず bench に置く (Rapid Vernier でデバフ無効化)"""
if card_id == P_TETSUNOIBARA_EX:
return (19000, "bench Iron Crown ex (Rapid Vernier — play first)")
return None
def register(pipeline: RulePipeline) -> None:
pipeline.hooks.bench_priority.append(deck_specific_bench_priority)
RulePipeline は archetype layer + universal
layer をコンポーズしたもので、フックポイント (bench_priority, attach_bonus,
boss_target_selector など) で override を差し込める。
アルゴリズム自体の問題分析¶
現行の rule agent は本質的に 1 手を独立にスコアリングする reactive scorer である。以下の 6 つの構造的欠陥を持つ。
1. スコア合成が「校正されていない加算」¶
SCORE_BOSS_LETHAL=50000 と SCORE_HYPER_BALL_SEARCH=18000
は "ボスの方が優先" を表現しているだけで、比率 (50000/18000 ≈
2.78) には何の意味もない。閾値 A + 閾値 B の加算合成が起きたとき、結果は無意味な相対関係になる。
現行: score = base + bonus1 + bonus2 + ...
問題: bonus 同士が競合しても補正されない、絶対値の大小に意味がない
対策案:
- スコアを 順序 (rank) として設計。tier (0〜9) + tier 内優先度 で表現
- または 確率としての policy 出力: softmax 温度でスケール、tuning で校正
2. Look-ahead ゼロ¶
各 option を その瞬間の盤面 だけで評価しており、"この手を打った後にどうなるか" を見ていない。
症状:
- 攻撃準備の完了を「次ターンにあと 1 エネで殴れる」で判断できない
- boss で引きずった相手を 今ターン中に KO できるか を計算しない → 引きずった意味がない引きずり
- 進化 → 攻撃の 2 手連鎖を単一 option 評価では表現できない
対策案:
- 1〜3 手先の determinized look-ahead (簡易 CABT sim を rule 側でも持つ)
- または turn plan: ターン開始時に "今ターンの目的" を決定 → 各 option を "計画達成に寄与するか" で評価
3. 独立評価: 手の組み合わせを表現できない¶
「エネ張り + 攻撃」「サーチ + プレイ」の 2 手を同時に考慮できない。
症状:
- エネ張りを別の pokemon にしてしまい、直後の攻撃で必要エネが足りない
- Hyper Ball で 2 枚トラッシュを "その 2 枚で失うもの" を評価せず選ぶ
対策案:
- plan-and-execute: ターン開始で "今ターンにやりたい 3 手" を立て、以降の option 評価はその文脈で判定
- または SelectContext ごとに 同ターン内で既に選ばれた option を context に注入
4. 相手モデル不在¶
自分の手のスコアリングにしか関心がなく、相手が次に何をしそうか を推論しない。
症状:
- Boss の指令の狙撃先選定を "prize × energy × stage" の静的スコアだけで決める → 相手の脅威度は動的
- 自分のベンチ狙撃されそうな pokemon を判別できない → 場に出すべきでない場面で出す
- 相手の手札枚数からアンフェアスタンプの成功率を推定しない
対策案:
- 軽量 opponent modeling: 相手 archetype + 相手 discard から "次ターンの想定打点分布" を軽く推論
- Neural 側の BeliefNet を rule agent からも呼べる薄いラッパを提供 (Phase 2 以降)
5. Resource budget が暗黙¶
1 ターン = supporter 1 / energy attach 1 / retreat 1 (基本) の予算を 各 SelectContext が独立に消費 しており、"今ターンあと何を残しているか" が rule 側の思考に入っていない。
症状:
- supporter を序盤に軽い理由で切り、後半にボスを使えない
- retreat を無駄に切って攻撃準備が崩れる
対策案:
- ターン開始時に
TurnBudget = {supporter: 1, attach: 1, retreat_used: false}を追跡 - 各 option を "budget 消費に見合う価値か" で評価
6. ターン計画の欠如¶
現在は 状況反応 (SelectContext ごとに独立スコアリング) に閉じており、ターン単位のゴール (今ターン何を達成したいか) の概念がない。
症状:
- 序盤に「盤面展開」「エネルギー加速」「サーチで手札の質を上げる」のどれを優先するかがコード上で表現されない
- 対戦のフェーズ (setup / trade / endgame) 認識がない
対策案:
- ターン開始時に TurnGoal を選ぶ:
SETUP— ベンチ展開・進化下ろし・エネ加速PRESSURE— 攻撃を通しつつ盤面維持LETHAL— 今ターン KO でサイド確定STALL— 対面不利で耐える- 各 SelectContext のスコアリングを TurnGoal で条件付ける
これら 6 点は アルゴリズムを "reactive scorer" から "planner + reactive scorer" に拡張 する形で解消できる。以下の 3 層アーキテクチャ にこれを組み込む。
ポケカ戦略を AI に実装する方法論¶
ここが本節の一番重要な部分。「デッキごとの立ち回り」を どうやって発見・形式化・コード化するか の作業手順を明文化する。
手順¶
1. 立ち回り知識の収集
↓
2. Game Plan 形式化 (turn goal + kill path + threat map)
↓
3. パラメータ空間の切り出し (tunable vs fixed)
↓
4. archetype layer への配置 or deck-specific 実装
↓
5. Golden fixture で "この局面でこの手" を固定
↓
6. 自己対戦でチューニング
↓
7. Trace レビューでミスを修正
Step 1: 立ち回り知識の収集¶
入力: 大会入賞レシピ・海外 YouTube 解説・Kaggle notebook のコメント・ポケカ公式ブログ
成果物 (src/pca/rule_agents/agents/<agent_id>/strategy.md) — 対応する機械可読版
strategy.yaml を並置:
# raging_bolt_ogerpon strategy note
## 勝ち筋
- T1: Ogerpon active + Raging Bolt bench + 草エネ手張り
- T2: Ogerpon エネ加速 → Raging Bolt に手張り + アカマツで雷を追加
- T3: Raging Bolt にエネ 3+ → Burst Lightning で KO
## 脅威への対応
- Dragapult: ベンチ狙撃 → Ogerpon 保護のため Latias skyline で pivot
- Mega Lucario: 高打点 → 先攻優位、Iron Crown で built-in draw 妨害
## リソースの優先順位
- Akamatsu > その他 supporter (エネ加速のため)
- Hyper Ball は 1 枚温存 (終盤の Iron Crown サーチ用)
## Bench Composition (理想)
- Active: Ogerpon
- Bench 1: Raging Bolt ex
- Bench 2: Iron Crown ex (Rapid Vernier)
- Bench 3: Mega Kangaskhan ex (draw engine)
- Bench 4: Latias ex (free retreat)
重要: この strategy note を書けない agent は作らない。言語化できない立ち回りはコードにできない。
Step 2: Game Plan の形式化¶
strategy note を TurnGoal state machine に落とす:
# src/pca/rule_agents/agents/raging_bolt_ogerpon/game_plan.yaml
turn_goals:
- name: SETUP
condition: "turn <= 2 or active_energy < 2"
priorities:
- fill_bench_with_key_pokemon
- accelerate_energy_via_ogerpon
- search_key_cards
- name: PRESSURE
condition: "turn >= 3 and active_energy >= 2 and can_attack_next_turn"
priorities:
- attach_to_main_attacker
- draw_via_kangaskhan
- preserve_supporter_for_boss
- name: LETHAL
condition: "can_ko_active_this_turn or (opp_prize == 1 and can_boss_target)"
priorities:
- boss_target_selection
- burst_lightning_energy_maximization
- attack
threat_responses:
dragapult:
- keep_ogerpon_low_hp_off_bench
- prefer_latias_pivot
mega_lucario:
- iron_crown_priority_high
- conserve_hyper_ball
成果物: agent ごとの game_plan.yaml。turn goal を決めるルール + archetype 別 threat
response を宣言的に持つ。
Step 3: パラメータ空間の切り出し¶
game plan の中で 数値化できる部分は全て params.yaml に:
- スコア閾値
- 優先度の順序
- 条件式の threshold (
active_energy < 2の2)
手続的な部分だけを main.py に残す。
Step 4: archetype vs deck-specific の判断¶
「他のデッキでも使えるロジックか?」でふるい分ける:
- archetype layer 行き: Ogerpon エネ加速、Rocket supporter chain、Stage2 rush、bench spread
- deck-specific 行き: Iron Crown 早出し、フェアリーゾーン弱点付与、"このカード特有の効果" 全般
判断に迷ったら deck-specific から始めて、2 デッキ目で同じロジックが出たら archetype に昇格 させる。
手順5: 基準となるテストデータ¶
strategy note の各 kill path から代表局面を fixture 化:
tests/rule_agents/golden/raging_bolt_ogerpon/
t1_setup_ogerpon_active.json/expected.yaml
t2_akamatsu_for_lightning.json/expected.yaml
t3_burst_lightning_ko.json/expected.yaml
vs_dragapult_pivot_latias.json/expected.yaml
手書きで良い。5〜10 fixture / agent で十分。selfplay から自動収集した trace を種にする。
Step 6: 自己対戦チューニング¶
tuning runner で params.yaml を最適化:
uv run python -m pca.rule_agents.tuning \
--agent raging_bolt_ogerpon \
--search grid \
--params-space configs/rule_agents/tuning/raging_bolt_space.yaml \
--opponents starmie_ex_archaludon_counter,archaludon_ex_metal,dragapult_ex_phantom_dive_or_go_home \
--games-per-config 200 \
--parallel 8
対戦相手には 凍結 agent を含める。Elo 基準が動かないように。
Step 7: Trace レビュー¶
--rule-explain N で対戦の trace を吐き、負け試合を目視で:
- どのターンでミスをしたか
- なぜそのスコアになったか
- game_plan のどの条件が誤って発火したか
を確認して strategy note に反映 → コード修正 → 再チューニング。
私 (Claude) と ryo さんの役割分担¶
| 手順 | ryo さん | 私 |
|---|---|---|
| Step 1: 知識収集 | ★★★ 主導 (ポケカ知識) | 補助 (英語情報の翻訳、公式データ整理) |
| Step 2: Game Plan | ★★ 監修 | ★ 形式化 (yaml 化) |
| Step 3: パラメータ切り出し | ★★★ 主導 | |
| Step 4: archetype 分類 | ★ アドバイス | ★★ 実装 |
| Step 5: Golden fixture | ★★ 期待挙動を指定 | ★★ 実装 |
| Step 6: チューニング | ★★★ 主導 | |
| Step 7: Trace レビュー | ★★★ 主導 (ミス判定) | ★★ ミスの根本原因分析 |
3 層アーキテクチャの提案¶
Universal layer (deck 非依存 — 全 agent 適用)
├─ setup: hand の basic pokemon を active に
├─ deck-out 回避
├─ END_TURN は最後 (score=0)
├─ 攻撃可能なら必ず攻撃 (無理攻めは archetype でペナルティ)
├─ 空ベンチ safety (種切れ回避)
└─ 火傷/麻痺での retreat 判定
Archetype layer (デッキ族 — 有効化 flag で選択)
├─ energy_engine Ogerpon 系
├─ evolve_rush Stage2 早出し
├─ spread_damage ベンチダメカン蓄積
├─ rocket_toolbox Rocket supporter chain
├─ counter_swap Starmie / Wugtrio 系
├─ mega_setup Mega ex 進化準備
└─ draw_engine Kangaskhan / Meowth 特性
Deck-specific layer (100〜200 行の main.py override)
└─ カード固有の特殊効果 (Iron Crown, フェアリーゾーン 等)
--- 上記の上に、ターン計画層を追加 ---
Turn planner (ターン開始時に走る)
├─ TurnGoal 選択 (SETUP / PRESSURE / LETHAL / STALL)
├─ TurnBudget 初期化 (supporter/attach/retreat 予算)
└─ ThreatMap 更新 (相手 archetype 判定 + 想定打点)
Reactive scorer (各 SelectContext で走る)
└─ 各 option を "TurnGoal 達成寄与 + Budget 使用効率" で採点
これで アルゴリズム自体の問題 の 6 点に対応:
| 問題 | 対応 |
|---|---|
| 1. スコアが校正されていない | tier + 内部順位で表現、softmax で確率化 |
| 2. Look-ahead ゼロ | Turn planner で 1〜3 手先を想定 |
| 3. 独立評価 | TurnBudget で "既消費/残予算" を共有 |
| 4. 相手モデル不在 | ThreatMap で archetype ベースの脅威度を持つ |
| 5. Resource budget 暗黙 | TurnBudget を明示 |
| 6. ターン計画欠如 | TurnGoal state machine |
パラメータチューニング機構¶
(前セクション 具体例: raging_bolt_ogerpon 参照)
探索空間の書き方¶
# configs/rule_agents/tuning/raging_bolt_space.yaml
attach_energy.key_attacker_lightning_bonus:
type: choice
values: [3000, 4000, 5000, 6000, 8000]
supporter.akamatsu_no_lightning_in_hand:
type: choice
values: [18000, 20000, 22000, 25000]
items.hyper_ball_generic:
type: continuous
low: 10000
high: 20000
出力¶
data/rule_tuning/<agent>/history.csv— 全 config × 対戦相手の勝率data/rule_tuning/<agent>/top_k.yaml— 勝率トップ Kdata/rule_tuning/<agent>/best.yaml— 最良 params (書き戻し候補)
対戦相手セットの選び方¶
- 凍結 agent を必ず含める (Elo 基準連続性)
- 環境 Tier1 相当を 3〜5 種
- 同 archetype 同士も含める (ミラー適応性)
説明性 (Trace)¶
追加する型¶
@dataclass(frozen=True)
class TraceEntry:
option_index: int
score: float
reason: str
layer: str # "universal" | "archetype:energy_engine" | "deck"
tags: tuple[str, ...] = ()
@dataclass(frozen=True)
class RuleDecision:
selected: list[int]
scores: list[float]
target_policy: list[float] | None = None
trace: list[TraceEntry] = ()
turn_goal: str | None = None # ターン計画層追加後
turn_budget: dict[str, int] | None = None
meta: dict[str, Any] = ...
凍結 agent は空 trace を返す (後方互換)。改変可能 agent のみ trace を埋める。
selfplay 出力¶
uv run python -m pca.training.selfplay \
--rule-explain 20 \
--rule-explain-output data/rule_trace/2026-07-05.jsonl
分析ツール¶
uv run python -m pca.rule_agents.explain \
--trace data/rule_trace/2026-07-05.jsonl \
--agent mega_venusaur_ex_grass_sustain \
--show-turn-ends
例えば mega_venusaur が 0.045 に沈んでいる原因
(回復ループで END が来ない、等) を trace で追える。凍結対象なので修正はできないが、なぜ壊れているかを言語化してドキュメント化できる (src/pca/rule_agents/agents/mega_venusaur_ex_grass_sustain/known-issues.md)。
Golden Replay テスト¶
テストデータ¶
tests/rule_agents/golden/raging_bolt_ogerpon/
t1_no_lightning_in_hand.json # 観測 snapshot
t1_no_lightning_in_hand.expected.yaml
# expected.yaml
context: PLAY_SUPPORTER
must_include_option_card: アカマツ
forbidden_option_cards: [ボスの指令]
min_score: 15000
turn_goal: SETUP # ターン計画層追加後
継続的インテグレーション¶
uv run pytest tests/rule_agents/ -v
凍結 agent 用の hash guard¶
# tests/rule_agents/test_frozen_hash.py
FROZEN_AGENTS = {
"starmie_ex_archaludon_counter": "sha256:abcd...",
"archaludon_ex_metal": "sha256:1234...",
# ...
}
def test_frozen_agent_main_py_unchanged():
for agent_id, expected_sha in FROZEN_AGENTS.items():
path = Path(f"src/pca/rule_agents/agents/{agent_id}/main.py")
assert sha256(path.read_bytes()) == expected_sha, (
f"{agent_id} is frozen. See docs/research/2026-07-05-rule-agents-redesign.md"
)
3 つの利用プリセット¶
| プリセット | policy_target | option 選択 | 用途 |
|---|---|---|---|
teacher (default) |
selected_one_hot | argmax | 学習 policy 生成 |
pool |
score_softmax | softmax(T=0.5) | selfplay 対戦相手プール |
baseline |
selected_one_hot | argmax | Elo 評価 (固定) |
Agent 整理計画 (凍結境界を守る)¶
凍結: 17 agent (改変禁止)¶
前掲の notebook 由来リスト。全て main.py にロック。
改変可能・積極改善: 8〜13 agent¶
- 手書き系 5 種 (
raging_bolt_ogerpon,clefairy_ogerpon_fairy_zone,festival_lead_appletun,grafaiai_dark_spread,honchkrow_rocket_toolbox) - city_top16 系 5 種 (
garchomp_ex_cynthia_city_top16,mega_sharpedo_ex_city_top16,n_zoroark_ex_city_top16,slowking_psychic_city_top16,terastal_box_jewel_search_city_top16) - その他 (
wugtrio_ex_tricolor_pump,generic_advanced_heuristicなど)
削除・統合はしない¶
凍結 agent との比較性を保つため、当面 agent 数を減らさない。Elo baseline pool を痩せさせない ことを優先。
段階的移行フェーズ¶
Phase 1 (即時、1 週間)¶
- [x] 本ドキュメント作成
- [x]
RuleDecision.traceフィールド追加 (base.py、後方互換のため default 空) - [x]
--rule-explainフラグを selfplay に追加 - [x]
tests/rule_agents/test_frozen_hash.py追加 (凍結 hash lock) - [x]
src/pca/rule_agents/agents/_template/scaffold (README + strategy.md + strategy.yaml + params.yaml + known-issues.md)
Phase 2 (1〜2 週) — pilot: raging_bolt_ogerpon¶
- [x]
raging_bolt_ogerpon/strategy.mdを書く (ryo さん監修は継続) - [x]
params.yamlschema 定義、pilot agent を params 化 (setup / supporter / items / attack tier / prize_race) - [x] tuning runner (grid + optuna) 実装
- [ ] pilot で tuning 1 ラウンド、best params を書き戻す (次アクション、
--confirm-top-k 3推奨) - [ ] golden fixture 5 個
Phase 3 (2〜4 週)¶
- [x] 共有 combat 層 (
combat.py): リーサル判定 / ko_plan / 被リーサル推定 / プライズレース / 同ターン文脈。詳細: docs/architecture/rule-agent-combat.md - [ ] archetype layer 実装 (
layers/archetypes/*.py) - [ ] pilot を layer 上に載せ替え、main.py 200 行以下
- [ ] TurnGoal / TurnBudget / ThreatMap の型と Turn planner 実装 (prize_race がフェーズ判断の材料として先行実装済み)
- [ ] pilot に turn planner を統合
Phase 4 (4〜8 週)¶
- [ ] 残 handwritten agent 4 種を順次移行 (strategy-note → params → layer 移行 → golden test)
- [ ] city_top16 系 5 種を移行
- [ ]
wugtrio_ex_tricolor_pumpを tuning で修復試行 (凍結対象外)
Phase 5 (継続)¶
- [x] Optuna (TPE + MedianPruner) 統合 完了 (2026-07-06)。詳細: docs/architecture/rule-agent-tuning-optuna.md
- [x] Selfplay evaluator 実装完了 (subprocess ベース、
PCA_PARAMS_OVERRIDE_DIR経由) - [x] Tuning 信頼性改善 完了 (2026-07-09): baseline warm-start / seed 固定 / 確認ラン (ADR 0004) / match_weight 加重 objective
- [ ] CMA-ES / Hyperband への切り替え (Optuna sampler / pruner 差し替えで対応可)
- [ ] games 数 multi-fidelity 化 (Wilson 区間での早期打ち切り)
- [ ] 並列 config 実行 (multiprocessing.Pool)
- [ ] BeliefNet 相当の軽量 opponent modeling を rule 側にも提供 (
opponent_can_ko_meが静的打点版の先行実装) - [ ] 新環境デッキ対応
ディレクトリレイアウト (提案)¶
src/pca/rule_agents/
base.py # TraceEntry, RuleDecision 拡張
policy.py # unchanged
registry.py # unchanged
ported.py # unchanged
generic.py # unchanged
heuristics.py # 縮小 (observation helpers のみ)
params.py # NEW
planner/
__init__.py
turn_goal.py # NEW: TurnGoal state machine
turn_budget.py # NEW
threat_map.py # NEW
layers/
universal.py # NEW
archetypes/
energy_engine.py
evolve_rush.py
spread_damage.py
rocket_toolbox.py
counter_swap.py
mega_setup.py
draw_engine.py
tuning/
__main__.py
grid.py
space.py
explain/
__main__.py
trace.py
agents/
<frozen_deck>/ # 凍結: main.py touch 禁止
main.py # # FROZEN header
agent.py
deck.csv
<mutable_deck>/ # 改変可能
main.py # 100〜200 行 override
agent.py # archetype layer 宣言
deck.csv
strategy.md # NEW: 立ち回り解説 (人間可読)
strategy.yaml # NEW: 立ち回り (機械可読)
params.yaml # NEW: 数値パラメータ (auto-tuned)
_template/ # NEW: 新規追加時のコピー元 (登録対象外)
tests/rule_agents/
test_frozen_hash.py # NEW
test_golden.py
golden/<agent>/*.json,yaml
configs/rule_agents/tuning/
<deck>_space.yaml
data/rule_tuning/ # gitignore
data/rule_trace/ # gitignore
よくある質問¶
Q. なぜ notebook 由来 agent を凍結するのか?
A. Elo 基準の再現性と回帰検出のため。改善は "凍結 agent との勝率差分" で測る。基準側を触ると過去比較が崩れる。
Q. 凍結 agent にバグがあっても直せないのか?
A. main.py は触らない。代わりに src/pca/rule_agents/agents/<agent>/known-issues.md
に記録し、Neural 側の trace や上位 agent の派生でカバーする方向。
Q. デッキごとの動作を個別設定できるか?
A. Yes、2 レベルで:
- 数値化できる部分は
params.yaml(tuning 可能) - 手続的な部分は
main.py(100〜200 行の override)
Q. アルゴリズムの根本問題 (look-ahead ゼロ、相手モデル不在等) は本当に rule ベースで解決できるか?
A. 完全解決は無理。しかし Turn
planner + TurnBudget + ThreatMap で 今より 2〜3 段階の改善 はできる。それ以上は Neural
ISMCTS 側に任せる。rule agent の役割は "ある水準以上の相手 + 教師" であって "最強" ではない。
Q. Trace を全 agent に付けるコストは?
A. option ごとに TraceEntry を 1 個作るだけ。1 ゲーム 100 decisions × option 平均 20 個 = 2000
entry ≒ 数百 KB。selfplay 全数に付けても問題ないサイズ。
Q. ryo さんは何を提供すればいい?
A. 主に 3 つ:
- 各デッキの strategy note (立ち回り + kill path + threat map)
- Trace レビュー時のミス判定 (負け試合を見て「ここが違う」と指摘)
- fixture の expected 挙動 (「この局面ではこれを選ぶべき」)
コードは私が書く。ポケカ知識に関わる意思決定だけ ryo さん依存。