2500 дней создания AI без использования нейронных сетей или покерный бот, который дороже $50к

Вступление

Давно хотел написать статью про своё хобби, которое стало нечто большим для меня. 

Я закончил математический факультет (ТвГУ) в 2012 г.  В период учёбы я профессионально играл в покер, как вживую, так и онлайн (yura_$198802, основной аккаунт PS). Не могу сказать, что был супер успешен, но для студента вполне себе подработка. Уже с 2011 года я начал карьеру программиста и продолжаю её по сей день. Это мой основной источник заработка. Но где-то в 2014 я серьёзно решил заняться написание покерного бота, для онлайн площадок. На данный момент «я» превратился в команду энтузиастов, которая двигает этот проект вперёд! Еще в университете довольно таки плотно был знаком с Байесовским классификатором, а также имел  базовые представления по нейронным сетям. Сейчас стало «мейнстримом» считать, что если вы нашли релевантные данные и корректно обучили сетку с использованием (ML, CatBoost, TensorFlow и т.д.), то вы сделали что-то похожее на «искусственный интеллект»(далее AI). Я решил , что если раскрою верхнеуровневую архитектуру своего проекта, это может кого-то удивить тем, что AI — это нечто большее.(только не профессионалов в этой области) И даже в такой игре как покер, где казалась бы не обойтись без нейронных сетей (на самом деле это действительно так), до момента органического встраивания их в продукт, лично у меня прошло примерно 2500 дней. Сразу хочу отметить, что способ, когда ты знаешь всю информацию обо всех участниках и играешь с одними и теми же, где можно просто собрать модель и обучить её по лучшим и быть в их числе, не подходит для реального онлайн покера. Тут  нужно делать изначально экспертную систему, которую уже можно бесконечно долго улучшать и модифицировать.

P.S. Предполагается знание покерных и IT- терминов у читателя.

Мы назвали наше решение →

MONICA

АрхитектураАрхитектура

Monica.Proxy

Это основной блок системы. По сути является прокси-сервером, который обеспечивает взаимодействия клиента и AI. В основном весь проект написан на C#, есть немного С в ядре. Прокси осуществляет взаимодействие со всеми участниками процесса кроме покер рума (далее ПР).

Client API — фактически это набор контроллеров, в который на вход подаётся (JSON или XML) из нашего протокола. Мы передаем с клиента название функции, которая должна дать ответ и параметры. В момент обработки запроса, если все удачно произошло, вызывается нужная функция на сервере, а там уже происходит выполнение той или иной команды. Грубо говоря (RPC).

ORM — основная база где хранится вся история действий клиента который был подсоединен 

к серверу использует MySQL. Сама ORM Devexpress. Используем DTO (DAL) подход. База с PostgreSQL пополняется сторонними программами, такими как PT4 и HoldemManager. Из неё просто тянем процедурами конкретные параметры. Вообще база postgresql становится архаизмом, так как изначально бот играл сессии только располагав столы стопкой, что не позволяло видеть рантайм картину за всеми столами одновременно. Сейчас у нас разрабатывается отдельный модуль мониторинга, который закроет эту задачу.

Update Module — не самая сильная часть проекта, всё никак не перенесём на TeamCity из за того, что всё работает;) Сейчас реализовано так. Есть сервер (в теории отличный от того, где находится прокси), который в свою очередь просто по клиентскому запросу (по http, используется внутренний протокол), отдаёт с определенной папки опять же по http протоколу либо ftp всю изменившеюся часть папки на компьютер прокси. В момент обновления, прокси сам перезагружается, а клиент и риадер обновляются от прокси, в момент запуска.

Security — у нас немного проверок на безопасность, что-то сейчас не используется за ненадобностью и где-то просто лежит, но у нас есть следующие модули.  Есть модуль по привязки ЭЦП (X509Certificat), которая подписывает прям XML (JSON). Есть модуль с логином и паролем, когда с клиента приходит связка, Логин, Пароль, (активационный ключ) token то на сервер передаётся хеш MD5,  , а на уровне сервера к хешу привязывается соль, есть даже перец в коде.

Есть модуль даже по ответам в чате. Внимание! Одно из первых мест где использовалась нейронная сеть. Для классификации сообщений в чате изначально (нам, не нам) и простые заготовленные варианты ответа. В последствие отказались от этого, кроме комментария на финальном столе об отказе в делёжке. В Poker Stars редко кто пишет в чат и лучше вообще отключить сообщения.

Клиентский код проходит обфускацию (мы использовали https://www.eziriz.com/dotnet_reactor.htm, он слишком дорогой, мы триальной версией обрабатывали, есть опыт с https://www.gapotchenko.com/eazfuscator.net). Сжимали всё до одного exe, с разным весом для каждого клиента, и разным доменным именем. Дабы если клиент окажется агентом сб безопасности или он решит посотрудничать с ними и вышлет наш exe (клиент), не получить быстрый бан по коду на других машинах. Скажу сразу СБ очень переоценены и по секрету всему свету, действительно достойные оппоненты только ребята из Amaya Gaming Group (СБ PokerStars). С остальными мы даже не знакомы;) Всего за всю историю использования получали 2 бана от PokerStars всей линейки ботов (мой основной аккаунт попал туда же и они запретили мне играть у них на платформе). 1-й за то что начали бесцеремонно брать файлы handhistory, которые создает ПР, 2-й за то что хотели ускорить процесс ввода информации и вообще забыли о человеческих движениях мыши. Да еще важный момент о программном вызове WinApi речь вообще не идёт, у них там стоят хуки и они в принципе блокирует это. Всё вводится и двигается «Аппаратно». На данный момент 3 года без бана с выводами и даже одной проверкой СБ;)

Ну и как бы основное, что вся архитектура в принципе заточена на безопасное использование клиентов, то что на клиенте нет никого кода решателя, точнее есть, но минимальный для авто паса. Покер румы отделены от места где проходит решения. Если мы на порту сидим в ОС Windows, как минимум никто туда попасть не может. Но я был бы очень признателен за критические обоснованные замечания и любые предложения.

Poker core — это сторонний модуль взятый у человека который написал его на C (оболочка C#) где-то в 2000 году. Это модуль который работает с покерными картами в количестве 52. По сути он переводит строку в карту (шестнадцатеричная маска) по максам определяет комбинацию, двух карт, ранг любой из твоих карт, карты флопа, выигравшую комбинацию, считает Pod Odds. И делает это примерно 1000 рук за 0.1 сек, короче просто заканчиваю всё, там он написал около 100к+ строк, где в основе маски и он побитово по ним все вычленяет. Модуль оттестирован, полностью исправен, работает постоянно. На основе него написаны функции по определению Стрит-дро, гатшотов, координированость борда, вторая, третья пары и т д.

Replayer — это модуль с gui на wpf, он может отображать все прошлые раздачи любого клиента который играл на этом сервере и может симулировать момент принятия решения из любой части раздачи и вызвать AI. Используется только для разбора некорректных раздач. Просто лежит проектом в общем решении и может использоваться только программистами.

GUI — сейчас прокси, это как бы еще и админка за всеми пользователями которые используют данный сервер, кроме этого на Gui ничего нет. Настройки, кнопки перезапуска и окно лога сервера, где только служебная информация.

Экскурс в турнирный покер

Перед тем как описывать AI модуль, дам примерный обзор из чего складывается игра в турнирный покер. 

    Open Fold — означает, что карты которые вы получили не подходят и вы вынуждены сдаться и дождаться следующей раздачи.

   1vs0 — означает, что вы сделали рейз или 3 бет, или 4 бет, или выставились, или все сбросили. Раздача либо больше не зависит от вас, либо уже завершилась вашей победой или вылетом. Другими словами вы совершали действия только префлоп.

      1vs1 — означает что после действий префлоп, наступил следующий круг торгов и открылся флоп и вы остались строго один на один с оппонентом.   

      1vs2 — означает что после действий префлоп, наступил следующий круг торгов и открылся флоп и вы остались строго один с двумя  оппонентами.   

       1vs3< -  означает что после действий префлоп, наступил следующий круг торгов и открылся флоп и вы остались один с тремя и более оппонентами.   

Эти графики получены сугубо из нашей статистики, цифры у всех могут отличаться, но если это не покер на условные деньги или совсем минимальные ставки, то тенденции именно такие.

Глубокие стекиГлубокие стеки Глубокие стекиГлубокие стеки Глубокие стекиГлубокие стеки

Другими словами, тут явно видно что в основном при принятие решений вы сталкиваетесь с выбором принимать участие или нет, либо играете 1 на 1.

Именно по этому принципу я и развивал AI, те максимальный акцент сделан на такие раздачи.

Есть еще один важный момент, из чего складывается выигрыш в течение турнира. Цифры на рисунке для красоты.

Основой выигрыша (измерение в ББ) является поиск слабых мест оппонентов и использование их в своей выгоде. Их большое множество и с нуля нейронная сеть изначально вам их не формализует. Для примера к ним можно отнести, узкие диапазоны открытия, чрезмерно широкие, слабая защита в зоне блайндов, недостаточная активность в зоне блайндов, частая попытка продолжить игру на флопе, наоборот частые сдачи на флопе, реакции на большие ставки, реакции на маленькие ставки, слабость игры в флопе с несколькими соперниками, активная игра в 3 бет потах, неактивная, предоставление положительных шансов банка (pod odds), оценка динамики роста стека и т.д Перечислять их можно долго. Но для их правильного использования нужна релевантная статистика и по сути максимально быстрая классификация оппонента, точнее обнаружение слабости. В начале турнира когда слабых игроков много, эксплуатация применяется гораздо чаще и эффективна. К концу турнира приходится играть с более сильными соперниками и тут для выбора эксплуатирующий стратегии должны быть очень весомые обстоятельства. В основном вы должны играть строго по ГТО правильно закладывая диапазон (даже дефолтному оппоненту), тогда баланс блефа и игры по карте будет приносить успех.

AI

Подключается одним интерфейсом сейчас, на вход получает объект m_hand, который сформировался на клиенте. На выходе один объект m_decision, фактически решение.

(Кол, Пас, Рейз (какого размера), Allin). В проекте около 130к строк. Поддержаны режимы игры от 9 человек за столом — до Хедз Апа. Скажу что есть сейчас из основного.

Решение на Префлопе:  

Open Push (Open Raise) просчитан на позициях EP, MP, CO, BTN, SB по ГТО в дефолтных игроков , ранее были еще комбинации с тайтовыми, агро и фишами. (на уровнях блайндов    1.5,1.9, 2.2, 2.5, 2.7, 3, 4,5,7,10,13,17,25, 30, 35,42, 50). Используется в турнирах, так как уровень блайндов постоянно меняется.  И вот тут ВНИМАНИЕ одно из мест где используется нейронная сеть. После тестирования, подбора шага расчета, и перебора разных типов оппонентов, хорошо себя зарекомендовала модель которая на вход получает характеристики оппонентов сидящих после вас, данные о призовых (Что-то типа ICM, но не совсем. Используется история получения конкретного выигрыша в турнире такого же рода в балансе с возможностью вылета). И относительно этого выбирается ряд оппонентов для которых заранее просчитан диапазон атаки. Плюсом его является, что сколько не рассчитывай для разных типов игроков все варианты не просчитать. И второй очень важный момент, что теперь если после вас сидят X игроков, где X из [1,8] , а статистика есть только на Y, где Y из [1,8] и часто бывает, что X>Y, т.е статистика может быть не на всех.  Нейронная сеть достаточно хорошо выбирает диапазон для конкретной ситуации.

Таким же образом с позиций EP, MP, CO, BTN, SB, BB рассчитана защита от 3 бета против одного. Просчитан префлоп при защите от одного оппонента если мы на CO, SB, BTN, BB (на уровнях блайндов    1.5,1.9, 2.2, 2.5, 2.7, 3, 4,5,7,10,13,17,25, 30, 35,42, 50), с этих же позиций защита от 4 бета против одного. На всех остальных позициях играется в зависимости от уровня дефолтный диапазон с дефолтной логикой. 

Против двух есть отдельная обработка, используется стата из PT4(PostgreSQL). Пробовали тут прикрутить нейронную сеть, но кроме линейно зависимого сквиза (3 бета) от элементов статистики одного из оппонентов, а также позиционного ColdCall.  В реальной борьбе ничего лучше нет.  

Против трех и более играется по шансам банка, более тайтово. Тоже по заранее описанной логике. Заходы в большие банки в позициях на среднем диапазоне и т.д.

Решения на флопе, есть несколько дефолтных стратегий, АБЦ, есть эксплойтинг фиша, игра против гипер тайта, эксплойтинг бетсайзингом. Стратегии НЕ ВЫДЕЛЕНЫ в отдельные, а используются в рантайме по обстановке за столом и по определению типов оппонентов. 

В момент того как у «Hero» остается меньше 30 ББ и идёт игра строго один на один, есть выделенная стратегия, решение там принимается по абсолютно иным принципам, никак не пересекаясь с дефолтными. Фактическ там используются (физически на диске) заранее просчитанные деревья (ГТО игра против заданного диапазона), а где-то в префлопе и константы! В момент решения я использую PioSolver, у него есть процесс, который можно запустить и по текстовому АПИ, брать у него результаты деревьев (им же созданные). Есть просчитанные деревья для всех флопов (естественно они раскрываются в тёрн и ривер) в тайтовых спектрах для 15 ББ (адаптированы под 0–25ББ).

Есть просчитанные деревья в фул спектрах для хедз апа для 20ББ (адаптированы 0–25ББ). Они применяются и хорошо себя зарекомендовали. Есть просчитанные деревья для 50ББ в обычном префлоп споте и в трибеченном, но в ранних стадиях признаны мной  слабо плюсовыми ибо дефолтная стратегия дает лучший результат. Для справки скажу чтобы просчитать один тип флопа с кастомным диапазоном нужно построить 1755 деревьев на программе Pio Solver, человек эту работу делал месяц. Скажу еще что в момент принятия решения используется примерно 500ГБ очень сжатой просчитанной информации (7020 деревьев), Время принятия решения на данный момент (0.03с -0.4с) в среднем в рабочем процессе. Долго считывает клиент около (0.5с-2). И поэтому общее пока что можно строго ограничить 3 секундами. (комфортно запускать по 10 столов, макс 14, далее очень сложно запускать, вырастает вероятность ошибки считывания). Добавлена функция на клиенте быстрого паса, когда решение принимается на клиенте, для «очеловечивания»

 AI слаб, в принятие нестандартных решений, например в сложных префлоп торгах в глубоких стеках, или на флопе против 3х и более оппонентов из за того что ситуации такие случаются крайне редко, а прогнозировать их крайне сложно. Но фактически из за более тайтовой стратегии в таких моментах все равно играется в плюс. Тут есть над чем работать. ITM в регулярных MTT>100 человек (не турбо) около 26%, выборка на разных аккаунтах более чем 10к сыгранных турниров с последней видоизмененной логикой. Каждое серьезное обновление логики, требует большого времени на тестирование, очень часто бывает, что казалось бы улучшение приводит к более плохой игре из за большой дисперсии и ограниченности поля тестирования процесс улучшения идёт не так быстро как хотелось бы. Готовим серьезное обновление как раз с использованием нейронной сети. А именно удалось автоматизировать просчёт деревьев на PioSolver. Сейчас цель просчитать примерно (52650 деревьев) и как раз по входным данным оппонента, как на префлопе будет выбираться заранее просчитанный диапазон, максимально приближенный к конкретной ситуации.

PioSolver API  — это калькулятор игры ОДИН НА ОДИН. PioSolver строит дерево решений исходя из диапазонов которые заданы для игрока без позиции (OOP) и игрока в позиции (IP), а также по доп параметрам. Это ПО по сути специально сделано, чтобы использовать бота, ребята сделали просто всё (наша версия edge). Там можно построить дерево префлоп или флоп (а можно прифлоп раскрывающийся в несколько флопов).У них есть API (как уже писалось в пункте про AI) и с помощью них я могу в рантайме брать любое дерево решений и добираться до того узла дерева который у меня на рантайм покерном столе. Но у них всё устроено так, что можно не только брать готовые решения, а с помощью их API даже полностью задавать и просчитывать программно. На данный момент есть блок, который запускает из билда екзешник Pio, цепляет его вывод и вход и есть наши API которое достаёт нужную инфу из деревьев. По сути всё.

Monica.Client

Это фактически клиент, он отвечает за формирование данных в рантайм режиме с покерных столов. Передает данные на сервер, получает решение, и аппаратно нажимает на кнопки. Перед его запуском клиент покер рума, должен быть соответственно настроен вручную! Осуществлена поддержка трех румов (888, party, PS). Работает только на Windows (от 7 и выше). Желательно ставить на виртуальную машину, но не обязательно.

Scan Engine — Блок который парсит в рантайме экран каждые 0.1 сек. По косвенным признакам понимает когда у него решение, сравнивает по заранее нарезанным координатам картинки,   по алфавиту (который набивается для каждого рума отдельно, человеком) определяет имена деньги ставки и всю необходимую инфу. И отдаёт на сервер. Есть хорошо описанная модель для подключения новых покер румов! Делается довольно таки быстро — долго тестировать. Работает как часы.

Keyboard API mouse API — для ввода данных используется аппаратный эмулятор (там есть и клавиатура и мышь), работает через длл (написана на C++), имеет строгое API, оттестирован, работает мгновенно. На данный момент боты с такой технологией уже не создаются, мы перешли на новое поколение ввода информации, но старые продолжают работать без банов. Новое решение позволяет больше не устанавливать никаких программ на компьютере где находится PokerRoom.

API мыши и клавиатуры есть и программные тупо по winAPI. (не используются нигде только, если не ошибаюсь одна функция есть в 888).

Monica.Reader

Это Gui, общается и с прокси и с клиентом. Где можно отслеживать всех ботов которые принадлежать конкретному человеку с разных компьютеров. В данный момент переносим этот модуль на WEB (PimeVue), чтобы с любого устройства было удобно контролировать.

Заключение

Ну, а как же главный вопрос?! Играют то в плюс?!

Когда я начинал делать первого бота и запустил его с минимальной логикой он играл примерно с ROI -50%(ROI это коэффициент, показывающий доходность или убыточность бизнеса с учетом вложенных в него средств. Измеряется в процентах.) На данный момент есть версии играющие уже большую дистанцию с ROI 20% , но там отдавались большие мажоры. Есть версии с около нулевыми результатами. Наиболее прибыльная бизнес-модель, это запуск многих версий на разных румах и человек умеющий доигрывать финальные части. Параллельно с этим есть куча автоматических видео от PokerStars, с тем как он поздравляет наших ботов с победой в больших турнирах. Мы с нетерпением ждём бана старой линейки, чтобы выложить их всех и посмеется на фразами на форумах типа в PokerStars такая СБ, с анти ботами, которая вычисляет тебя, как только ты о них подумал. В название указал про бота который дороже $50к, так как где-то на хабре читал статью про покер ботов и там в конце было что то типа «ну я же не пишу про бота который стоит дороже $50k», ну, а вот я получается пишу;)

P.s Оценка цены сугубо моя личная, боты не продаются. Статья для развлечения. Спасибо , что дочитали до конца.

© Habrahabr.ru