Обновленный 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

    65,00

    Практические уроки по программированию

    Поделиться публикацией
    Комментарии 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
            Добавьте нотификации перед началом игры
            Ждешь игру, перключаешься на другую вкладку, возвращаешься — уже проиграл
              +2
              Звуковую?
                +5
                + можно мигающую фавиконку
                  0
                  или alert
                  0
                  Да
                +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
                                        Не срабатывает кнопка «проверить», пишет, что игра закончена уже
                                          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 встречаю в первый раз.

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

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