# 15 のルール

> どれも実際の対戦で痛い目を見て得たものです。Bot を書くときに照らし合わせれば、原因調査の手間の大半を省けます。

出典: https://war3ai.com/ja/docs/rules/

> **ヒント**
>
> このページを [`api.json`](https://war3ai.com/ja/api.json) と一緒に LLM に渡すと、書かれる Bot の回り道がずっと少なくなります。

## 状態を読む

### 1. 読めないときは `None`、0 ではない

`resources()`、`time_of_day()`、`production()`、`cooldown()` はいずれも `None` を返すことがあります（ロード中、ユニットに詳細がない、建物が生産していない……）。使う前に判定してください。

```python
res = g.resources()
if res is None:
    return
```

### 2. ユニットはハンドルで識別し、アドレスは使わない

アドレスは新しいユニットに再利用されます。古いアドレスが新しく生まれたユニットを指すこともあります。ティックをまたいであるユニットを覚えておくには、`u.handle` を保存し、`g.unit(handle)` で取り戻します。

### 3. イベントストリームはグローバル

`production.done` や `unit.died` には、対戦相手やクリープのものも含まれます。`ev.owner`（または建物のハンドル）でフィルタリングしてください。

```python
if ev.kind == "production.done" and ev.owner == g.me():
    ...
```

### 4. 金鉱に入ったワーカーはスナップショットにいない

ワーカーは金鉱に入った瞬間にスナップショットから消えます（`unit.removed` で、死亡ではありません）。鉱山ごとの人数を数えるなら**自分で記録**し、スナップショットに合わせて記録を減らさないでください。さもないと満員の鉱山にさらに人を送ってしまいます。

## コマンドを出す

### 5. レシートの「受理」≠ 成功

森の中の建設地点でもエンジンはその場で受理し、ワーカーが到着してから失敗します。スキルは中断されることもあります。効果はスナップショットとイベントで確認します。建物の建設には `build_near`（建設が始まったかを追跡します）を使い、スキルは `g.cooldown()` がクールダウンに入ったかで確認します。

### 6. 見えない目標は攻撃できない

霧の中の敵に目標指定のコマンドを出すと拒否され、理由コードは **1001** です。霧の中の敵を追うには、最後に見えた位置に `attack_move` します。

### 7. 命令は暇なユニットにだけ出す

毎ティック同じユニットに同じコマンドを出し直すと、動作が中断されます。兵はその場で痙攣したようになり、ワーカーの採集サイクルはリセットされます。「暇かどうか」の判定には `g.order_of(u)`（このティックで出したばかりの命令も含む）を使い、スナップショットの `u.order` は使わないでください（スナップショットはまだ追いついていません）。

### 8. Shift は「現在の命令の直後に挿入」しかない

エンジンには「末尾に追加」がありません。`queue='after'` で B、C を続けて送ると、A、C、B の順になります。複数の地点を順番に巡るには `g.path(units, 地点リスト)`、1 体のワーカーで複数の建物を連続建設するには `g.build_queue(worker, 計画)` を使ってください。これらは逆順に挿入して、順序をうまく処理してくれます。

### 9. 1 ティックのコマンドは 1 バッチで送る

数十のコマンドを 1 件ずつ送ると、ゲームスレッドを数十回待つことになります。`with g.batch():` で包めば待つのは 1 回だけです。

## 経済と生産

### 10. 1 鉱山のワーカーは最大 5 人

それ以上増やしても収入は増えません。ワーカーの目標数は鉱山の数に合わせます。各鉱山に採金 5 人、加えて伐採を数人。

### 11. 訓練キューは 1 体だけ

7 枠を埋めると資金がキューにロックされます（実測では、タウンホールにピーザント 4 体をキューに入れて 300 ゴールドがロックされ、序盤が大きく遅れました）。`g.queue(b)` が空になってから次を追加してください。

### 12. 人口の詰まりは生産表で確認

`g.production(b).blocked` = キューに入っているのに始まっていない状態で、ほとんどの場合は人口不足です。「人口が上限に近づいたら建てる」より一歩早く気づけます。戦闘で兵をまとめて失い、補充しようとしてキューが詰まった時点でわかります。

### 13. ヒーローは唯一、タウンホールのキューが空でないとティアアップできない

- ヒーローが死んだら `g.revive(祭壇)` しかありません。再び訓練しようとすると拒否されます（221）。蘇生にも人口が必要です（ヒーローは 5）。
- タウンホールのキューに何か残っているときは、タウンホールをアップグレードできません（理由コード 185、「建物が使用中」）。

## 時間と空間

### 14. 2 倍速では実時間で待たない

3 ゲーム秒待ちたいなら、`g.clock()` が 3 進んだかを見ます。`sleep(1.5)` ではありません。倍速ではエンジンの時計が実時間より速く進みます。

### 15. 島マップや森の多いマップでは直線距離を使わない

クリープキャンプや拡張地点の選択には `g.path_distance(a, b)`（地上 A*。森、崖、建物を迂回）を使います。到達できない場合は `None` を返します。直線で最も近い地点は、海の向こう側かもしれません。

## もう 1 つ：フェアモードで書く

`--fair` では視界内のユニット、アイテム、生産、イベントしか見えません。アリーナのルールもこれと同じです。今からフェアモードで書いておけば、将来 [アリーナ](https://war3ai.com/ja/arena/) に出るときに書き換える必要はありません。詳しくは [フェアモード](https://war3ai.com/ja/docs/fair-mode/) を参照してください。
