Всем привет! Меня зовут Олег, я старший Python/Go разработчик в Cloud.ru, а в свободное от работы время я... довольно азартный человек!

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

В таких конкурсах для меня главное не победа и призы, а участие и дух соревнования. Правда играю в них я не совсем честно. Различными способами я умудряюсь набрать наибольшое количество очков/баллов/монеток и не тратить на это дни и недели своей жизни. А как именно - расскажу в этой статье на примере одного из недавних конкурсов, который проводился на Хабре в честь 25-летия Ростелекома.

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

В чём смысл игры?

Игра в процессе
Игра в процессе

Для участия в конкурсе требовалось перейти на страницу веб-игры и выбрать одного из персонажей:

  1. Java-разработчик

  2. Системный аналитик

  3. QA-тестировщик

После выбора персонажа вас встречает геймплей, в основном известный людям с нестабильным интернет-соединением по игре с диназавриком из Google Chrome. Назовём этот жанр tap-and-jump. Ваш персонаж бежит по полю и нажатием клавиши Space вы заставляете его прыгать. Вам надо собирать монетки, куски кода, всякие усилители, но главное - успевать перепрыгивать различные препятствия, за каждую пойманную преграду вы теряете одну жизнь, а жизней у вашего персонажа всего 3.

Процесс игры: чашки надо перепрыгивать, всё что в воздухе - собирать
Процесс игры: чашки надо перепрыгивать, всё что в воздухе - собирать

Интересным отличием является то, что кроме монеток есть много других элементов:

  • Бустеры/усилители: предметы, которые при взятии дают какой-то положительный эффект - неуязвимость, дополнительную жизнь и т.д.

  • Факты: они ничего не дают, но знакомят игрока с интересными фактами о Ростелекоме и Wink

  • Вопросы: поймав вопрос, надо будет на него ответить - за правильный ответ дают баллы.

Правила конкурса

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

Но если вы более въедливый нёрд любознательный, то скорее всего начнёте искать какое-нибудь положение конкурса. В этом случае оно тоже есть и находится в футере лендинга под ссылкой "Правила конкурса".

Раздел 3 "Правил конкурса"
Раздел 3 "Правил конкурса"

Самый интересный раздел положения - раздел 3 "Условия участия в акции". Что удивительно, это то, что условия отличаются от того, что написано в лендинге, а именно в пункте 3.1.2 написано, что для того чтобы участвовать в розыгрыше, надо набрать не менее 2000 очков (а не 200, как написано на лендинге).

Раздел 5 "Правил конкурса"
Раздел 5 "Правил конкурса"

Также в разделе 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 забегов и посмотрел, какие результаты в каком случае отправляются.

Методом тыка выяснилось, что три числа это:

  1. Время игры в секундах.

  2. Количество набранных очков.

  3. Магическое число, соответствующее ветке игры минус количество набранных очков.

До последнего было догадаться сложнее всего, поиск по коду ничего не давал.

Так выглядит победа!
Так выглядит победа!

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

В итоге я решил перенести логику формирования и отправки запросов в код, чтобы не curl-ить сервер вручную. Код с приложением находится здесь (на гитхабе я с недавнего времени перманентно забанен).

Итоги

Недавно были подведены итоги конкурса - они размещены в этой google-таблице. Если отсортировать колонку Баллы по невозрастанию, то в первой строчке оказывается мой ник на хабре с результатом в 21851 балл, с невероятным отрывом от второго места в 4 раза!

Выпью сегодня вечером за свой успех, какой же я красавчик и победитель, непонятно, почему до сих пор не миллионер
Выпью сегодня вечером за свой успех, какой же я красавчик и победитель, непонятно, почему до сих пор не миллионер

К сожалению, материальных призов я не получил, так как в итоге конкурс проводился по правилам, описанным на лендинге, а не в Правилах конкурса. Но, как и было обещано, я получил свой промокод на Wink и теперь я могу в свободное от работы время смотреть с женой свежие фильмы в хорошем качестве!

Есть ли во всём этом смысл? Наверное, нет, но процесс лично для меня был интересным и захватывающим.

P.S. Не могу не упомянуть, что помимо абьюза веб-игр я ещё и веду свой телеграм канал, где пишу про работу в IT, про self hosting, безопасность и множество других технических и нетехнических вещей, которые меня интересуют. Жду вас там!

Комментарии (1)


  1. AdrianoVisoccini
    02.12.2024 14:05

    В свое время у нас в общаге был легендарный товарищ который абьюзил всякие розыгрыши от компаний, только физические. Вся комната у него была завалена брендированным барахлом. Использовались весьма интересные методы, например когда нужно было собирать ключики от банок и всякие крышечки, то у него на поруках была целая сеть бездомных/пьяниц которые за сущие копейки собирали ему неимоверное количество этих крышек.
    Я лично его не знал, но знал его соседа, как то раз зайдя к нему в гости увидел у него на столе огромную гору выигранных часов от AdrenalineRush штук наверное 40-50...