Бытовые сниппеты №2: Индикот

Есть такая игра «Индикот» для Android. Игра как игра, казуального жанра «три в ряд», коих сейчас вагон. Но вот как-то так получилось, что играем мы в неё третий год, и всё никак не доиграем.

Как и в остальных играх модели «free-to-play», здесь предлагается приобретать игровые бонусы за местную валюту — бантики. Виртуальные бантики можно купить за вполне себе реальные рубли, а можно заработать просмотром однообразной рекламы — периодически и понемногу.

Каждые полчаса появляется возможность получить 10 бантиков за один просмотр рекламного ролика. Звучит как отличный повод для автоматизации! Стало быть, нужно создать бота, который запустит игру, подождёт полчаса, нажмёт правильные кнопочки для запуска ролика и терпеливо посмотрит рекламу. В конце концов, кого волнует, что рекламодатель заплатил настоящих денег, чтоб его рекламу крутили? Пусть скажет спасибо, что мы хотя бы её не скликиваем.

Итак, нам нужно как-то получить скриншот для анализа с Android-аппарата. Воспользуемся утилитой ADB из комплекта Android SDK. В аппарате предварительно нужно активировать developer-режим.

Сделать скриншот можно стандартной Android-утилитой screencap. Работает даже без root’а!

adb shell "screencap -p" | sed 's/\r$//' > screenshot.png

Загвоздка в том, что создание PNG-картинки на аппарате может занять продолжительное время. Поэтому я сделал примерно вот так (нужен установленный ImageMagick):

adb shell "screencap | gzip" | \
    sed 's/\r$//' | \
    gunzip | \
    tail -c +13 | \
    convert -size 2560x1600 -depth 8 rgba:- screenshot.png

Скриншот снимаем в raw-виде, сжимаем на аппарате, разжимаем на ноутбуке и там же конвертируем в PNG. Получается чуть быстрее, но всё равно медленно: от одной до семи секунд. Пока непонятно, как бы ускорить процесс, и это останавливает от написания полноценного бота, который бы самостоятельно проходил уровни. Впрочем, такой скорости достаточно для нашей задачи.

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

Картинки легко сравнивать с помощью наложения в режиме смешивания «разница». Если некоторый регион на картинках одинаковый, результирующий регион будет абсолютно чёрным.figureЕсть чёрный регион — есть совпадение.

Определив, на каком экране мы находимся, мы можем нажимать правильные кнопки на экране. На помощь опять приходит ADB. Так мы сэмулируем клик по координатам (100, 100):

adb shell input tap 100 100

А вот так — нажатие «железной» кнопки вкл/выкл:

adb shell input keyevent 26

Ещё надо добавить немного логики: если два последовательных скриншота одинаковые, и имеют специальный логотип, значит, реклама закончилась, можно возвращаться в игру. Или: если попали на экран с таймером, надо выключить экран и подождать полчаса, пока таймер не обнулится, и мы сможем снова смотреть вожделённую рекламу.

Я собрал небольшой скрипт на Python: репозиторий. Теперь остаётся запустить его и, откинувшись в кресле, наблюдать, как растёт бантичное благосостояние…

Один комментарий к “Бытовые сниппеты №2: Индикот

  1. Лидия

    Обожаю вас, Михаил! Теперь мы сказочно богаты! Можно тратить бантики налево и направо 🙂

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поставьте галочки правильно (как бы защита от спама):

Я бот

Я не бот