Обновленный Codebattle: игра для программистов

    Привет, Хабр!



    Три недели назад мы (дружная команда образовательного проекта Хекслет) опубликовали пост про наш новый проект — игру для программистов Codebattle. Напомню, идея игры очень простая: вам и сопернику дается задача, вы решаете ее на выбранном вами языке. Вы видите код соперника в реальном времени, результаты запуска тестов и можете общаться с ним и зрителями в чате. Кто первый решит задачу (удовлетворит тестам) — тот победил.

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

    Встречайте — обновленный Codebattle! Вкратце:

    1. Хабраэффект нам не страшен (тьфу-тьфу-тьфу)
    2. Читерить больше не получится (нельзя подогнать решение под тесты)
    3. Добавлять языки стало проще (сейчас уже есть clojure, ruby, js, python, php, java, erlang)

    Подробности под катом →

    Почему лежали и как решили


    Мы работали через поллинг, что генерировало тысячи запросов в минуту. Теперь все переписали через websockets. Еще нашелся баг в библиотеке nkdocker.

    Читерство и языки


    В предыдущей версии была такая система:
    1. Пишем задание и тесты на Clojure
    2. Транслируем на целевые языки нашей библиотекой multicode.
    3. Показываем сгенерированные тесты игроку

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

    В обновленной версии другая схема: мы просто работаем через стандартные потоки ввода/вывода stdin/stdout, и не привязываемся к конкретному языку. Теперь мы генерируем тесты при проверке и не показываем их игроку. Система стала намного проще: мы просто подаем в вашу программу сгенерированные данные и смотрим на stdout. Это же позволило упростить добавление новых языков, мы успели добавить Clojure, Java и Erlang.

    Из мелочей: добавили кучку новых заданий, обновили описание во всех заданиях, обновили расширение для Хрома.

    Как добавить новое задание

    Хотите добавить новое задание в базу и прокачаться в Clojure? ;-) В нашем репозитории с задачами есть подробное README и наглядные примеры.

    В нашем Слак-чате есть специальный канал #codebattle, где можно обсудить игры, проблемы и идеи.
    Метки:
    Hexlet 54,09
    Практические уроки по программированию
    Поделиться публикацией
    Похожие публикации
    Комментарии 59
    • +1
      Зря спрятали тесты совсем. Иногда они помогают лучше понять задание. Неплохо бы пару тестов показывать, но при проверке задания во внимание их не принимать.
      • +4
        Мы показываем один пример из теста рядом с описанием задания:

        • 0
          Пока плохо спрятали, к вечеру обещают закрыть серьёзнее =)
          • –1
            как то вот так

            1. read(x)
            2. sendToMyOwnServerViaInternet(x)
            3.…
            4. profit

            • +2
              вы про это?)
              image
              • +3
                Проверил на большинстве задач, уникальное решение для php примерно такое =)
                <?php
                
                function solution($a) {
                    $tests = file_get_contents('data.jsons');
                    echo $tests;
                    $tests = explode("\n", $tests);
                    foreach ($tests as $test) {
                        $test = json_decode($test, true);
                        $arg = $test['arguments'];
                        if (is_array($test['arguments'])) {
                        	$arg = $test['arguments'][0];
                        }
                        if ($arg == $a) {
                	    	return $test['expected'];
                        }
                    }
                }
                
                • 0
                  Закончилась халява)
          • +2
            Добавьте нотификации перед началом игры
            Ждешь игру, перключаешься на другую вкладку, возвращаешься — уже проиграл
          • +3
            Было бы неплохо, чтобы работал ES6 синтаксис в JavaScript — он более короткий и если кодить на время, то это важно :)
            • 0
              Он частично работает, там node 4.2.1
            • +1
              Добавьте haskell. Кстати, кому жалко тратить по 10$ в месяц хочу посоветовать stepic.org.
              • 0
                Хаскель в процессе. У степика нет такой практики как у нас ;)
              • 0
                У вас тесты на некоторых задачах неверные. Из-за них верные решения не проходят. Нужно добавить кнопку, что-то типа «Пожаловаться».

                Например:

                У меня ответ [-1, -1]
                А ваш assert ожидает [1, 1]
                Хотя и то и то выдают одинаковое произведение
                • 0
                  Ага спасибо, посмотрим.
                  • 0
                    или у меня ответ [7, 6], а ваш assert ждет [6, 7]
                    • 0
                      Задача 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}]

                      Два элемента с одинаковым минимальным значением, один почему-то «неправильный»
                      • 0
                        Те же проблема со списком анаграм.
                    • +2
                      У вас в задачах есть ссылка на github, и там выложено решение на Clojure внизу… не дает ли это преимущество тем кто выбирает Clojure и затем копипастит решение?
                      • +1
                        Мы таким образом хотим познакомить программистов с кложей. Реально на ней играет пока очень мало игроков.
                      • 0
                        Bugreport: en.hexlet.io/users/new — last surname
                        • 0
                          Поправили, спасибо, в следующем деплое обновится на сайте.
                        • 0
                          Предлагаю сделать так:
                          Решил первым: 3 очка
                          Решил вторым: 2 очка
                          Решил позже таймаута: 1 очко.
                          (очки накапливаются, рейтинги там и все дела, но потихоньку тают, дабы лидерство поддерживать)
                          • +1
                            Открытые игры быстро «дёргаются», красивее было бы сделать fadein(out)
                          • 0
                            Пользователи частенько «отваливаются». Может добавить возможность «подхватить упавшее знамя»?
                            • 0
                              Имхо, нужно давать возможность проверять свое решение даже после поражения (как бы, вне игры).
                              Даже если я проиграл, я привык доходить до конца. И, интересно, справился ли я в итоге.
                              • 0
                                Так и работает же. Всегда можно доиграть.
                                • 0
                                  Не срабатывает кнопка «проверить», пишет, что игра закончена уже
                                  • 0
                                    Вы уверены что под этой надписью не появляется новый вывод? Просто эта надпись всегда сверху висит. Ну и нет там ограничений в коде да и по играм видно что оба соперника доигрывают.
                              • +2
                                > Хабраэффект нам не страшен (тьфу-тьфу-тьфу)
                                Вроде как баттл лежит
                                • 0
                                  Не лежит, но заметно лагал. Щас все снова в норме.
                                  • 0
                                    нет, не в норме.. Хотя возможно это относится только к ruby vm…
                                    • 0
                                      Да(, исполнение кода это таки не странички грузить.
                                      • 0
                                        Ну вот я щас сижу с человеком. У него PHP, у меня Ruby. У него PHPUnit работает, а у меня сплошные таймауты.
                                        К слову о нагрузке… тот же codingame.com держит тысячи пользователей онлайн без проблем… наверное у вас архитектурно что-то неправильно сделано.
                                        • +1
                                          Круто вы конечно сравниваете кто сколько держит. У них это весь сервис под которым целая инфраструктура, у нас виртуалка с одним ядром.
                                • +1
                                  А нормально так, парень скопипастил решение откуда-то за 10 секунд и был таков…
                                  • 0
                                    Тоже самое только что было. Сейчас думаю покодю — опа и вы проиграли! :)
                                  • 0
                                    универсальная решалка для пыха:
                                    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'];
                                                
                                            }
                                        }
                                    }
                                    
                                    • 0
                                      хм, выше было уже оказывается
                                      • 0
                                        Все, нету больше чтений data.json
                                    • +1
                                      build_hash_with_default на пхп решается одной array_fill_keys
                                      • 0
                                        Эта задача много где решается в одну строку. На питоне:

                                        return {k:d for k in a}
                                        

                                        (d — default, a — array)
                                      • 0
                                        Я попробовал было. Задачка «транспонируйте матрицу». Я пишу себе на питоне. Потом замечаю что опонент на руби написал что-то типа m.transpose() за первые 3 секунды. Ну ок. Я вообще не понимаю зачем эти все соривнования, опоненты, потому больше не играл.
                                        • +2
                                          Инструмент надо выбирать под задачу. А на питоне меньше букв :)
                                          zip(*m)
                                          
                                          ( stackoverflow.com/a/4937526 )
                                        • 0
                                          Жаль что нет ни C++ ни C#.
                                          Интересно, и дальше не будет?
                                          • +1
                                            Несколько пожеланий:
                                            — мало задачек, часто повторяются, для одного ЯП — на вечер развлечение, потом неинтересно;
                                            — как-то надо учитывать фичи ЯП, например для «separate_with_comma» на питоне решение «return '{0:,}'.format(arg)», задание, думаю, подразумевает более низкоуровневое решение;
                                            — и да, как писали выше, есть задачки с несколькими возможными решениями, и как я понимаю верным считается первое, а у питона, так как нет порядка в ключах словаря, может быть ответ удовлетворяющий условию, т.е. верный, но не совпадающий с тестовым и приходится тыкать на «проверить» пока тест подходящий не сработает.
                                            • 0
                                              О, спасибо за крутое решение 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]
                                              
                                              • 0
                                                Там таких задачек много, есть что на php в одну строку.

                                                Опять же на питоне подсчет количества вхождений элементов массива сводится к банальному:
                                                def solution(arg):
                                                  from collections import Counter
                                                  return Counter(arg)
                                                


                                                Это несколько нечестно.
                                                • +1
                                                  def solution(a):
                                                    return {k: a.count(k) for k in a}
                                                  

                                                  Даже меньше на строчку. и вполне честно.
                                              • +2
                                                Задач будет больше. Их решают с такой скоростью что мы добавлять не успеваем)
                                                • 0
                                                  Задачки новые сть — это хорошо. А вот «Timeout error has occurred» замучил сосвсем. Побеждает не тот, кто первый, а кому повезло что тесты отработали.
                                              • 0
                                                Непонятно, когда отправил задачку на проверку — сработала кнопка или нет. Надо какую-то обратную связь, чтоб не слать по несколько раз. Болеетого, если отправил, потом дописал, потом снова отправил, потом снова дописал — если приходит ответ с первой отправки — может откатить код на несколько шагов назад. Это неприятно.

                                                Потом в какой-то момент после нескольких infinite loop/slow script — сервер вообще перестал что либо принимать. Потом в консоли браузера стало появляться много ошибок о дублирующемся ключе. Обновил вкладку, не с первого раза пустило, задачу на проверкуне принимало, потом вообще написали мне, что игра не существует.

                                                Safari, Mac os x 10.11

                                                А в целом идея интересная, если не превратится в очередной codeforces. пока задачки не академические — дух соперничества подстегивает играть))
                                                • 0
                                                  Сделайте, пожалуйста, чтобы окна с кодом изменяли размер, но всегда остовались бок о бок, а не выпихивали друг-друга. В данный момент окошки всегда по ширине текста и зачастую выпихивают друг-друга вниз экрана (на Огнелисе, на других не знаю).

                                                  Ещё было бы хорошо, если бы вы учитывали не только скорость написания, но и производительность написанной программы. Не знаю, какой-нибудь лидерборд на самый быстрый алгоритм или что-то подобное, подумайте. Написать по-другому — это по-крайней мере хоть какой-то стимул проходить уже пройденное задание снова.
                                                  • 0
                                                    + Сделайте ещё какое-нибудь пенальти за брошенные игры. Типа 10 минут в рид-онли не можешь создать или присоединиться к игре.
                                                  • +1
                                                    Спасибо за python, php. Особенно за добавление php, т.к. для python я находила игры. Для php встречаю в первый раз.

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

                                                    Самое читаемое