文件 核心概念

十五條規矩

每一條都是在真實對局裡踩坑踩出來的。寫 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, 點清單);要讓一個工人連續建造多座,用 g.build_queue(worker, 計畫) —— 它們會倒序插入,幫你處理好。

9. 一拍的命令一批送出

幾十條命令逐條送出,要等幾十次遊戲執行緒;包進 with g.batch(): 只需要等一次。

經濟與生產

10. 一座礦最多 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。直線距離最近的那個點,可能在海的另一邊。

還有一條:照公平模式寫

--fair 下只看得見視野內的單位、物品、生產和事件,擂台用的就是這套規則。現在就照公平模式寫,將來上對戰平台不用修改。詳見公平模式。