LLM で Bot を書く
プログラミングができなくても作れます。あなたはどう戦ってほしいかをはっきり伝え、コードは LLM が書きます。プロンプトテンプレートをコピーして戦い方を説明し、動かして、また直してもらいましょう。
Warcraft は遊べるけれどプログラミングはできない人にも、時間を節約したい開発者にも向いています。全体の流れは 1 つの対話です:あなたが戦い方を説明する → モデルがコードを書く → あなたが 1 試合動かす → 見た現象をモデルに伝える → モデルが直す。
まず クイックスタート に従って環境を整え、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 を読ませます。サイト全体のドキュメントがこの 1 ファイルにまとまっています |
| Web チャットでインターネットに接続できない | ハンドブック、api.json、サンプルファイル 1 つをプロンプトの後ろに貼り付けます |
| ローカルモデル(LM Studio、Ollama) | 同上。コンテキストウィンドウは 32K トークン以上を推奨します。そうでないとハンドブックと API カタログが収まりません |
特定のプロの戦術を入れたい場合は、プロの戦術レシピ集 から該当するレシピも貼り付けます。
2. このプロンプトをコピーする
最後の「欲しい戦い方」をあなた自身の言葉に置き換えてください。具体的であるほど良くなります。
あなたは 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 として保存し、次を実行します。
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 による自律反復 を参照してください。
5. よくある問題
| 現象 | たいていの原因 |
|---|---|
| 何も動かない | インスタンス番号が違う(--inst)、またはゲームがまだ試合に入っていない |
| 農民が採掘しない | 作業中の農民に命令している。idle_workers() にだけ割り当てる |
| いつまでも建物が建たない | build_near を使い、座標を決め打ちしない。レシートの reason がゴールド不足になっていないか確認する |
| ヒーローが出てこない | train のレシートを確認:人口不足? それともヒーローが死んでいる(revive が必要)? |
| ヒーローがスキルを使わない | 習得していない(learn)か、マナがない。使った後に cooldown() がクールダウンに入ったか確認する |
| 兵がティックごとにガクガクする | 毎ティック命令を出し直している。手が空いているユニットにだけ命令する |
| 兵が出てこず、ゴールドが増え続ける | 人口で詰まっている:g.production(barracks).blocked を確認する |
| モデルが存在しないメソッドを使う | プロンプトで「api.json のメソッドだけを使う」ともう一度強調し、api.json を全部貼り付ける |