Как мы сделали битву разработчиков

image
Вот тут два игрока соревнуются, кто быстрее решит задачу

Вообще-то мы ничего специально не придумывали, как-то всё само получилось с Code Battle. Взяли простую задачу по информатике, добавили мультиплеер, чтобы два разработчика видели код друг друга, и предложили приз тому, кто пройдёт тесты быстрее.

И что-то всем внезапно понравилось. Причём так, что в итоге этим сервисом пользуются даже в Яндексе и других крупных компаниях на мероприятиях для разработчиков, а также в эпическом соревновании разных вузов.

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

Можно использовать любой язык из 16 доступных, гуглить в процессе — пожалуйста (если успеете), тырить чужой код и отлаживать у себя быстрее, чем это сделает оппонент, — тоже не проблема.

В итоге получились очень забавные соревнования.

Механика игры

Один поединок — это когда ровно два разработчика сидят за своими компьютерами и видят веб-страницу.

image

На левой половине — редактор собственного кода, на правой — код оппонента. Видно статусы прохождения тестов.

16 языков на выбор. Можно писать на любом. А ещё можно менять язык в любой момент во время решения задачи. Сборка (компилирование или интерпретация) выполняется на удалённом сервере, где развёрнуты все нужные среды. Для каждого языка предусмотрен отдельный скрипт, который запускает код решения на заранее подготовленных тестовых данных и сравнивает полученные результаты с ожидаемыми ответами.

В дуэли возможны следующие результаты:

  • Кто-то победил: один из разработчиков быстро написал код, прошёл все тесты и выиграл.
  • Оба проиграли: не успели в таймер задачи (соревноваться надо ещё и с ним).

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

То есть можно получить немного очков за частичное решение задачи, много — за полное и быстрое или ничего не получить, если ничего не успеть.

Зачем просмотр кода оппонента?

Это, собственно, киллер-фича Code Battle.

Пока стандартные олимпиадные задачи вы решаете один — это работа.

Когда появляется второй игрок — это соревнование. Атмосфера сразу меняется: добавляются адреналин, задор, азарт и нервозность, особенно когда соперник движется быстрее.

Во-первых, видно, как человек пишет код. Во-вторых, можно потырить у него идею. В-третьих, он может потырить вашу идею.

И во всём этом вишенкой на торте — образовательный элемент. Человек видит, как одна и та же задача решается на разных языках, как работают различные подходы и методы.

Часто бывает, когда вы вместе решили 80 % тестов, а потом смотрите, что пишет оппонент, и понимаете, что упустили этот крайний случай.

И начинается гонка!

Как всё начиналось

Сначала это была просто игра один на один с другом. Иногда приходит один человек и хочет с кем-то поиграть. Мы создали бота, который записывал прохождения других, с кем можно было соревноваться, как с виртуальным противником на гонке. Человек приходил, и мы ему воспроизводили одну из записей предыдущего прохождения, как будто он играет с реальным соперником. Все хотели победить одного из лютых senior’ов, который такие задачи просто щёлкал.

Потом мы добавили систему рейтинга и топ-10 игроков за неделю, месяц. Люди стали приходить и бороться за топ рейтинга. Стало понятно, что наша ниша — это не повторение codewars/leetcode со сложными задачами и алгоритмами, а развлечение, где нужны более лёгкие задачи.

Но с элементом соревнований.

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

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

Чтобы игра всегда была интересной, важно подбирать соперников по уровню. В итоге турниры автобалансируются так, что вы всегда играете с кем-то, кто кодит на вашем уровне. Стратегически это означает, что выгодно может быть проигрывать первые раунды «швейцарки», чтобы попадать на более слабых противников и легче вырывать у них победу, но на практике я ни разу не видел, чтобы так происходило.

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

Баттл вузов: как Яндекс использовал Code Battle

Яндекс давно использует Code Battle для различных активностей, но однажды пришёл с новым запросом: провести соревнование среди студентов в супермасштабном формате. Платформу пришлось прокачать, иначе она не выдержала бы таких нагрузок. Мы добавили новые фичи, настроили серверы под тысячи участников и сделали всё таким образом, чтобы ничего не сломалось в самый ответственный момент.

Так появился Баттл вузов — турнир, в котором схлестнулись 3 500 студентов из 211 вузов. В полуфинале осталось 500 человек из 39 университетов, а в финале, на главной сцене фестиваля Young Con, бились 20 лучших: студенты из МФТИ, ВШЭ, СПбГУ и РТУ МИРЭА. Поддерживать их приехали даже представители вузов.

image

Финал получился жарким. Сергей Бережной, директор по взаимодействию с разработчиками в Яндексе, вспоминает:

Когда смотришь чемпионат по какому-нибудь виду спорта, иногда кажется, что интригу специально закрутили ради зрелищности. Но тут всё было по-настоящему. МФТИ и ВШЭ шли ноздря в ноздрю, набрав одинаковое количество баллов. В итоге пришлось вручную пересчитывать время выполнения задач, и победителя определила разница в какие-то секунды. Это было очень мощно!

Задачи для финала придумали в Яндексе. Они становились всё сложнее от этапа к этапу, но оставались в блиц-формате. Тут было важно не только написать правильное решение, но и сделать это быстрее соперника.

Задача 1

В Мире Творцов с помощью считалочки выбирают нового ответственного за красоту во Вселенной. Задается две строки: считалка (текст из слов через пробелы) и упорядоченный список кандидатов. Ведущий показывает на первого кандидата, называет слово из считалки, а затем переходит к следующему участнику и следующему слову. На ком прозвучит последнее слово?

Пример: «To be or not to be», «John Mary Ann Kate» →➤ «Mary»

Задача 2

На галактическом базаре места для торговли пронумерованы от 1 до N. Свободные обозначены нулём, занятые — единицей. Рик ищет свободное место для лавки, максимально удалённое от ближайшего занятого. Если таких несколько, подойдёт с наименьшим номером.

Подходящее место точно есть — найдите его!

Пример: [1, 0, 1, 0, 0, 1, 0, 1] →➤ 2

Задача 3

Мана — важный ресурс Вселенной Яндекса. Переправляют её между Мирами, используя гибкие прямоугольные контейнеры. Они могут менять пропорции сторон, сохраняя площадь S, оставаясь прямоугольниками с целочисленными сторонами.

Сколько способов разместить один контейнер в шаттле размерами H×W? Все числа до 100.

Пример: 4, 2, 4 →➤ 5

Задача 4

Из глубин Вселенной Яндекса исходит поток космических сигналов. Длина потока до 100 сигналов, каждый сигнал кодируется латинской буквой. Ходят легенды, что там сокрыто некое пророчество в виде подстроки-палиндрома. Возможно, при передаче из космоса, один сигнал исказился и его нужно заменить.

Найдите максимальную длину пророчества-палиндрома.

Пример: «baaacbab» →➤ 6

Турнир оказался настолько крутым, что теперь это традиция. Уже в мае пройдет новый Баттл вузов. В этом году принять участие могут не только действующие студенты, но и выпускники вузов.

И ещё задачи

image

image

image

image

image

image

Получается, Code Battle — это соревнование по скоростному говнокодингу?

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

Наши самые частые задачи — одна-две минуты медианного времени на решение с ограничением в четыре-пять минут максимум по таймеру.

Есть совсем элементарные задачи вроде переворота строки, они скорее разминочные: вспомнить, где какая кнопка на клавиатуре. Дальше — посложнее: посчитать перестановки в массиве — это уже целых три строчки кода у олимпиадника. А дальше уже на подумать.

С тестами не жестим прямо совсем (например, в тестовых подборках нет целых чисел, выходящих за int разных языков), но и данные подбираем всё же не просто так. Где-то, где есть шансы быстро улететь в сложные алгоритмы, финальный тест обычно большой и показывает разницу по времени исполнения в пару десятков секунд в сравнении с оптимизированным кодом.

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

На время исполнения теста GUI блокируется, кодить во время исполнения нельзя.

Выполнение всех тестов, кроме последнего объёмного, чаще всего даёт 35 % от возможных очков вместо 100 % за полное решение.

Возвращаясь к вопросу про говнокод — сам подбор задач делает так, что приходится балансировать между тремя элегантными строчками и 20 страшными. И вот три элегантные обычно быстрее. Супернеоптимальные алгоритмы мы просто отсеиваем.

Тесты и условия специально не запутываем.

Откуда берутся задачи

Есть Хекслет — это школа программирования, коммерческая компания. Изначально турниры мы придумали внутри Хекслета, но потом вокруг игры образовалось отдельное сообщество.

Собственно, сообщество накидывает задачи и постепенно всё обновляет. Сами задачи, кстати, не должны зависеть от языка, в смысле не быть нерешаемыми на каком-то отдельном языке из-за его особенностей. С другой стороны, есть задачи, которые легче решать, переключив язык, если в коробке идёт какая-то готовая библиотека с тем же расстоянием Дамерау — Левенштейна, например.

Сейчас в базе — около 200 задач.

Можно закоммитить свою под лицензию для свободного использования, в конце — ссылка.

Задачи делятся на четыре уровня сложности:

  • Самые простые — на уровне сортировки массива. Однострочники для разминки — освоить интерфейс и шаблон.
  • Лёгкие — две-три строки, когда уже нужно сделать преобразование похитрее. Например, массив в массиве, в каждом надо найти среднее и посчитать среднее из них. Такой стандартной библиотечной функции нет, но сам алгоритм очень простой. Надо сориентироваться и сделать.
  • Средние — тут появляются рекурсия, регулярные выражения, набор математических знаний, построение вспомогательных массивов или мап для ускорения поиска. Нет сложных алгоритмов, но есть условия, над которыми надо немного подумать.
  • Тяжёлые — на реально подумать. Они могут быть двух типов: с непростыми условиями, например, преобразовать любое число в текст или римское число, либо связанные с динамическим программированием, графовыми алгоритмами и оптимизацией решения с учётом ограничений на время и память. Эти задачи требуют не только знаний, но и способности разбить сложную проблему на этапы и найти эффективное решение.

Задач на отладку чужого кода нет, все они типовые, входящая последовательность, числовой проверяемый ответ. Мы не подкладываем 10-гигабайтный массив в первом тесте посмотреть, уложитесь ли вы за 20 секунд, не берём ничего неочевидного для тестов, что не лезет в стандартные типы, почти не заморачиваемся на время исполнения (если только у вас не чудовищный говнокод или какой-то брутфорс вместо математики). Все задачи решаются на уровне «быстро придумал и вспомнил, быстро накодил» без 10 циклов оптимизации и рефакторинга.

Напоминаю, что это не касается коммерческих турниров: там заказчик может принести свои задачи. Там мы часто выставляем другие таймеры, не три–пять минут.

Реально ли люди переключают язык?

Да, и очень часто. Преимущество на стороне тех, кто знает несколько языков: под разные задачи можно выбрать подходящий. На том же турнире Яндекса у нас были участники, которые выбирали между Питоном и C++. Простые задачи быстрее писать на Питоне: синтаксис лаконичнее. Но со сложными, где алгоритмы важнее скорости, лучше идти в C++.

Есть ли готовый шаблон?

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

Про читерство

В классическом турнире с призами мы блокируем поле ввода и второй экран на копипаст. То есть если хотите тырить идеи — тырьте именно идеи второго игрока, а не сам код. Можно договориться на берегу про возможность гуглежа или консультаций с LLM.
Но тут так: хотите спросить у LLM — спросите. Но не просите написать код. Ну или перепечатывайте вручную. Понятно, что это можно обойти на онлайне, но не в зале с сотнями людей.

Про LLM — вопрос спорный: где-то на турнирах просто запрещали покидать окно GUI. Можно было бы усложнить, но тогда ушла бы главная радость очень быстрого решения. На внутренних мероприятиях это достаточно просто решается игрой на честность. На внешних в целом пока мы не видим злоупотребления LLM, но если дальше будут проблемы, то будем решать.

Мы смотрели записи игр олимпиадников, бравших «золото» ICPC. Вот это — просто демоны: они кодят, ещё не дочитав до конца описание. Просто за доли секунды понимают, про что задача, и дальше уже делают. GPT пока их не обгонит).

Адреналин в программировании

Вот один из первых участников очень хорошо рассказал:

У нас был общий чат. Сначала все были немножко в лёгком шоке. Блин, а как тут играть? Соперник тоже решает код! Я вообще не понимаю, что происходит! Сначала — немножко ступор и удивление, а потом — всё наоборот: блин, я уделал его! Я видел, как это происходило! На последних секундах я успел что-то решить! Ты не просто решаешь задачу, а у тебя есть три минуты и твой оппонент. Максимальный адреналиновый скачок. Потом — когда ты видишь там турнирную таблицу и положение своё и топов. Ты видишь, что у тебя — 100 очков, а у топов — 700–800–900. Или, наоборот, ты в топе и думаешь, что идёшь с кем-то ноздря в ноздрю. Выделяется дикое количество адреналина. Сложнее решать задачки. У кого-то потеют и трясутся руки. Люди, когда писали в чат, были все в таком восторге, как будто они пришли на скучный турнир, где тебе сейчас дадут сложные олимпиадные задачки и ты будешь сидеть, пыхтеть и так далее, а в итоге — задачки не очень сложные, и всё очень весело и быстро. Это как играть блиц в шахматы!

По желанию организаторов турнира мы можем в финале делать ещё и дополнительные усложнения — не в коде, а в способе взаимодействия. Например, включить громкую ритмичную музыку, забрать у всех мышки, включать экран каждые пять секунд на две секунды и так далее. Конкретно так не делали, но был опыт с тем, что дали двум участникам за одним компьютером две неполные клавиатуры: на одной не было 30 % кнопок, но эти кнопки были на другой. Зато на другой не было части кнопок, которые были на первой.

Как участвовать

Вот канал. Тут обсуждают турниры и ищут участников в команду.

А вот — как запустить.

Автор: toxicmt

Источник

Оставить комментарий