自ら学び、自ら進む。
Claude Code が Pokemon Red を自律プレイする MCP Server。
graph LR
CC["Claude Code
画面認識 + 判断"] -->|"stdio"| MCP["MCP Server
gameboy_mcp_server.py"]
MCP -->|"TCP :9876"| EMU["emulator.py
TCP Client"]
EMU -->|"TCP"| PB["pyboy_server.py
PyBoy 60fps + SDL2"]
PB -->|"JSON"| EMU
PB -->|"mmap
/tmp/pyboy_screen.shm"| API["game_state_api.py
SSE 配信"]
EMU -->|"応答"| MCP
MCP -->|"stdio"| CC
style CC fill:#1a0a0a,stroke:#f8d030,color:#f8d030
style MCP fill:#3a1010,stroke:#e03030,color:#f0e8e0
style EMU fill:#3a1010,stroke:#e03030,color:#f0e8e0
style PB fill:#3a1010,stroke:#e03030,color:#f0e8e0
style API fill:#3a1010,stroke:#e03030,color:#f0e8e0
↺ Claude が自律的にループ — 配信は共有メモリ (mmap) で画面を直接読み取り
Claude Code 起動からゲームプレイまでの起動シーケンス。PyBoy サーバーは別プロセスで動作し、TCP 経由で接続する。
pyboy_server.py を別ターミナルで起動。SDL2 ウィンドウが表示され、TCP :9876 で待受開始。
このディレクトリで Claude Code を開くと .mcp.json を自動検出。MCP サーバーが子プロセスとして起動。
Claude Code が load_rom を呼ぶと、emulator.py が TCP 経由で pyboy_server.py に接続。ROM ヘッダから JP/EN を自動判定。
以降、Claude Code → MCP (stdio) → TCP → PyBoy サーバーに対して操作が続く。SDL2 ウィンドウでリアルタイム表示。
game_state_api.py が共有メモリ (mmap) から画面を直接読み取り、SSE でブラウザに配信。16:9 ポケモン赤テーマ。
graph TD
subgraph parent["Claude Code(親プロセス)"]
CC[Claude Code]
end
CC -->|"stdio (JSON-RPC)"| MCP
MCP -->|"stdio 応答"| CC
subgraph child["子プロセス: gameboy_mcp_server.py"]
MCP["FastMCP
gameboy_mcp_server.py"]
MCP -->|"関数呼び出し"| EMU["emulator.py
(TCP クライアント)"]
EMU -->|"応答 (JSON)"| MCP
end
EMU -->|"TCP :9876 コマンド送信"| SRV
SRV -->|"TCP 応答 (JSON)"| EMU
subgraph server["別プロセス: pyboy_server.py"]
SRV["PyBoy TCP サーバー
PNG 生成 → mmap"]
SRV --- PB["PyBoy エミュレータ
60fps + SDL2 表示"]
end
SRV -->|"mmap
/tmp/pyboy_screen.shm"| API
subgraph optional["オプション: game_state_api.py"]
API["FastAPI + SSE
配信オーバーレイ"]
end
API -->|"emulator.py を import
TCP :9876 経由で状態取得"| EMU2["emulator.py
(共有 TCP 接続)"]
EMU2 -->|"TCP :9876"| SRV
CC -->|"移動経験を自動蓄積"| NAV["nav_memory.py
自己学習ナビ"]
CC -->|"プレイ経験を記録"| MEM["CLAUDE.md / Memory
自己改善ルール"]
style parent fill:#1a0a0a,stroke:#e03030,stroke-width:2px,color:#f0e8e0
style child fill:#2a1010,stroke:#e03030,stroke-width:2px,color:#f0e8e0
style server fill:#2a1010,stroke:#f8d030,stroke-width:2px,color:#f0e8e0
style optional fill:#1a0a0a,stroke:#8a7a70,stroke-width:1px,stroke-dasharray:5,color:#f0e8e0
style CC fill:#3a1010,stroke:#f8d030,color:#f8d030
style MCP fill:#3a1010,stroke:#e03030,color:#f0e8e0
style EMU fill:#3a1010,stroke:#e03030,color:#f0e8e0
style SRV fill:#4a1515,stroke:#f8d030,color:#f8d030
style PB fill:#4a1515,stroke:#f8d030,color:#f8d030
style API fill:#2a1515,stroke:#8a7a70,color:#8a7a70
style EMU2 fill:#2a1515,stroke:#8a7a70,color:#8a7a70
style NAV fill:#1a2010,stroke:#48d848,color:#48d848
style MEM fill:#1a2010,stroke:#48d848,color:#48d848
※ 双方向矢印は要求/応答フロー / 緑ノードは自己改善(マップ学習 + ルール蓄積)
PyBoy を別プロセスで SDL2 ウィンドウ付き起動。MCP サーバーが TCP 経由でリモート操作。
ROM ヘッダから日本語版/英語版を自動判定。文字テーブルを自動切替。
ボタン操作後に wait_frames 分待って画面を自動返却。ツール呼び出し回数を半減。
PyBoy は別プロセスで常時 60fps + SDL2 表示。MCP サーバーとは TCP で疎結合。
移動経験を nav_memory.py が自動学習。操作ノウハウを CLAUDE.md / Memory に記録し、次回プレイに活用。
LLMアドバイザー不要。battle_calc + nav_memory + objective の計算モジュールを Director が直接使い、全判断を実行。
load_rom("/path/to/pokemon_red.gb") でエミュレータ起動
get_game_state で構造化 JSON を取得。シーン・座標・手持ちを把握
press_button で1ステップ操作、do_action で移動/テキスト送り。バトルは press_button で1手ずつ進める
返ってきた画面/JSON を見て次のアクションを決定。2-4 を自律的にループ
移動の成功・失敗を nav_memory.py が自動記録。壁・行き止まり・マップ遷移を学習し、次回は最短ルートで移動
| Tool | Args | Description |
|---|---|---|
press_button | button, wait_frames, include_image | ボタンを押す。デフォルトJSON、include_image=trueで画面付き |
press_buttons | buttons, interval_ms, wait_frames | ボタン連続入力、最後に画面を返す |
hold_button | button, frames, wait_frames | ボタン長押し後に画面を返す |
wait | seconds | 指定秒数待って画面を返す |
get_game_state | - | 構造化 JSON(scene / プレイヤー / 手持ち / バトル) |
get_collision_map | - | 衝突マップ(9x10) + プレイヤー方向 + NPC + ドア位置 |
get_wide_map | - | マップ全体の歩行可否(三状態: 2=確認済歩行可, 0=壁, -1=未探索) + 草むらグリッド |
press_button_fast | button, wait_frames | ボタン押下 + JSON 状態を返す(画像なし) |
press_buttons_fast | buttons, interval_ms | 連続入力 + JSON 状態を返す(画像なし) |
do_action | action, count, direction | 歩行・テキスト送りをまとめて実行。エンカウント/マップ遷移で中断 |
navigate_to | target_x, target_y, target_map_id | 自己学習型ナビで目的地まで自動移動 |
navigate_smart | target_type, direction, target_map_id | 意図ベース移動(exit/explore/transition/grass) |
load_rom | rom_path, headless | ROM をロードしてエミュレータ起動 |
quit_emulator | - | エミュレータ停止(セーブ付き) |
say | text | Claude の実況コメントをオーバーレイに表示 |
get_emulator_info | - | エミュレータの状態確認 |
LLMアドバイザーを廃止し、Director が計算モジュールを直接使って全判断を行うシンプル構成。
graph TD
DIR["Director
Claude Code Opus
MCP 操作 + 全判断"] -->|"MCP stdio"| MCP["gameboy_mcp_server.py"]
BC["battle_calc.py
タイプ相性 + ダメージ推定"] -->|"計算済みデータ"| DIR
NM["nav_memory.py
自己学習マップ知識"] -->|"歩行実績 + 草タイル"| DIR
NA["nav_analyst.py
リアルタイム分析"] -->|"毎歩自動実行"| DIR
OBJ["objective.py
目標管理"] -->|"進捗追跡"| DIR
style DIR fill:#3a1010,stroke:#f8d030,color:#f8d030
style MCP fill:#3a1010,stroke:#e03030,color:#f0e8e0
style BC fill:#1a2010,stroke:#48d848,color:#48d848
style NM fill:#1a2010,stroke:#48d848,color:#48d848
style NA fill:#1a2010,stroke:#48d848,color:#48d848
style OBJ fill:#1a2010,stroke:#48d848,color:#48d848
LLMアドバイザー不要。battle_calc + nav_memory + objective の計算結果を Director が直接読んで判断。
Claude Code セッションが MCP 経由でゲームを操作。battle_calc・nav_memory・objective を直接使い、全ての判断を自ら行う。
Gen1 タイプ相性表(15x15)、全165技、151種族のタイプデータ。STAB・ダメージ%を事前計算し、Director の技選択を支援。
歩行中に壁・遷移・草タイルを自動蓄積。wide_map のキャッシュデータと草むら判定(エンカウント実績ベース)を提供。
do_action 毎にリアルタイム分析を自動実行。フロンティア検出・出口情報・ループ検出を Director に返す。
目標設定・進捗追跡・再評価トリガー。grind/gym/heal/explore/story の目標タイプを管理。
衝突マップ生成、A* パスファインダー、wide_map 全体マップ構築。三状態システム(確認済/壁/未探索)でA*が未探索エリアも通過可能。
| Scene | wait_frames | Time |
|---|---|---|
| Menu select | 10 (default) | ~0.17s |
| Text advance | 20 | ~0.33s |
| Character move | 15 | ~0.25s |
| Screen transition | 30-60 | ~0.5-1s |
| Battle animation | 60-180 | ~1-3s |
Claude Code がこのディレクトリで起動すると、以下の設定で MCP サーバーが自動接続される。
FastMCP で構築された MCP サーバー本体。全 16 ツールを公開し、stdio トランスポートで通信する。
press_button — ボタン押下(デフォルトJSON、画像オプション)press_buttons — 連続入力、最後に画面を返すhold_button — 長押し + リリース後の画面を返却wait — 指定秒数待機 + 画面を返却get_game_state — 構造化 JSON(scene/手持ち/バトル)get_collision_map — 衝突マップ + NPC位置press_button_fast — ボタン押下 + JSON 状態を返すpress_buttons_fast — 連続入力 + JSON 状態を返すdo_action — 歩行・テキスト送りをまとめて実行navigate_to — 自己学習型ナビで自動移動load_rom — ROM ロード + エミュレータ起動quit_emulator — セーブ付きで停止get_emulator_info — 実行状態とカートリッジ情報say — Claude の実況コメントをオーバーレイに表示画面内衝突マップ(9x10)生成 + マップ全体の wide_map 構築 + A* パスファインダーで経路探索する。
Gen1 バトル計算エンジン。タイプ相性・技データ・ダメージ推定を提供し、Battle Advisor に計算済みデータを渡す。
enrich_battle_context() — 相性ラベル・ダメージ%・STAB判定・交代候補の防御相性を一括計算Director の状態追跡。稼働状態をオーバーレイにリアルタイム表示する。
agents イベントで変化時のみ配信PyBoy TCP クライアント。pyboy_server.py に接続してエミュレータを操作する。
PyBoy インスタンスを threading.Lock で排他制御_tick_loop が 60fps でフレーム進行get_screen_bytes — PIL Image → JPEG bytes 変換(MCP用)。配信は mmap 経由で PNG を直接読み取りpress_button — ボタン押下 → wait_frames/60 秒スリープ → 画面返却press_button_hold — 押下 → ホールド → リリース → 画面返却.gb / .gbc のみ許可、os.path.realpath で解決赤・青の両バージョンに対応。ターン制バトル + マップ移動で MCP 操作との相性が良い。
screencapture + Anthropic API ループ方式で初期実装
PyBoy + MCP サーバー方式に全面書き換え。wait_frames による画面自動返却
ダッシュボード削除、get_screen 削除、プロジェクト紹介 HTML 追加
scene 検出(8シーン)、複合ツール(do_action)、技名テーブル165件、配信オーバーレイ(ポケモン赤テーマ、anime.js)、アクションログ、PokeAPI スプライト連携
TCP クライアント/サーバー分離(SDL2 ウィンドウ表示対応)、日本語版 ROM 自動判定、ひらがな文字テーブル追加、シーン検出のゲーム開始直後誤判定修正
ボタン入力修正(button_press/release 方式)、_INTERNAL_TO_DEX 全面修正、マップナビゲーションデータ(map_data.py)、配信オーバーレイ JSON 表示、シーン検出バトル優先判定、do_action エンカウント中断検出、ビューワー UI リデザイン(ポケモン赤テーマ)、初テストプレイ完了(マサラ → トキワ → 図鑑入手)
衝突マップ & A* パスファインダー実装(壁自動迂回)、navigate_to に A* 迂回統合(_walk_toward が壁検出時に自動で迂回路を探索)、Route 1 通過 → トキワシティ到着、ヒトカゲ Lv.9(ひのこ習得)
配信オーバーレイ高速化 — 画面転送を TCP から共有メモリ (mmap) に置き換え、レイテンシ約60倍改善。RGBA→RGB 変換修正、PNG 形式採用でアーティファクト解消。スキャンライン CSS 無効化(H.264 モアレ対策)、プレイヤー名表示追加。音声安定性も確認済み
トークン効率 & TCP 最適化 — bulk read で TCP 40-60回→1-2回、collision_map 分離(毎回300-400 tokens 節約)、do_action(walk) 毎歩チェック廃止(scene バイトのみ)、press_button 画像オプショナル化、ステートキャッシュ層追加。20歩ウォークで約95%トークン削減
自己学習ナビゲーション(nav_memory.py)、マップ遷移検出追加(do_action/navigate_to で建物出入り時に自動wait)、ポケモンセンター出口座標修正
プロジェクト整理 — CLAUDE.md 65%削減(MCPツール一覧の重複除去)、ルールファイル10→4に統合(69%削減)、メモリファイル整理、map_data.py 削除(nav_memory.py に完全移行)、デッドコード検出、README.md 更新
マルチエージェント ゲームプレイ — Director+Advisor 型構成を実装。battle_calc.py(Gen1 タイプ相性表 15×15、全165技、151種族タイプ、ダメージ推定)、4 アドバイザー(Battle/Nav/Strategist/Map Analyst)、エージェント状態可視化(agent_log.py → オーバーレイ AGENTS パネル)、Claude 実況 MCP ツール(say)、collision_map の AI LOG 表示、セッションイベントログ、137テスト全通過
ワイドマップ&オーバーレイ改善 — get_wide_map MCP ツール追加(マップ全体の衝突データ取得)、オーバーレイ右パネルのコンパクト化(フォント・スプライト・パディング縮小)、Bookmark 機能完全削除、Director 状態のイミュータブル合成に修正、マルチエージェント動作検証(Navigation/Strategist/Map Analyst の並列起動確認)
Map Analyst 廃止 & DESIGN.md 導入 — Map Analyst エージェントを nav_memory.get_exploration_stats() に置換(Haiku 1回分のコスト削減)、exploration_stats を Navigation Advisor と Strategist に直接提供、DESIGN.md でデザイントークン統一、英語版 index_en.html 追加
草むら検出修正 & 自律ループ — 洞窟上部タイルの草むら誤認識を修正、JP/EN 判定ロジック分離、ドア表示(衝突マップ D 表示)、自律ゲームループ(objective.py で目標管理・Strategist自動トリガー)、セマンティックナビ(smart_nav.py で意図ベース移動)、CLAUDE.md 52%圧縮
初の正式リリース — Director 直結アーキテクチャ(LLMアドバイザー廃止、battle_calc + nav_memory + objective で全判断をDirectorが直接実行)。nav_analyst.py(do_action毎にリアルタイムマップ分析)、press_button からcaptureパラメータ完全除去。トキワの森→ニビシティ到達・ポケモンセンター回復・野生ポケモン戦自動処理を実証。
マップデータ構造修正 & コード整理 — JP/EN のマップデータ構造を修正。wide_map に2層フォールバック導入(collision_cache + ボーダーブロック比較)。草むらグリッドを nav_memory エンカウント実績ベースに変更。不要コード削除。
ナビゲーション全面改善 (P0-P6) & プロジェクト名「ラプラス」 — wide_map 三状態化(unknown≠wall、A*が未探索エリアをコスト3で通過)。衝突判定の精度を100%まで改善。collision_cache を nav_memory.json に永続化(サーバー再起動後も維持)。no_progress 閾値 4→12(迷路で粘る)。フロンティア上限撤廃+多様性スコアリング。HP安全チェック(全滅防止)。ワープ事前記録(マップ遷移時に全ドア自動記録)。PyBoy ヘッドレスモード追加(並列テスト基盤)。Claude Code Agent() による8エージェント並列調査で改善点を発見・実装。JP/EN判定の共通化、不要TCP呼び出し削除などリファクタ実施。
ナビゲーション座標修正 & ドア回避 — warp座標とplayer座標の系統統一、A*ターゲットのgrid変換に//2追加(navigate_toが短距離で正確到達)。find_pathにドア回避機能追加(navigate_to中に建物に吸い込まれる問題を解消)。stuck時のcollision_cache大量削除を廃止(高精度キャッシュを保護)。壁ヒット時の適応的ウェイポイント選択(no_progress増加に応じてwide_mapの先のウェイポイントを参照し、建物を大きく迂回)。タイルセット情報の動的取得で衝突判定をさらに正確化。pyboy_serverにmark_wall/set_speedコマンド追加。
レッジ方向判定 & ドア回避統一 — レッジ(段差)の一方通行判定に移動方向チェックを追加(南方向ジャンプは許可、北への登りはブロック)。navigate_toのA*全呼び出しでドア回避ゴール除外を統一(ウェイポイント・画面端ゴールがドア位置と一致しても到達可能に)。_DIR_BLKをモジュール定数に統一しリファクタ。ニビシティジム(タケシ)をHP2で撃破、グレーバッジ獲得。