Всем привет! Меня зовут Олег, я старший Python/Go разработчик в Cloud.ru, а в свободное от работы время я... довольно азартный человек!
Нет, вы не подумайте, я не делаю ставки на спорт, не мучаю однорукого бандита и не пытаюсь испытать удачу в рулетке, но я очень люблю конкурсы и розыгрыши в Интернете, в которых надо играть в какую-нибудь веб-игру и выигрывать призы.
В таких конкурсах для меня главное не победа и призы, а участие и дух соревнования. Правда играю в них я не совсем честно. Различными способами я умудряюсь набрать наибольшое количество очков/баллов/монеток и не тратить на это дни и недели своей жизни. А как именно - расскажу в этой статье на примере одного из недавних конкурсов, который проводился на Хабре в честь 25-летия Ростелекома.
Этот конкурс уже закончился и итоги были подведены, поэтому я решил, что могу рассказать про то, как конкурс работал и как можно обойти "официальный" способ участия.
В чём смысл игры?
Для участия в конкурсе требовалось перейти на страницу веб-игры и выбрать одного из персонажей:
Java-разработчик
Системный аналитик
QA-тестировщик
После выбора персонажа вас встречает геймплей, в основном известный людям с нестабильным интернет-соединением по игре с диназавриком из Google Chrome. Назовём этот жанр tap-and-jump. Ваш персонаж бежит по полю и нажатием клавиши Space
вы заставляете его прыгать. Вам надо собирать монетки, куски кода, всякие усилители, но главное - успевать перепрыгивать различные препятствия, за каждую пойманную преграду вы теряете одну жизнь, а жизней у вашего персонажа всего 3.
Интересным отличием является то, что кроме монеток есть много других элементов:
Бустеры/усилители: предметы, которые при взятии дают какой-то положительный эффект - неуязвимость, дополнительную жизнь и т.д.
Факты: они ничего не дают, но знакомят игрока с интересными фактами о Ростелекоме и Wink
Вопросы: поймав вопрос, надо будет на него ответить - за правильный ответ дают баллы.
Правила конкурса
На лендинге конкурса указано, что для того чтобы участвовать в розыгрыше надо набрать не менее 200 очков в игре, тогда по окончанию победители конкурса будут определены в случайном порядке. Буквально с третьей попытки я смог набрать нужный минимум.
Но если вы более въедливый нёрд любознательный, то скорее всего начнёте искать какое-нибудь положение конкурса. В этом случае оно тоже есть и находится в футере лендинга под ссылкой "Правила конкурса".
Самый интересный раздел положения - раздел 3 "Условия участия в акции". Что удивительно, это то, что условия отличаются от того, что написано в лендинге, а именно в пункте 3.1.2 написано, что для того чтобы участвовать в розыгрыше, надо набрать не менее 2000 очков (а не 200, как написано на лендинге).
Также в разделе 5 "Определение победителей и подведение итогов акции" в пункте 5.1 написано, что победителями становятся по 10 человек из каждой ветки игры, которые набрали наибольшее количество баллов (а не случайные участники, как написано на лендинге).
Но также я не пропустил и пункт 5.2, в котором чётко указано, что "претензии и апелляции к результатам Акции не принимаются", так что в любом случае этой статьёй я не пытаюсь подвергать сомнению итоги конкурса независимо от их соответствия изложенным правилам. Просто хочу указать на несостыковку лендинга и Правил конкурса.
В поисках победы
Я очень хотел поучаствовать в конкурсе и выиграть какой-нибудь приз, ведь по официальным правилам те, кто набирают наибольшее количество очков могут рассчитывать на беспроводной аккумулятор, термобутылку или портативный увлажнитель воздуха с подсветкой. Но прыгать человечком по 10 часов в день я точно не хотел, поэтому решил набрать очки более простым способом, а именно - разобраться, как работает игра и передать на сервер запись с баллами, которые бы точно привели меня к победе. Я начал своё исследование.
При загрузке страницы с игрой к нам загружается весь исходный код на JavaScript и игра запускается в браузере. После того, как игрок совершил забег - игра должна куда-то сохранить результаты, скорее всего результаты отправляются на сервер. То есть конечная моя задача - найти способ, как отправить результаты с нужным для сокрушительной победы количеством очков.
Перед началом забега я открыл консоль разработчика в браузере, чтобы отследить, в какой момент какие запросы отправляются на сервер. Но в момент запуска игры поток исполнения останавливался на размещённой заранее в исходном коде точке останова, которая не позволяла отдебажить код и продолжить выполнения скрипта.
Обойти это можно было отключением остановки на брейкпоинтах во всём приложении, но тогда пропадает возможность отдебажить скрипт игры. В общем, для отслеживания запросов мне это и не нужно, поэтому я деактивировал все точки останова и перешёл во вкладку Network
.
С открытой консолью я выполняю забег и после третьего удара персонажем об чашку (то есть после проигрыша) во вкладке Network вижу тот самый запрос, который и записывает результат на сервер.
POST https://rt.habr.io/game/save
Кажется, что задача решена, но результат игры на сервер отправляется в завуалированном виде, а именно в строке вида BBBCCKAKJAAHBJJCFEHEAJJB
. Каждый раз этот результат разный и с нескольких попыток догадаться, как же эта строка формируется у меня не удалось.
Поэтому я решил найти код формирования строки с результатом прямо на странице. Какого было моё удивление, когда я увидел неминифицированный JavaScript код. С таким намного проще работать!
Простым поиском по коду я нашёл функцию, которая отправляет запросы на сохранение. Здесь тело запроса формируется в функции encodeResult, она находится чуть выше.
В этой функции описана логика формирования строки. Разобрав её, стало понятно, что строка состоит из трёх частей, разделёнными буквой K
. Каждая часть - это какое-то десятичное число, в котором каждая цифра соответствует букве, то есть 0
- A
, 1
- B
, 2
- C
и т.д.
Сразу становится понятно, почему разделителем выбрали K
- она десятая по счёту в английском алфавите и не будет встречаться в числах.
Осталось понять, что обозначает каждое число. Это оказалось не просто, так как непонятно, что обозначают переменные He
, Ht
, Gs
и Bs
. Поэтому я просто совершил 10-15 забегов и посмотрел, какие результаты в каком случае отправляются.
Методом тыка выяснилось, что три числа это:
Время игры в секундах.
Количество набранных очков.
Магическое число, соответствующее ветке игры минус количество набранных очков.
До последнего было догадаться сложнее всего, поиск по коду ничего не давал.
Перенеся логику формирования строки в код, я попробовал отправить пару запросов на сервер и получил от него ответ об успехе.
В итоге я решил перенести логику формирования и отправки запросов в код, чтобы не curl-ить сервер вручную. Код с приложением находится здесь (на гитхабе я с недавнего времени перманентно забанен).
Итоги
Недавно были подведены итоги конкурса - они размещены в этой google-таблице. Если отсортировать колонку Баллы
по невозрастанию, то в первой строчке оказывается мой ник на хабре с результатом в 21851 балл, с невероятным отрывом от второго места в 4 раза!
К сожалению, материальных призов я не получил, так как в итоге конкурс проводился по правилам, описанным на лендинге, а не в Правилах конкурса. Но, как и было обещано, я получил свой промокод на Wink и теперь я могу в свободное от работы время смотреть с женой свежие фильмы в хорошем качестве!
Есть ли во всём этом смысл? Наверное, нет, но процесс лично для меня был интересным и захватывающим.
P.S. Не могу не упомянуть, что помимо абьюза веб-игр я ещё и веду свой телеграм канал, где пишу про работу в IT, про self hosting, безопасность и множество других технических и нетехнических вещей, которые меня интересуют. Жду вас там!
AdrianoVisoccini
В свое время у нас в общаге был легендарный товарищ который абьюзил всякие розыгрыши от компаний, только физические. Вся комната у него была завалена брендированным барахлом. Использовались весьма интересные методы, например когда нужно было собирать ключики от банок и всякие крышечки, то у него на поруках была целая сеть бездомных/пьяниц которые за сущие копейки собирали ему неимоверное количество этих крышек.
Я лично его не знал, но знал его соседа, как то раз зайдя к нему в гости увидел у него на столе огромную гору выигранных часов от AdrenalineRush штук наверное 40-50...