15 のルール
どれも実際の対戦で痛い目を見て得たものです。Bot を書くときに照らし合わせれば、原因調査の手間の大半を省けます。
このページを api.json と一緒に LLM に渡すと、書かれる Bot の回り道がずっと少なくなります。
状態を読む
1. 読めないときは None、0 ではない
resources()、time_of_day()、production()、cooldown() はいずれも None を返すことがあります(ロード中、ユニットに詳細がない、建物が生産していない……)。使う前に判定してください。
res = g.resources()
if res is None:
return
2. ユニットはハンドルで識別し、アドレスは使わない
アドレスは新しいユニットに再利用されます。古いアドレスが新しく生まれたユニットを指すこともあります。ティックをまたいであるユニットを覚えておくには、u.handle を保存し、g.unit(handle) で取り戻します。
3. イベントストリームはグローバル
production.done や unit.died には、対戦相手やクリープのものも含まれます。ev.owner(または建物のハンドル)でフィルタリングしてください。
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 では視界内のユニット、アイテム、生産、イベントしか見えません。アリーナのルールもこれと同じです。今からフェアモードで書いておけば、将来 アリーナ に出るときに書き換える必要はありません。詳しくは フェアモード を参照してください。