ИИ разных авторов выясняют, кто сильнее, на одной карте
Честность может гарантировать только судья, а не сознательность бота. Бот никогда не касается общей памяти: он получает только наблюдения, отфильтрованные судьёй по обзору, может лишь отправлять действия, и у каждого действия сначала проверяется владение юнитом.
По степени гарантии честности
Возможности наблюдения в проекте опираются на то, что «клиент хранит состояние всех игроков», — и на вашей машине это тоже так. Поэтому честность может дать только судья, которому доверяют все. Сначала делаем A, тот же протокол затем напрямую переходит в B; C — только для развлечения.
Локальная арена
Одна машина, одна игра; у каждого бота свой слот, приказы за них отдаёт процесс-судья
Хостинговый ладдер
A переезжает на сервер; игроки загружают ботов, сервер запускает их в песочнице
Каждый у себя
Каждый запускает игру + бота на своей машине, бой по локальной сети
Один процесс отдаёт приказы за обе стороны
- Оркестрация Выбор карты, запуск матча, раса и сложность для каждого слота
- Тики Тик каждые T игровых миллисекунд (по умолчанию 200); в режиме lockstep игра ставится на паузу, пока рассылаются наблюдения
- Наблюдение Снимок → фильтр по обзору каждого слота → JSON
- Действия Проверка «юнит принадлежит этому слоту» → бюджет (команд за тик, APM) → отправка пачкой через быструю полосу
- Запись Сводка наблюдения за каждый тик + каждое действие: можно воспроизвести, разобрать, использовать как обучающие данные
- Решение У слота не осталось зданий → выбывает; время вышло → решение по оставшейся силе / ресурсам
Наблюдения на входе, действия на выходе
Выйти на карту может любая программа, которая умеет принимать и отправлять JSON, — в том числе LLM, которая напрямую выдаёт действия каждый тик. Python-боту на SDK менять код не нужно.
| Наблюдение | Только свои юниты + вражеские в пределах нашего обзора; крипы и золотые рудники — по обзору или открыты с начала матча |
| Лимит действий | Не больше 32 за тик, лишние отбрасываются (защита от спама командами, который тормозит судью) |
| Один юнит | В одном тике учитывается только последняя команда |
| Бюджет времени | Длина тика × 0.9; не успели — тик пропущен; медленная сторона проигрывает сама и не тормозит других |
| Lockstep | Когда нужна строгая честность, игра стоит на паузе, пока рассылаются наблюдения и собираются действия (или истекает тайм-аут), — скорость машин не влияет на результат |
| Обмен стартовыми точками | Каждая пара ботов играет дважды, поменявшись местами, — чтобы убрать асимметрию карты |
| Ладдер | Elo / TrueSkill; не меньше 20 матчей на пару, прежде чем делать выводы (по 2 матчам видна лишь разница в винрейте примерно от 60 процентных пунктов) |
{"t": "obs", "tick": 57, "gameMs": 11400, "me": 1,
"res": {"gold": 320, "lumber": 150, "food": [18, 30]},
"units": [
{"id": 101, "type": "hfoo", "owner": 1,
"x": -4500, "y": 2200, "hp": 380, "hpMax": 420}],
"visibleEnemies": [
{"id": 733, "type": "ogru", "owner": 2,
"x": -3900, "y": 2500, "hp": 700}],
"deadlineMs": 180} id — стабильный номер, который назначает судья, он не меняется весь матч. {"t": "act", "tick": 57, "actions": [
{"do": "attack", "unit": 101, "target": 733},
{"do": "train", "unit": 5, "code": "hfoo"},
{"do": "cast", "unit": 7, "spell": "thunderbolt", "target": 733},
{"do": "move", "unit": 102, "x": -5000, "y": 2000}]} category == "command", параметры называются так же. Опоздавший act отбрасывается, тик считается пропущенным. from openwar3 import Bot
class MyBot(Bot):
def on_tick(self, g): # один и тот же код: локально g — это Game, на Арене — ArenaGame
for w in g.idle_workers():
g.gather(w, g.nearest(g.gold_mines(), w))
# Локально: python tools/play.py --bot my_bot.py --fair
# На Арене: те же методы, под капотом WebSocket — код бота не меняется ни на строчку Game на ArenaGame, чтобы выйти на Арену. Строго по порядку — пока не пройден предыдущий, следующий не начинаем
| # | Эксперимент | Критерий | Что известно |
|---|---|---|---|
| 1 | Два слота в одном матче, оба без встроенного ИИ | Юниты обеих сторон стоят на месте | Метка ИИ и поле сложности слота известны |
| 2 | Отдавать приказы за слоты, кроме локального | Крестьяне вражеского слота действительно идут добывать | Самый важный пункт: если не пройдёт, остаётся только «один клиент на бота и настоящая сетевая игра» |
| 3 | Запрос видимости для любого номера игрока | Одна и та же точка даёт разный результат для двух слотов | Проверка видимости в движке принимает любой номер игрока |
| 4 | Программное определение победителя | Уничтожение всех зданий одной стороны известно в течение 1 секунды | У шины событий есть более прямая точка входа |
| 5 | Пауза / продолжение в lockstep | Действия собираются во время паузы и применяются после продолжения | Пауза проверена |
Заодно проверка: эталонный мозг сейчас сильно опирается на информацию обо всей карте (например, цель атаки компьютерного противника). Для Арены ему придётся перейти на методы фасада и только видимых юнитов — насколько сильным он останется без полной карты?