Три недели назад мы (дружная команда образовательного проекта Хекслет) опубликовали пост про наш новый проект — игру для программистов Codebattle. Напомню, идея игры очень простая: вам и сопернику дается задача, вы решаете ее на выбранном вами языке. Вы видите код соперника в реальном времени, результаты запуска тестов и можете общаться с ним и зрителями в чате. Кто первый решит задачу (удовлетворит тестам) — тот победил.
После публикации статьи у нас был веселый день. Легли под хабраэффектом и обнаружили несколько багов. Когда буря успокоилась, на арене снова закипела жизнь. В течение следующих двух недель мы решали три главные проблемы: производительность, борьба с читерством и возможность быстрого добавления новых языков. И решили их!
Встречайте — обновленный Codebattle! Вкратце:
- Хабраэффект нам не страшен (тьфу-тьфу-тьфу)
- Читерить больше не получится (нельзя подогнать решение под тесты)
- Добавлять языки стало проще (сейчас уже есть clojure, ruby, js, python, php, java, erlang)
Подробности под катом >
Почему лежали и как решили
Мы работали через поллинг, что генерировало тысячи запросов в минуту. Теперь все переписали через websockets. Еще нашелся баг в библиотеке nkdocker.
Читерство и языки
В предыдущей версии была такая система:
- Пишем задание и тесты на Clojure
- Транслируем на целевые языки нашей библиотекой multicode.
- Показываем сгенерированные тесты игроку
Естественно, нашлись люди, которые просто подгоняли код под тесты не решая саму задачу. К тому же, такая схема усложняла добавление новых языков.
В обновленной версии другая схема: мы просто работаем через стандартные потоки ввода/вывода stdin/stdout, и не привязываемся к конкретному языку. Теперь мы генерируем тесты при проверке и не показываем их игроку. Система стала намного проще: мы просто подаем в вашу программу сгенерированные данные и смотрим на stdout. Это же позволило упростить добавление новых языков, мы успели добавить Clojure, Java и Erlang.
Из мелочей: добавили кучку новых заданий, обновили описание во всех заданиях, обновили расширение для Хрома.
Как добавить новое задание
Хотите добавить новое задание в базу и прокачаться в Clojure? ;-) В нашем репозитории с задачами есть подробное README и наглядные примеры.
В нашем Слак-чате есть специальный канал #codebattle, где можно обсудить игры, проблемы и идеи.
Комментарии (58)
devpony
27.10.2015 13:53+1Добавьте haskell. Кстати, кому жалко тратить по 10$ в месяц хочу посоветовать stepic.org.
xytop
27.10.2015 13:56У вас тесты на некоторых задачах неверные. Из-за них верные решения не проходят. Нужно добавить кнопку, что-то типа «Пожаловаться».
Например:
У меня ответ [-1, -1]
А ваш assert ожидает [1, 1]
Хотя и то и то выдают одинаковое произведениеtoxicmt
27.10.2015 13:57Ага спасибо, посмотрим.
Core2Duo
27.10.2015 20:32Задача key_for_min_value тоже видимо не слишком правильная.
Given a hash map, return the key of the element with the smallest value.
AssertionError: 'religion' != 'surprise'
— religion
+ surprise
: Arguments was: [{'surprise': 1, 'paper': 5, 'religion': 1, 'food': 2}]
Два элемента с одинаковым минимальным значением, один почему-то «неправильный»
xytop
27.10.2015 14:27+2У вас в задачах есть ссылка на github, и там выложено решение на Clojure внизу… не дает ли это преимущество тем кто выбирает Clojure
и затем копипастит решение?toxicmt
27.10.2015 14:38+1Мы таким образом хотим познакомить программистов с кложей. Реально на ней играет пока очень мало игроков.
mihmig
27.10.2015 17:15Предлагаю сделать так:
Решил первым: 3 очка
Решил вторым: 2 очка
Решил позже таймаута: 1 очко.
(очки накапливаются, рейтинги там и все дела, но потихоньку тают, дабы лидерство поддерживать)
mihmig
27.10.2015 17:23Пользователи частенько «отваливаются». Может добавить возможность «подхватить упавшее знамя»?
xytop
27.10.2015 21:27+2> Хабраэффект нам не страшен (тьфу-тьфу-тьфу)
Вроде как баттл лежит…toxicmt
27.10.2015 22:14Не лежит, но заметно лагал. Щас все снова в норме.
xytop
27.10.2015 22:35нет, не в норме.. Хотя возможно это относится только к ruby vm…
toxicmt
27.10.2015 22:42Да(, исполнение кода это таки не странички грузить.
xytop
27.10.2015 23:07Ну вот я щас сижу с человеком. У него PHP, у меня Ruby. У него PHPUnit работает, а у меня сплошные таймауты.
К слову о нагрузке… тот же codingame.com держит тысячи пользователей онлайн без проблем… наверное у вас архитектурно что-то неправильно сделано.toxicmt
27.10.2015 23:16+1Круто вы конечно сравниваете кто сколько держит. У них это весь сервис под которым целая инфраструктура, у нас виртуалка с одним ядром.
hedgehog
27.10.2015 23:18универсальная решалка для пыха:
function solution(){ $f = function($json){return json_decode($json, true);}; $data = array_map($f, file('data.jsons')); foreach($data as $row){ if ($row['arguments'] == func_get_args()){ return $row['expected']; } } }
Shchvova
28.10.2015 02:35Я попробовал было. Задачка «транспонируйте матрицу». Я пишу себе на питоне. Потом замечаю что опонент на руби написал что-то типа m.transpose() за первые 3 секунды. Ну ок. Я вообще не понимаю зачем эти все соривнования, опоненты, потому больше не играл.
funca
28.10.2015 11:42+2Инструмент надо выбирать под задачу. А на питоне меньше букв :)
( stackoverflow.com/a/4937526 )zip(*m)
tmnhy
28.10.2015 11:26+1Несколько пожеланий:
— мало задачек, часто повторяются, для одного ЯП — на вечер развлечение, потом неинтересно;
— как-то надо учитывать фичи ЯП, например для «separate_with_comma» на питоне решение «return '{0:,}'.format(arg)», задание, думаю, подразумевает более низкоуровневое решение;
— и да, как писали выше, есть задачки с несколькими возможными решениями, и как я понимаю верным считается первое, а у питона, так как нет порядка в ключах словаря, может быть ответ удовлетворяющий условию, т.е. верный, но не совпадающий с тестовым и приходится тыкать на «проверить» пока тест подходящий не сработает.Core2Duo
28.10.2015 12:51О, спасибо за крутое решение separate_with_comma. Я как-то так извращался:
def solution(s): s = s[::-1] p = [s[i:(i + 3)] for i in range(0, len(s), 3)] s = ','.join(p) return s[::-1]
tmnhy
28.10.2015 17:56Там таких задачек много, есть что на php в одну строку.
Опять же на питоне подсчет количества вхождений элементов массива сводится к банальному:
def solution(arg): from collections import Counter return Counter(arg)
Это несколько нечестно.M_Muzafarov
28.10.2015 18:40+1def solution(a): return {k: a.count(k) for k in a}
Даже меньше на строчку. и вполне честно.
M_Muzafarov
28.10.2015 12:23Непонятно, когда отправил задачку на проверку — сработала кнопка или нет. Надо какую-то обратную связь, чтоб не слать по несколько раз. Болеетого, если отправил, потом дописал, потом снова отправил, потом снова дописал — если приходит ответ с первой отправки — может откатить код на несколько шагов назад. Это неприятно.
Потом в какой-то момент после нескольких infinite loop/slow script — сервер вообще перестал что либо принимать. Потом в консоли браузера стало появляться много ошибок о дублирующемся ключе. Обновил вкладку, не с первого раза пустило, задачу на проверкуне принимало, потом вообще написали мне, что игра не существует.
Safari, Mac os x 10.11
А в целом идея интересная, если не превратится в очередной codeforces. пока задачки не академические — дух соперничества подстегивает играть))
WingedBoar
28.10.2015 15:47Сделайте, пожалуйста, чтобы окна с кодом изменяли размер, но всегда остовались бок о бок, а не выпихивали друг-друга. В данный момент окошки всегда по ширине текста и зачастую выпихивают друг-друга вниз экрана (на Огнелисе, на других не знаю).
Ещё было бы хорошо, если бы вы учитывали не только скорость написания, но и производительность написанной программы. Не знаю, какой-нибудь лидерборд на самый быстрый алгоритм или что-то подобное, подумайте. Написать по-другому — это по-крайней мере хоть какой-то стимул проходить уже пройденное задание снова.WingedBoar
28.10.2015 16:01+ Сделайте ещё какое-нибудь пенальти за брошенные игры. Типа 10 минут в рид-онли не можешь создать или присоединиться к игре.
ketrin7
28.10.2015 21:28+1Спасибо за python, php. Особенно за добавление php, т.к. для python я находила игры. Для php встречаю в первый раз.
hedgehog
Зря спрятали тесты совсем. Иногда они помогают лучше понять задание. Неплохо бы пару тестов показывать, но при проверке задания во внимание их не принимать.
freetonik
Мы показываем один пример из теста рядом с описанием задания:
ev42
Пока плохо спрятали, к вечеру обещают закрыть серьёзнее =)
mekegi
как то вот так
1. read(x)
2. sendToMyOwnServerViaInternet(x)
3.…
4. profit
FallDi
вы про это?)
FallDi
Проверил на большинстве задач, уникальное решение для php примерно такое =)
toxicmt
Закончилась халява)