- PVSM.RU - https://www.pvsm.ru -

Всем привет! Несколько дней назад мы выкладывали пост [1] про задачки, которые давали на конференции 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/ [2]).

Мы давно выучили: ни одна фича не должна разрабатываться без сбора статистики. Разумеется, и к игре мы прикрутили детальную статистику, которой можем поделиться.
Всего в игру за два дня сыграли 811 раз. Статистика ответов в зависимости от сложности вопроса:
| DIFFICULTY | COUNT | CORRECT_PERCENT |
| 1 | 3552 | 61 |
| 2 | 2031 | 49 |
| 3 | 912 | 46 |
До каких клеток поля и как часто доходили игроки:

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

Но самое интересное — это, конечно, статистика вопросов. Оценить их сложность с учётом распределения по категориям оказалось не так просто, оценка всегда субъективна, и простой вопрос для одного пользователя оказывается сложным для другого. Олег [3] предлагал выкинуть один из вопросов со словами «это даже уборщицы знают», но оказалось, что на многие «простые» вопросы правильные ответы знают далеко не все уборщицы, да и программисты тоже. Предлагаем вам некоторые вопросы из нашей игры — лидеры по неверным ответам, попробуйте оценить свои силы!
System.out.println(1/0d)
ArithmeticException. Но целые ли тут числа? Посмотрим внимательно. Что там за «d» после 0? Эта буква означает, что перед нами не целочисленная константа 0, а значение типа double. И получается, что выражение идентично 1.0/0.0. А это уже деление с плавающей точкой на ноль, результат которого равен Double.POSITIVE_INFINITY. Значит, правильный ответ — «b».
System.out.println(
Long.MAX_VALUE==(long)Float.MAX_VALUE
);
Float.MAX_VALUE или Long.MAX_VALUE? Хотя float имеет меньший диапазон значений, чем double, всё равно его максимальное значение примерно на 20 порядков выходит за диапазон возможных значений long. Но как в данном случае сработает приведение типов? Можно гадать, но лучше запустить код. А еще лучше — открыть Java Language Specification, раздел про Narrowing Primitive Conversion, и прочитать, что если значение числа с плавающей точкой слишком велико и выходит за диапазон доступных значений целочисленного типа, то результат конверсии равен максимальному значению, которое можно представить с помощью целочисленного типа. Т.е. результат конверсии равен Long.MAX_VALUE. Правильный ответ дали 27 % отвечавших.Comparable?
Object o = Math.min(-1, Double.MIN_VALUE)
double уж точно меньше -1, что тут опять может быть не так? Разумеется, всё не так просто, иначе мы не спрашивали бы. Оказывается, Double.MIN_VALUE содержит не совсем то, что ожидается, а именно «constant holding the smallest positive nonzero value», согласно документации. Правильнее его было бы назвать Double.MIN_POSITIVE_VALUE. Double опять обвел вокруг пальца! Правильный ответ: Object o = -1.0, и так ответили всего 22 % игроков.
Long.toHexString(0x1_0000_0000L + 0xcafe_babe)
this?
this явно первым параметром методаthis не стали обделять. Именно для этой цели this теперь можно явно указывать в сигнатурах методов:
class Foo {
public void test(@Annotated Foo this) {}
}
Хотя можно спорить о ее практической пользе, теперь это фича языка. До правильного ответа догадалось 32 % игроков.
concurrencyLevel в конструкторе ConcurrentHashMap влияет на:
ConcurrentHashMap, поэтому concurrencyLevel потерял свой прежний смысл. Он влияет только на начальный размер таблицы, да и то лишь ограничивает снизу значение initialCapacity.
По многочисленным просьбам мы выложили игру на наш сайт, где вы можете сыграть прямо сейчас [4]!
Автор: privatelv
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/java/297349
Ссылки в тексте:
[1] выкладывали пост: https://habr.com/company/odnoklassniki/blog/427337
[2] https://habr.com/company/odnoklassniki/blog/346868/: https://habr.com/company/odnoklassniki/blog/346868/
[3] Олег: https://habr.com/users/m0nstermind/
[4] сыграть прямо сейчас: https://javagame.odkl.ru/
[5] Источник: https://habr.com/post/427735/?utm_campaign=427735
Нажмите здесь для печати.