company_banner

Разбор игры от Одноклассников на Joker 2018


    Всем привет! Несколько дней назад мы выкладывали пост про задачки, которые давали на конференции Joker 2018. Но это еще не всё! В этом году специально для Joker мы сделали целую игру с не менее интересными задачками по Java (и не только), про которую и расскажем сегодня.

    Подобные игры на конференциях мы делали и раньше, например, на прошлом JPoint этой весной. Чтобы сделать игру, нам надо было: 1) придумать игровую механику, 2) придумать вопросы, 3) всё это реализовать.

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


    Надо, отвечая на вопросы, постараться провести Дюка (в левом верхнем углу) в одну из дверей в других углах. На один сеанс игры отводится 3 минуты. Чтобы открыть клетку, нужно правильно ответить на вопрос, который выбирается каждый раз случайно в соответствии с категорией. За правильные ответы начисляются очки, за неправильные — штраф, клетка с вопросом блокируется и её придется обходить. В результате путь может получиться достаточно длинным или вовсе заблокироваться. Игроки могут выбрать разные стратегии: как можно быстрее дойти до выхода и получить дополнительный бонус; ответить на как можно больше вопросов за отведенное время; пройти более длинный путь по простым вопросам, либо напрямую по более сложным и получить больше очков.


    С механикой разобрались, теперь надо придумать вопросы. Они должны быть трёх категорий сложности, от самых простых до хардкора. Формулировки вопросов должны быть предельно короткими, читать простыни текста не будет времени. Варианты ответов должны быть такими, чтобы не давать слишком много подсказок. Ну и сами вопросы должны быть интересными и практическими. При этом их должно было быть достаточно много, чтобы они не слишком быстро повторялись. В результате совместных усилий удалось придумать 130 вопросов про структуры данных, алгоритмы, «java-пазлеры», хардкорные вопросы по внутренностям JVM, и даже несколько вопросов про Docker.


    Есть проблема: игра выводится на большой экран, и те, кто стоят рядом, за несколько игр запомнят большую часть ответов. Сначала казалось, что нам понадобятся сотни вопросов, чтобы свести возможность запоминания к минимуму. Но, поразмыслив, поняли, что есть варианты попроще. Для начала, убрали управление мышкой, оставив только клавиатуру. Теперь стоящие рядом видят вопрос, но не видят, какой ответ выбрал игрок. Добавили перемешивание вариантов ответов, усложнив запоминание. Для каждого вопроса добавили несколько похожих, но немного отличающихся формулировкой. Конечно, запомнить ответы всё равно можно, и это было видно по заметно улучшившимся результатам на второй день конференции. Многие пользователи проводили за игрой десятки минут, пытаясь перебить рекорд других. Но тут всё как в жизни — усердие вознаграждается.

    С возникновения идеи до придумывания вопросов и реализации прошло две недели. Разумеется, всё на Java. Использовался Spring boot и Gradle. WEB-интерфейс сделан на Angular. В качестве хранилища использована встроенная база данных H2, которая «из коробки» поставляется с web-интерфейсом, что очень удобно. Конфигурация стенда — два MacBook, картинка с которых дублируется на двух телевизорах. Для удобства настройки приложение удаленно развернули в нашем облаке (https://habr.com/company/odnoklassniki/blog/346868/).


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

    Всего в игру за два дня сыграли 811 раз. Статистика ответов в зависимости от сложности вопроса:

    DIFFICULTY
    COUNT
    CORRECT_PERCENT
    1
    3552
    61
    2
    2031
    49
    3
    912
    46

    До каких клеток поля и как часто доходили игроки:


    Процент правильных ответов на каждой клетке поля:


    Но самое интересное — это, конечно, статистика вопросов. Оценить их сложность с учётом распределения по категориям оказалось не так просто, оценка всегда субъективна, и простой вопрос для одного пользователя оказывается сложным для другого. Олег предлагал выкинуть один из вопросов со словами «это даже уборщицы знают», но оказалось, что на многие «простые» вопросы правильные ответы знают далеко не все уборщицы, да и программисты тоже. Предлагаем вам некоторые вопросы из нашей игры — лидеры по неверным ответам, попробуйте оценить свои силы!

    1. Результат вызова этого кода?

      System.out.println(1/0d)

      • Выбросит ArithmeticException
      • Напечатает «Infinity»
      • Напечатает «NaN»
      • Напечатает 0

      Ответ
      Это кажется очень простым вопросом. Тут простая арифметика, какой может быть подвох, почему же правильный ответ дали только 28 % игроков? Деление целого числа на 0 приводит в Java к ArithmeticException. Но целые ли тут числа? Посмотрим внимательно. Что там за «d» после 0? Эта буква означает, что перед нами не целочисленная константа 0, а значение типа double. И получается, что выражение идентично 1.0/0.0. А это уже деление с плавающей точкой на ноль, результат которого равен Double.POSITIVE_INFINITY. Значит, правильный ответ — «b».
    2. Результат вызова этого кода?

      System.out.println(
          Long.MAX_VALUE==(long)Float.MAX_VALUE
      );
      

      • напечатает true
      • напечатает false
      • выбросит ArithmeticException

      Ответ
      Для начала, нужно понять, что больше: Float.MAX_VALUE или Long.MAX_VALUE? Хотя float имеет меньший диапазон значений, чем double, всё равно его максимальное значение примерно на 20 порядков выходит за диапазон возможных значений long. Но как в данном случае сработает приведение типов? Можно гадать, но лучше запустить код. А еще лучше — открыть Java Language Specification, раздел про Narrowing Primitive Conversion, и прочитать, что если значение числа с плавающей точкой слишком велико и выходит за диапазон доступных значений целочисленного типа, то результат конверсии равен максимальному значению, которое можно представить с помощью целочисленного типа. Т.е. результат конверсии равен Long.MAX_VALUE. Правильный ответ дали 27 % отвечавших.
    3. Какой класс не Comparable?

      • java.lang.String
      • java.util.TreeSet
      • java.io.File
      • java.lang.Enum

      Ответ
      Этот, казалось бы, простой вопрос поставил в тупик многих, точнее — 76 % отвечавших. Догадайтесь сами, какой из ответов тут правильный и какой ответ был самым популярным — его выбрали 61 % игроков.
    4. Чему идентичен код?

      Object o = Math.min(-1, Double.MIN_VALUE)

      • Object o = -1
      • Object o = Double.MIN_VALUE
      • Object o = -1.0

      Ответ
      Минимальное значение double уж точно меньше -1, что тут опять может быть не так? Разумеется, всё не так просто, иначе мы не спрашивали бы. Оказывается, Double.MIN_VALUE содержит не совсем то, что ожидается, а именно «constant holding the smallest positive nonzero value», согласно документации. Правильнее его было бы назвать Double.MIN_POSITIVE_VALUE. Double опять обвел вокруг пальца! Правильный ответ: Object o = -1.0, и так ответили всего 22 % игроков.
    5. Какая строка получится в результате вызова этого кода?

      Long.toHexString(0x1_0000_0000L + 0xcafe_babe)

      • 1cafebabe
      • cafebabe
      • ffffffffcafebabe

      Ответ
      Если вы выбрали второй ответ, то вы среди 22 % ответивших правильно. Этот вопрос взят из книги «Java Puzzlers: Traps, Pitfalls, and Corner Cases» за авторством Joshua Bloch и Neal Gafter. Если ответили неправильно, не расстраивайтесь, и бегом читать эту книгу!
    6. В JDK 8 появилась поддержка аннотаций у параметров методов. Возможно ли добавить аннотацию к параметру метода this?

      • Нельзя
      • Возможно, но только в байткоде
      • Возможно, определив this явно первым параметром метода

      Ответ
      Когда в JDK 8 добавляли возможность ставить аннотации на параметры методов, параметр this не стали обделять. Именно для этой цели this теперь можно явно указывать в сигнатурах методов:

      class Foo {
          public void test(@Annotated Foo this) {}
      }

      Хотя можно спорить о ее практической пользе, теперь это фича языка. До правильного ответа догадалось 32 % игроков.
    7. В JDK 8 параметр concurrencyLevel в конструкторе ConcurrentHashMap влияет на:

      • Доступный параллелизм при чтении/записи
      • Начальный размер таблицы
      • На оба параметра

      Ответ
      Если вы выбрали вариант 2, то вы среди 15 %, кто дал правильный ответ на этот самый сложный вопрос игры. Всё дело в том, что в JDK 8 отказались от сегментов в ConcurrentHashMap, поэтому concurrencyLevel потерял свой прежний смысл. Он влияет только на начальный размер таблицы, да и то лишь ограничивает снизу значение initialCapacity.

    По многочисленным просьбам мы выложили игру на наш сайт, где вы можете сыграть прямо сейчас!
    • +30
    • 4,7k
    • 6

    Одноклассники

    252,00

    Делимся экспертизой

    Поделиться публикацией
    Комментарии 6
      0

      Интересно всегда было узнать % прошедших задачу к пришедшим после этого работать в компанию.

        0
        Добавьте статистику по другим участникам игры, чтобы было с чем себя сравнивать.
          +1
          Добавили. Теперь показывается, какой % других участников сыграли хуже.
            0
            Спасибо!
            Правда не совсем понятно, как вычисляется.
            image
            Неужели все игроки насколько слабы?
              0
              Считается так: суммируются очки за все верные ответы в соответствие с их ценой в зависимости от сложности (1, 2 или 5 очков) и вычитаются очки за все неверные ответы. Большинство игроков действительно уходят в минус, но это, разумеется, не показатель знаний Java. Результаты сильно улучшаются при второй и последующих попытках. У игры была цель не столько оценивать способности, сколько развлечь участников, дать размять мозги и освежить какие-то знания.
          0
          Как всегда, один из лучших стендов на Joker. Так держать!

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

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