Предлагается реализовать агента для простой многопользовательской игры с другими агентами. Это вариант многораундовой ультимативной игры.
По всем вопросам, связанным с этим заданием, можно обращаться к Алексею Пшеничному: slack:@izhleba, email: [email protected].
Для игры выбирают двух случайных участников. Дальше выбирают в паре участника (proposer), которому дают возможность сделать ультиматум. Например, есть 100 долларов/очков/леденцов. Он (proposer) должен разделить эти плюшки в каком-то соотношении. К примеру, 100 себе и 0 второму участнику (responder). Или 70 себе и 30 второму участнику. Второй участник (responder) может согласиться на этот ультиматум. Тогда произойдёт сделка, каждый получит в соответствии с предложенным разбиением. Либо может отказаться. Тогда оба получают 0.
Проводится множество раундов, после которых сравниваются статистики набранных долларов/очков/леденцов и распределяются места. Набравшему больше всех — первое и т. д.
В качестве метрики успешности агента будет считаться bayesian average, чтобы избежать в песочнице ситуаций, когда агент сыграл две игры случайно получил хороший результат и больше не играет.
Если gains
- это массив заработков размера n
, то score = (C*m + sum(gains))/(C+len(gains))
где C
будет равно 18 (возможны корректировки в будущем), m
будет равно 50 (средне значение для примитивного агента).
По адресу https://ultimategame.ml/ находится песочница. Сюда можно отправить решение, и посмотреть результаты. С некоторой периодичностью там проходят игры, на момент написания каждые 15 минут. Решения принимаются через Docker-контейнеры, об этом будет написано ниже.
- Зайдите на сайт https://ultimategame.ml/ нажмите
Login
в правом верхнем углу, затемRegister
. - Укажите необходимые поля (пожалуйста, заполните настоящие имя и фамилию).
- На указанный email придёт письмо с активационной ссылкой, пройдите по ней.
- После активации можете заходить со своим логином и паролем.
- Зайдите в
Submissions
и кликните наMake submission
- В открывшейся форме в поле
Dockerhub image
вставьте адрес вашего Docker образа. Адрес указывается без http префикса и выглядит как<username>/<image_name>:<tag>
. О способе создания докер образа смотри инструкцию ниже. - В очередной игре участвует самое последнее отправленное решение. Возможно позже появится возможность управлять этим.
- Список своих отправленных решений можно увидеть пройдя во вкладку
Submissions list
. - Поле
Pull Status
показывает на каком этапе сейчас находится решение.- 'Waiting' - ожидается загрузка при следующей игре;
- 'Downloaded' - образ успешно загружен;
- 'Downloading error' - не удалось загрузить образ с указанного адреса в dockerhub;
- 'Exited to fast' - контейнер завершил работу сразу после старта;
- 'Wrong launch' - контейнер запустился, но работает не корректно;
- 'Ok' - контейнер корректно отработал игру.
- После успешного участия в очередной игре в поле
Last Score
будет сохранено последнее значение score. - Общую таблицу по последней игре можно найти во вкладке
Leaderboard
или на главной странице.
Для вашего удобства создан класс agent.my_agent.MyAgent
, в котором вам нужно написать код агента.
Необходимо, чтобы метод offer_action
возвращал размер предложения для другого агента, а deal_action
результат согласия или несогласия.
Метод round_result_action
позволяет узнать результаты раунда.
Более подробное описание методов и структур данных представлено ниже.
Код шаблона агента:
from agent.base import BaseAgent
from base.protocol import OfferRequest, DealRequest, RoundResult
class MyAgent(BaseAgent):
def offer_action(self, m: OfferRequest) -> int:
return 1
def deal_action(self, m: DealRequest) -> bool:
return True
def round_result_action(self, data: RoundResult):
pass
Любой агент должен наследовать методы от базового класса agent.base.BaseAgent
.
Описание этих методов:
def offer_action(self, data)
возвращает размер вашего предложения (int) некоторому агенту в раунде. Данные об агенте и общем размере разделяемых средства находятся вdata
. Структура класса описана здесь:base.protocol.OfferRequest
. Размер вашего предложенияoffer
это то, сколько вы предлагаете оставить другому агенту, в случае принятия предложения, ваша награда будет равнаtotal_amount - offer
.deal_action(self, data)
возвращает ответ (bool
): согласны ли вы на предложение от некоторого агента. Данные об агенте и о размере предложения находятся вdata
структура класса описана здесьbase.protocol.DealRequest
def round_result_action(self, data: RoundResult)
метод вызывается по окончании раунда, сообщает общие результаты вdata
; описание:base.protocol.RoundResult
.
round_id: int - номер раунда
target_agent_uid: str - идентификатор агента, которому будет отослано предложение
total_amount: int - общее количество, которое необходимо разделить
round_id: int - номер раунда
from_agent_uid: str - идентификатор агента, от которого поступило предложение
total_amount: int - общий размер разделяемых средств
offer: int - предложение от агента
round_id: int - номер раунда
win: bool - True если раунд успешен и предложение принято, в противном случае False
agent_gain: Dict[str, int] - ассоциативный массив с размерами наград, ключ - идентификатор агентов раунда
disconnection_failure: bool - флаг показывает, что во время раунда произошел дисконнект одного из участников
Когда вы создадите агента, перед сабмитом стоит провести базовый тест.
python3 agent_test.py
Если вы получите Base test successfully completed!
, значит основные требования
к методам выполнены. Можете сабмитить результат.
После того как вы создадите своего агента, нужно будет отослать результат. Текущий процесс включает в себя использование Docker-образов. Если коротко, ваш агент со всеми используемыми библиотеками и файлами будет упакован в контейнер, который будет использоваться в песочнице.
-
Прежде всего вам нужно установить Docker. Здесь можно найти дистрибутивы для Mac/Win/Linux: https://www.docker.com/get-started
-
После установки зайдите в терминал и наберите
docker run hello-world
. Если все пройдет успешно, вы увидите:
Hello from Docker!
This message shows that your installation appears to be working correctly.
-
Далее вам необходимо зарегистрироваться на https://hub.docker.com/signup. Далее оно будет использоваться как облачное хранилище ваших контейнеров. Запомните login и password далее: они будут использоваться вам еще раз.
-
После регистрации зайдите в терминал и наберите
docker login
. Далее введите login и password с которым вы зарегистрировались на Docker Hub. Если все пройдет успешно, вы увидите:
Login Succeeded
Если базовый тест пройден, можно попробовать сделать сабмит решения. Для этого нужно упаковать решение в Docker-образ и сделать push в Docker Hub.
- Сделайте
docker login
под вашим login в Docker Hub (далее будем обозначать его какdockerhub_login
). - Создайте образ
docker build -t <dockerhub_login>/ai_agent -f Dockerfile .
(не потеряйте точку в конце). Вместо<dockerhub_login>
вставьте свой login от Docker Hub. Обратите внимание, образ будет сделан даже без<dockerhub_login>
, но сделать push этого образа вы уже не сможете. В случае успеха вы увидите в конце:
Successfully built <идентификатор сборки>
Successfully tagged <dockerhub_login>/ai_agent:latest
-
Сделайте push в Docker Hub
docker push <dockerhub_login>/ai_agent
. В случае успеха вы сможете зайти на Docker Hub и увидеть этот контейнер среди своих в списке. -
Воспользуйтесь инструкцией по сабмиту решения через песочницу.
- Версия python по умолчанию 3.7
- Запрещается менять
client.py
, делать запросы в Интернет и вообще любые манипуляции с сетью или протоколом. - Для вашего удобства проще всего разместить весь код агента в том же файле, где и основной класс, и использовать библиотеки NumPy, scikit-learn.
Однако вы можете поместить в контейнер другие необходимые файлы и библиотеки с учетом того, чтобы контейнер не превысил размеры в 500 Mb.
Библиотеки добавляются через
requirements.txt
. - В качестве идентификаторов агента используются строковые представления UUID. После того как подключатся все агенты,
сервер оповестит вас о вашем uid, его можно будет узнать из поля
agent_id
. Обратите внимание: после инициализации класса (вызова__init__
) это поле будетNone
до оповещения от сервера. Однако гарантируется чтоagent_id
будет доступен, когда будут вызываться методыoffer_action
,deal_action
иround_result_action
. - Если агент не отвечает более, чем 2 секунды, например из-за долгого цикла обработки в
offer_action
, он удаляется из обработки. Никакие дальнейшие его сообщения не обрабатываются. - Если нужна длительная инициализация, проведите ее в методе
__init__
, так как сервер будет одну минуту ждать инициализации всех агентов. - Агент должен не упасть с ошибкой или не дисконнектнуться хотя бы в 1 % раундов, чтобы его очки учитывались.
Следите за обновлениями новостей на сайте и в Slack: могут быть скорректированы правила или добавлены утилиты для повышения удобства.
В папке agent
можно найти несколько примеров агентов. Ниже представлены некоторые из них.
Простой агент без памяти, который всегда делит поровну и принимает любое ненулевое предложение.
class DummyAgent(BaseAgent):
def offer_action(self, m):
return m.total_amount // 2
def deal_action(self, m):
if m.offer > 0:
return True
else:
return False
def round_result_action(self, data):
pass
- Клиент создается через
__init__
. После создания отсылает серверу сигнал готовности. - Сервер некоторое время ждёт участников и начинает серию раундов.
- Случайным образом выбираются пары агентов: один proposer, другой responder.
- Сервер спрашивает у proposer размер его предложения (вызывается метод
offer_action
) и отсылает результат к responder. - У responder вызывается метод
deal_action
, ответ отсылается на сервер, который решает исход раунда. - В случае окончания раунда, либо дисконнекта одного из участников, сервер отсылает результат агентам и у них вызывается
round_result_action
. - Это повторяется много раз, пока не наберется достаточная статистика по результатам игр агентов.
- Классы агентов всё это время находятся в памяти клиентов и могут хранить состояние предыдущих раундов.
Если вы хотите сделать сборку с классом, отличным от класса по умолчанию, то это можно сделать, воспользовавшись
аргументом agent_cls_path
. Пример:
docker build --build-arg agent_cls_path=agent.dummy.DummyAgent -t <dockerhub_login>/ai_agent -f Dockerfile .
Если нужны дополнительные библиотеки в сборке, добавьте их в файл requirements.txt
и сделайте ребилд с флагом
--no-cache
.
Посмотреть локальные образы можно командой docker images
удалить через docker rmi <имя или идентификатор>
Настройки сборки могут изменится, и не все файлы из проекта могут быть включены в образ. Чтобы быть уверенным, что файлы
попадут в образ, размещайте их в папке agent
.
Можно использовать тэги для образов, подставив в конце :<тэг>
. Таким образом становится легче следить за версиями.
Пример:
docker build -t <dockerhub_login>/ai_agent:v1 -f Dockerfile .
При сабмите используйте адрес вместе с тэгом.