Пятнадцать правил
Каждое выстрадано в реальных матчах. Сверяйтесь с ними, когда пишете бота, — это сэкономит большую часть времени на поиск ошибок.
Отдайте эту страницу LLM вместе с api.json — бот, которого она напишет, обойдёт множество ловушек.
Чтение состояния
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 умеет только «вставить после текущего»
В движке нет «добавить в конец»: если подряд отправить B и C с queue='after', получится 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 видны только юниты, предметы, производство и события в пределах обзора — именно по этим правилам играют на Арене. Пишите под честный режим уже сейчас, и при переходе на Арену ничего менять не придётся. Подробнее — в разделе Честный режим.