第12章:総仕上げ(ゲームを作る)

Nanocodeは実際に何かを作れるのでしょうか?

「ゼロコードチャレンジ」:PythonとPygameを使ってクラシックなSnakeゲームを作ります。ルールは一つ——Pythonを一行も書いてはいけません。エージェントへの指示は英語で話しかけるだけです。

An icon of a info-circle1

補足: このデモでは多くのAPIコールが発生します。レート制限(HTTP 429)に達した場合、エージェントは自動的にリトライします。長いセッションでは、制限を完全に回避するためにOllamaを使ったローカルモデルの利用も検討してみてください。

ステップ1:準備

プロジェクトのルート(nanocode.py.envが含まれるディレクトリ)から、ゲーム用の作業ディレクトリを作成します:

An icon of a info-circle1

補足: サブディレクトリで作業することで、エージェントのlist_filesがゲームファイルだけを参照し、自身のソースコードが見えないようになります。そして、まっさらなメモリの状態から始められます。

1 mkdir -p snake_game
2 cp nanocode.py snake_game/
3 cp .env snake_game/
4 cd snake_game

本書のコードリポジトリを使用している場合は、代わりに ch11 からコピーしてください:

1 mkdir -p snake_game
2 cp resources/code/ch11/nanocode.py snake_game/
3 cp .env snake_game/
4 cd snake_game

Pygameをインストールする:

1 pip install pygame
An icon of a info-circle1

補足: 上記のシェルコマンドは macOS/Linux 用です。Windows の場合は、代わりに mkdir snake_gamecopy nanocode.py snake_game\copy .env snake_game\ を使用してください。macOS で pip install pygame が失敗する場合は、brew install sdl2 sdl2_image sdl2_mixer sdl2_ttf が必要になることがあります。Linux の場合は、SDL 開発パッケージをインストールしてください: sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev。Windows では、pip install pygame にはすべてが同梱されています。

ステップ 2: アーキテクト(プランモード)

エージェントを起動します。レンガを積む前に設計図を用意したいので、プランモードで始めます。

1 python nanocode.py

プロンプト:

1 Build a classic Snake game using Pygame. Include a score counter and Game Over screen with a restart option. Put ALL code in ONE file: snake.py. Write the plan in PLAN.md.

エージェントはwrite_planを使ってPLAN.mdを作成します。読んでください。Snakeクラス、Foodクラス、そしてゲームループがすべて単一ファイルにまとめられた構成が概説されているはずです。

プランが妥当であれば、ステップ3に進んでください。

ステップ3:ビルダー(アクトモード)

アクトモードに切り替えます:

1 /mode act

プロンプト:

1 Implement the plan in snake.py. All code in one file.

ターミナルを確認してください:

1   → Writing snake.py

エージェントは PLAN.md に保存したコンテキストをもとにコードを生成しています。

ステップ4:現実確認

ゲームを実行する前に、タイムアウトを増やしてください。デフォルトの30秒では実際にゲームをプレイするには不十分です——Pygameのメインループはウィンドウを閉じるまで処理をブロックし続けます。起動する前に環境変数を設定してください:

1 export NANOCODE_TIMEOUT=300

プロンプト:

1 Run the game with: python snake.py

エージェントが run_command を実行します。ウィンドウがポップアップします。スネークをプレイします。

クラッシュした場合: LLM は非決定論的です。エージェントが最初の試みでバグを出してしまうこともあります。AttributeError: 'Snake' object has no attribute 'draw' のようなエラーでゲームがクラッシュしても、自分で修正しないでください。stderr をエージェントに確認させましょう。

プロンプト:

1 The game crashed. Read the error and fix it.

エージェントはトレースバックを読み取り、read_file でバグを特定し、edit_file でパッチを当て、再度実行します。

ステップ5:ピボット(フィーチャークリープ)

ゲームは動いていますが、見栄えがしません。スネークはただの緑の四角形です。エージェントのリファクタリング能力を徹底的にテストしましょう。

プロンプト:

1 The game looks boring. Make the snake change color as it eats food, increase speed every 5 points, and search the web for 'cool retro game color palettes' to apply.

エージェントがすべきこと:

  1. search_web を使ってカラーパレットを探す
  2. read_file を使って現在のレンダリングロジックを理解する
  3. edit_file を使って新機能を組み込む
  4. ゲームを実行して動作を確認する

うまくいく場合とうまくいかない場合

LLMは非決定論的なので、あなたの結果は私のものとは異なるでしょう。ただ、典型的に起こりがちなことと、注意すべきポイントを紹介します。

初回実行時によくある失敗:

  • ModuleNotFoundError: No module named 'pygame' — エージェントがインストールの必要性を忘れていたか、別の環境でスクリプトを実行してしまった場合です。エージェントに先に pip install pygame を実行するよう指示してください。
  • エージェントが定義したメソッドを呼び出し側でスペルミスしたことによる AttributeError。トレースバックを確認すれば、エージェントはすぐに修正できます。
  • 衝突検出のオフバイワンエラー。蛇が壁をすり抜けたり、1ピクセル早く死んでしまったりします。これは編集・実行・修正を2〜3回繰り返すことになります。

典型的なセッションの流れ:

私のテストでは、エージェントはたいてい2〜4回の反復で動作する(ただし見た目は粗い)ゲームを完成させます。最初の出力はクラッシュするものになり、2回目か3回目の修正でようやく動くようになります。機能拡張のステップ(色の変更、速度の段階的な上昇)では、エージェントが自分のコードを読み返してピンポイントの編集を行い、各変更を確認するため、さらに3〜5回の反復が加わります。

最終的には、会話が15〜20ラウンドにも及びます。Claudeを使っている場合は、コンパクションが発動するタイミングに注意してください。トークン数が75%のしきい値に近づく12〜15ラウンド目あたりで「(Compacting conversation…)」と表示されます。コンパクション後、エージェントは序盤のラウンドの細かい情報を一部失いますが、作業は続けます。これこそ第9章で作り上げたシステムが本領を発揮する瞬間です。

エージェントが苦手とするところ:

Pygameの座標系とイベントループはやっかいです。エージェントは、レンダリングは正しくてもキーボード入力を適切に処理しないコードを書いてしまうことがあります。また、蛇の描画順序が逆になって頭が胴体の後ろに表示されてしまうこともあります。こういったバグは人間がすぐに気づけるものですが、エージェントには視覚的なフィードバックがなく、stdoutとstderrしか見えません。エラーなしにゲームが起動しても見た目がおかしい場合は、視覚的なバグを言葉で説明する必要があります。「蛇が逆向きにレンダリングされている——頭は前に来るべきだ」といった具合に。

最初から完璧にいく必要はありません。大切なのは、エージェントが収束することです——書く、実行する、エラーを読む、修正する、繰り返す——11章にわたって構築したすべてのツールを活用しながら。

最終的な snake.py をリリースする前に、コードを読んでみてください。エージェントは動くコードを書きますが、テストループでは検出できないことを人間が確認する必要があります。ハードコードされたマジックナンバー、見落とされたエッジケース(ウィンドウがリサイズされたらどうなる?)、そしてコードの構造が保守しやすい形になっているかどうかです。エージェントは素早い下書き役であって、最終レビュアーではありません。

まとめ

計画して、実装して、クラッシュして、デバッグして、修正して、また実行する——これがすべての章の本領を発揮する瞬間です。

では、ここからどこへ向かうのでしょうか?

エピローグ

全体で約750行のPythonコードです。フレームワークは使っていません。nanocode.py はあなたのものです。好きなように使ってください:

  • テストがグリーンになった後に自動コミットするGit連携
  • フロントエンド作業向けのスクリーンショットベースのデバッグ(Claudeは画像を読み取れます)
  • タイピングの代わりに話せるよう、Whisperによる音声入力
  • チームがすでに使っている外部サービスへの接続のためのMCP
  • 会話をフォークしてサブタスクを並行処理するサブエージェント

Claude Code、Cursor、Copilotといったプロダクションエージェントはこれよりもさらに多くのことをこなします。ストリーミングレスポンス(付録Aを参照)、並列ツール実行、tree-sitterによる構文解析、サンドボックス実行環境、数千ファイルにまたがるマルチファイルコンテキストウィンドウ。750行と75万行の差は確かに存在します。しかしアーキテクチャは同じです。ブレイン、ループ、ツール、メモリ、そして安全ハーネス。これで舞台裏に何があるかがわかったはずです。

モデルは進化し続けるでしょう。ハーネス——ループ、ツール、安全チェック——それはエンジニアリングの領域です。そしてその部分は、これからもなくなることはありません。