# LLM で Bot を書く

> プログラミングができなくても作れます。あなたはどう戦ってほしいかをはっきり伝え、コードは LLM が書きます。プロンプトテンプレートをコピーして戦い方を説明し、動かして、また直してもらいましょう。

出典: https://war3ai.com/ja/docs/ai-bot/

Warcraft は遊べるけれどプログラミングはできない人にも、時間を節約したい開発者にも向いています。全体の流れは 1 つの対話です：**あなたが戦い方を説明する → モデルがコードを書く → あなたが 1 試合動かす → 見た現象をモデルに伝える → モデルが直す**。

> **ヒント**
>
> まず [クイックスタート](https://war3ai.com/ja/docs/quickstart/) に従って環境を整え、`hello_bot` を動かしておきましょう（農民が採掘に向かうのを確認します）。そうしておけば、問題が起きたときに環境の問題なのか Bot の問題なのかを切り分けられます。

## 1. モデルに資料を用意する

モデルが上手に書けるかどうかは、8 割がた正しい資料を読めているかで決まります。使っているツールに合わせて 1 つ選んでください。

| 使っているもの | 資料の渡し方 |
|---|---|
| **リポジトリを読める Coding Agent**（Claude Code、Cursor、Codex など） | リポジトリのディレクトリで起動し、まず `docs/BOT_HANDBOOK_ZH.md`、`docs/api.json` とサンプル 1 つ（運営なら `brains/examples/macro_bot.py`、戦闘なら `micro_bot.py`）を読ませます |
| **Web にアクセスできるチャットモデル** | まず [`https://war3ai.com/llms-full.txt`](https://war3ai.com/ja/llms-full.txt) を読ませます。サイト全体のドキュメントがこの 1 ファイルにまとまっています |
| **Web チャットでインターネットに接続できない** | ハンドブック、[`api.json`](https://war3ai.com/ja/api.json)、サンプルファイル 1 つをプロンプトの後ろに貼り付けます |
| **ローカルモデル**（LM Studio、Ollama） | 同上。コンテキストウィンドウは 32K トークン以上を推奨します。そうでないとハンドブックと API カタログが収まりません |

特定のプロの戦術を入れたい場合は、[プロの戦術レシピ集](https://war3ai.com/ja/docs/cookbook/) から該当するレシピも貼り付けます。

## 2. このプロンプトをコピーする

最後の「欲しい戦い方」をあなた自身の言葉に置き換えてください。具体的であるほど良くなります。

```text
あなたは Warcraft III 1.27 用の AI（Python）を書きます。使ってよいのは api.json に載っている Game のメソッドだけで、
存在しないメソッドをでっち上げないでください。書き方は rush_bot.py に倣い、openwar3.Bot を継承して on_start(g) と on_tick(g) を実装します。

ルール：
- on_tick は毎秒およそ 5 回呼ばれるので、速く保つこと（中で sleep しない）。
- 読み取れない値は 0 ではなく None なので、使う前にチェックすること。
- コマンドはレシート（Receipt）を返す。`if r:` が「エンジンが受理した」という意味。受理されなかった場合は r.reason に理由が入っている
  （人口不足、ゴールド不足、ターゲットが見えない、そのヒーローはすでにいる……）ので、次のティックで再試行するか別のやり方に変えること。
- 特定の敵を攻撃するには g.attack(兵, 敵) を使う。敵は視界内にいる必要があり、見えない敵への命令は拒否される。
- ヒーローが死んだら g.revive(祭壇) で復活させる。もう一度訓練することはできない。
- 建物は g.build_near(ワーカー, 建物コード, x, y) で建てる。置ける場所を自分で探して結果を追跡し、ゴールドが足りないときは何もしない。
- 「今何が起きたか」（誰が死んだか、誰がダメージを受けたか、ヒーローのレベルアップ、アイテムのドロップ）を知りたければ on_event(g, ev) を実装する。
- 同じユニットに毎ティック同じコマンドを出し直さないこと（今やっていることが中断される）。命令は「手が空いている」ユニットに出す。
- 採集は idle_workers() のワーカーにだけ割り当てる。1 つの金鉱には最大 5 人まで。
- 訓練キューには 1 つだけ入れる（g.queue(建物) が空になってから次を入れる）。人口で詰まっているかは g.production(建物).blocked で確認する。
- 1 ティックで多くのコマンドを出すときは with g.batch(): で囲む（ゲームスレッドを待つのが 1 回で済む）。
- 誰を攻撃するかは g.time_to_kill(自軍の集団, 敵) で選ぶ（相性とアーマーを考慮済み）。どこへ行くかは g.path_distance で選ぶ（到達できなければ None）。
- フェアモードでは視界内のものしか見えない。以前見た敵は g.last_seen() で取得する。
- ユニットは 4 文字コードで表す（ヒューマンの Peasant は hpea、Footman は hfoo、Barracks は hbar……）。スキルはオーダー文字列で表す（thunderbolt = Storm Bolt、
  blizzard = Blizzard、holybolt = Holy Light……、全一覧は data/order-ids.txt）。スキルの習得には 4 文字コードを使う（AHtb、AHbz……）。

欲しい戦い方：
<ここに普段の言葉で書く。例：
  「ヒューマン。序盤は農民 5 人でゴールドを掘り、1 人で伐採。最初のヒーローは Archmage。Barracks 2 つで Footman と Rifleman を出す。
   兵が 12 体たまったらヒーローを連れて相手の拡張を攻める。ヒーローの HP が 30% を切ったら本拠地へ撤退。
   クリープ狩りでは本拠地に近いキャンプを優先する。」>
```

### 戦い方をはっきり伝えるには

モデルが一番苦手なのはあいまいな要求です。「もっと攻撃的に」より、次のような情報のほうが役に立ちます。

- **種族とヒーロー**：どのヒーローを先に出すか、スキルの習得順（例：Archmage なら Water Elemental、Blizzard、Water Elemental……）。
- **建設順序**：何人目の農民で Barracks を建てるか、いつティアアップするか、Barracks をいくつ建てるか。
- **ユニット構成**：Footman + Rifleman？ 何体そろったら出撃するか？
- **攻撃と撤退の条件**：何体たまったら出撃するか、ヒーローの HP がどこまで下がったら撤退するか、壊滅したら本拠地に戻って立て直すか。
- **クリープ狩り**：するかしないか、いつするか（夜になってから？）、勝てるキャンプだけを狙うか？
- **フェアかどうか**：将来アリーナに出るなら「視界内に見えている敵だけを使う」と伝えます。

## 3. 動かす

モデルが書いたコードを `brains/my_bot.py` として保存し、次を実行します。

```bash
python tools/play.py --bot brains/my_bot.py --race 1 --difficulty 2
```

早く結果を見たいなら `--speed 200`（2 倍速）を付けます。

## 4. 直してもらう

- **エラーが出た**：**エラー全文**をそのままモデルに貼り付け、「直して」と伝えます。
- **うまく戦えない**：推測した原因ではなく、**ゲーム内で何が見えたか**を説明します。たとえば「ヒーローがずっと本拠地に立ったまま動かない」「兵が 1 体ずつ突っ込んでいく」「農民が 1 つの鉱山に群がっている」など。
- **新しい戦術を追加したい**：一度に 1 つだけ追加し、1 試合動かして壊れていないことを確認してから次を追加します。

> **補足**
>
> 自分でコマンドを実行できる Coding Agent なら、ステップ 3 と 4 も任せられます：1 試合動かし、ログとレシートを読み、コードを直して、また動かします。十分な情報を Agent に見せる方法は [Agent による自律反復](https://war3ai.com/ja/docs/agent-loop/) を参照してください。

## 5. よくある問題

| 現象 | たいていの原因 |
|---|---|
| 何も動かない | インスタンス番号が違う（`--inst`）、またはゲームがまだ試合に入っていない |
| 農民が採掘しない | 作業中の農民に命令している。`idle_workers()` にだけ割り当てる |
| いつまでも建物が建たない | `build_near` を使い、座標を決め打ちしない。レシートの `reason` がゴールド不足になっていないか確認する |
| ヒーローが出てこない | `train` のレシートを確認：人口不足？ それともヒーローが死んでいる（`revive` が必要）？ |
| ヒーローがスキルを使わない | 習得していない（`learn`）か、マナがない。使った後に `cooldown()` がクールダウンに入ったか確認する |
| 兵がティックごとにガクガクする | 毎ティック命令を出し直している。手が空いているユニットにだけ命令する |
| 兵が出てこず、ゴールドが増え続ける | 人口で詰まっている：`g.production(barracks).blocked` を確認する |
| モデルが存在しないメソッドを使う | プロンプトで「api.json のメソッドだけを使う」ともう一度強調し、api.json を全部貼り付ける |

## さらに進むには

- すべての API と、各 API の内部の仕組み：[API カタログ](https://war3ai.com/ja/api/)。
- リファレンスブレイン（`brains/xwar3/strategy`）は、拡張・クリープ狩り・出撃までこなす完全な AI です。モデルにその考え方を読ませることはできますが、より低レベルなインターフェースを使っているため、そのまま真似するのはおすすめしません。
- 将来 [アリーナ](https://war3ai.com/ja/arena/) に出るときは視界内の敵しか見えません —— 今のうちから `--fair` を付けて自分を縛っておけば、後で書き直す必要がありません。
