Примеры ботов
Четыре примера от простого к сложному: каждый запускается как есть, каждый фрагмент логики соответствует одной возможности SDK. Плюс полноценный эталонный мозг.
Все примеры лежат в brains/examples/; каждый следующий наследует предыдущий и добавляет только новое. Читать лучше по порядку:
| Пример | Чему учит | Запуск |
|---|---|---|
hello_bot.py | Добыча (5 рабочих на рудник, рудник заполнен — на лес), найм рабочих (в очереди только 1), постройка зданий для пищи, достройка брошенных фундаментов; работает за все четыре расы | python tools/play.py --bot brains/examples/hello_bot.py |
rush_bot.py | Казарма и алтарь (если их нет — строятся через build_near), сначала герой (погиб — воскрешение), очки навыков тратятся сразу, накопили волну — атака с движением (attack-move) | … --bot brains/examples/rush_bot.py |
macro_bot.py | Порядок постройки + после стройки рабочий сам возвращается на рудник (Shift), упёрлись в пищу — сразу строить, в очереди казармы 1 юнит, улучшения атаки и брони, переход на следующий тир и продвинутые войска, цель выбирается по реальному пути по земле, движение по маршруту | … --bot brains/examples/macro_bot.py --speed 200 |
micro_bot.py | Поверх экономики берёт на себя бой: фокус на том, кого можно убить быстрее всех, отвод раненых, спасение героя, ночью — лагеря крипов по силам, возврат на защиту, когда враг у базы; команды одного тика уходят одной пачкой | … --bot brains/examples/micro_bot.py --fair |
В комментариях hello_bot и rush_bot записаны грабли, на которые наступили в реальных играх, например: «строить ферму каждый раз посылали первого же рабочего — в итоге все 3 фермы остались недостроенными фундаментами», «жёстко заданные координаты казармы пришлись ровно на лес — за 3 минуты не построено ни одной». Комментарии дают больше, чем сам код.
hello_bot: экономика
# раса -> (рабочий, главные здания, здание для пищи)
RACES = {
"h": ("hpea", {"htow", "hkee", "hcas"}, "hhou"),
"o": ("opeo", {"ogre", "ostr", "ofrt"}, "otrb"),
"u": ("uaco", {"unpl", "unp1", "unp2"}, "uzig"),
"e": ("ewsp", {"etol", "etoa", "etoe"}, "emow"),
}
MINE_CAP = 5 # не больше 5 рабочих на рудник (больше — доход не растёт)
LUMBER_CREW = 5 # лесорубы: 5 на золото с каждого рудника + столько на лес = целевое число рабочих
Три задачи: свободных рабочих — на золото (бот сам ведёт учёт, сколько рабочих на каждом руднике; рудник заполнен — на лес); рабочих не хватает — нанимать (в очереди только 1); пища почти кончилась — найти рабочего, который сейчас ничего не строит, и поставить рядом с главным зданием здание для пищи (у Людей и Орды бот ещё и отправляет рабочих достраивать брошенные фундаменты).
rush_bot: армия и атака
Поверх hello_bot добавляются три вещи: нет казармы и алтаря — построить; в алтаре нанять героя (погиб — сначала воскресить, герой уникален), есть очки навыков — изучать; накопилось 8 бойцов — всей армией attack-move к вражескому главному зданию, потрепали — домой копить заново. Приказы отдаются только свободным бойцам, чтобы не сбивать бой каждый тик.
macro_bot: основы макро
TECH = {
"h": dict(order=["halt", "hbar", "hbla", "hlum"], altar="halt", hero="Hamg", skills=["AHwe", "AHbz", "AHab"],
barracks="hbar", soldiers=["hfoo", "hrif", "hkni"], smith="hbla", upgrades=["Rhme", "Rhar", "Rhra", "Rhla"],
tiers=["hkee", "hcas"]),
...
}
То, что профи делает каждую игру, — и каждому пункту соответствует возможность SDK: таблица порядка постройки + gather(..., queue="after"), чтобы после стройки вернуться на рудник; production().blocked показывает, что упёрлись в пищу; g.queue гарантирует, что в очереди казармы всего 1 юнит; can_do спрашивает у движка, можно ли исследовать следующий уровень атаки или брони; переход на следующие тиры и продвинутые войска (урок из реальной игры: бот застрял на первом тире и на 23-й минуте был снесён рыцарями и грифонами соперника с третьего тира); цель выбирается по path_distance, движение по точкам поворота — через path().
micro_bot: когда начинается бой
def _fight(self, g, army, foes, home, now):
...
visible = [e for e in foes if e.visible_to(me)] # невидимую цель движок отклонит (1001)
atk = [s for s in (g.stats(u) for u in fighters) if s]
target = min(visible, key=lambda e: _ttk(g, atk, e)) # того, кого быстрее убить, а не ближайшего
idle_or_other = [u for u in fighters if g.current_target(u) is None
or g.current_target(u).handle != target.handle]
if idle_or_other:
g.attack(idle_or_other, target)
В реальной игре: 5 минут, 1497 тиков, 3023 команды, 0 ошибок.
Эталонный мозг: полноценный ИИ
brains/xwar3/ — полноценный ИИ, который ставит вторую базу, крипует и атакует. Он состоит из трёх слоёв:
| Слой | Где | Ритм | Что делает |
|---|---|---|---|
| Стратегический слой | strategy/ | секунды | Выбор и смена стратегий в духе AMAI, таблицы постройки, контр-юниты, выбор героев; опционально — LLM-советник по стратегии |
| Рефлекторный слой | reflex/ (4 отдельных процесса) | ~100 ms | Спасение юнитов, применение способностей, фокус огня, подбор предметов |
| Модель шансов на победу | worldmodel/ | — | Выиграем ли бой (подмножество для инференса) |
Несколько процессов делят юнитов через таблицу захватов и по приоритету решают, чьё слово главное: ручное управление 95 > спасение 90 > уклонение от способностей 85 > применение способностей 80 > подбор предметов 70 > … > стратегия 50 > распределение рабочих 45. Ваш собственный бот записан в таблице как bot с приоритетом 50 по умолчанию.
Эталонный мозг напрямую использует низкоуровневую часть SDK (w3cmd / act) и сильно опирается на информацию обо всей карте. Он хорош как источник идей, но давать LLM копировать его один в один не стоит. Ему нужны данные AMAI: при первом развёртывании start.bat скачивает их из публичного репозитория AMAI и генерирует нужные файлы (у AMAI собственная лицензия, сгенерированные файлы в git не попадают; если не получилось, повторите через start.bat setup).
Проще всего запустить эталонный мозг через консоль Farsight: на странице «Экземпляры и запуск» отметьте номер экземпляра и нажмите «Начать тест».