Bonjour à tous! Il y a quelques jours, nous avons
publié un article sur les puzzles qui ont été donnés lors de la conférence Joker 2018. Mais ce n'est pas tout! Cette année, spécialement pour Joker, nous avons fait un jeu complet avec des tâches Java non moins intéressantes (et pas seulement), dont nous parlerons aujourd'hui.
Nous avons fait des jeux similaires lors de conférences avant, par exemple, au dernier JPoint ce printemps. Pour créer un jeu, nous devions: 1) proposer des mécanismes de jeu, 2) proposer des questions, 3) réaliser tout cela.
La mécanique du jeu doit être très simple, intuitive, mais en même temps pas trop banale, afin de ne pas priver d'excitation. À la suite de longues discussions, nous sommes arrivés au jeu suivant:

Lorsque nous répondons aux questions, nous devons essayer de conduire Duke (dans le coin supérieur gauche) dans l'une des portes des autres coins. Pour une session du jeu, 3 minutes sont allouées. Pour ouvrir la cellule, vous devez répondre correctement à la question, qui est sélectionnée à chaque fois au hasard en fonction de la catégorie. Des points sont attribués pour les réponses correctes, une pénalité pour les réponses incorrectes, la cellule avec la question est bloquée et elle devra être contournée. En conséquence, le chemin peut s'avérer être assez long, voire bloqué. Les joueurs peuvent choisir différentes stratégies: arriver à la sortie dès que possible et obtenir un bonus supplémentaire; répondre à autant de questions que possible dans le temps imparti; aller loin sur des questions simples, ou directement sur des questions plus complexes et obtenir plus de points.

Nous avons traité de la mécanique, maintenant nous devons trouver des questions. Ils doivent être de trois catégories de complexité, du plus simple au plus hardcore. Le libellé des questions doit être extrêmement court, nous n'aurons pas le temps de lire les feuilles du texte. Les choix de réponse doivent être tels qu'ils ne donnent pas trop d'indices. Eh bien, les questions elles-mêmes devraient être intéressantes et pratiques. De plus, il aurait dû y en avoir beaucoup pour qu'ils ne se répètent pas trop vite. Grâce à des efforts conjoints, nous avons réussi à trouver 130 questions sur les structures de données, les algorithmes, le "puzzle java", des questions inconditionnelles sur les composants internes de la JVM et même quelques questions sur Docker.

Il y a un problème: le jeu est affiché sur grand écran, et ceux qui se tiennent à proximité se souviendront de la plupart des réponses pour plusieurs jeux. Au début, il semblait que nous aurions besoin de centaines de questions pour minimiser la possibilité de mémorisation. Mais, après réflexion, ils ont réalisé qu'il existe des options plus simples. Pour commencer, supprimé le contrôle de la souris, ne laissant que le clavier. Maintenant, ceux qui se trouvent à proximité voient la question, mais ne voient pas quelle réponse le joueur a choisie. Ajout d'un mélange d'options de réponse, compliquant la mémorisation. Pour chaque question, plusieurs formulations similaires mais légèrement différentes ont été ajoutées. Bien sûr, vous pouvez toujours vous souvenir des réponses, et cela était évident à partir des résultats sensiblement améliorés le deuxième jour de la conférence. De nombreux utilisateurs ont passé des dizaines de minutes à jouer au jeu, essayant de battre le record des autres. Mais ici, tout est comme dans la vie - le zèle est récompensé.
Deux semaines se sont écoulées entre l'idée et la réalisation des questions et la mise en œuvre. Bien sûr, tout est en Java. Botte Spring et Gradle d'occasion. L'interface WEB est faite sur Angular. En tant que stockage, la base de données H2 intégrée est utilisée, qui sort de la boîte avec une interface Web, ce qui est très pratique. La configuration du stand est de deux MacBook, dont l'image est dupliquée sur deux téléviseurs. Pour faciliter la configuration, l'application a été déployée à distance sur notre cloud (
https://habr.com/company/odnoklassniki/blog/346868/ ).
Nous avons appris il y a longtemps: aucune fonctionnalité ne devrait être développée sans collecte de statistiques. Bien sûr, nous avons également joint des statistiques détaillées au jeu, que nous pouvons partager.
Au total, le jeu a été joué 811 fois en deux jours. Statistiques de réponses en fonction de la complexité de la question:
DIFFICULTÉ
| COUNT
| CORRECT_PERCENT
|
1
| 3552
| 61
|
2
| 2031
| 49
|
3
| 912
| 46
|
À quelles cellules du terrain et à quelle fréquence les joueurs ont-ils atteint:
Le pourcentage de réponses correctes sur chaque cellule du champ:
Mais le plus intéressant est, bien sûr, les statistiques des questions. Il n'était pas si facile d'évaluer leur complexité en tenant compte de la répartition par catégorie, l'évaluation est toujours subjective et une question simple pour un utilisateur est difficile pour un autre.
Oleg a suggéré de jeter l'une des questions avec les mots «même les nettoyeurs le savent», mais il s'est avéré que peu de nettoyeurs connaissent les bonnes réponses à de nombreuses questions «simples», et les programmeurs aussi. Nous vous proposons quelques questions de notre jeu - leaders sur les réponses incorrectes, essayez d'évaluer votre force!
- Le résultat de l'appel de ce code?
System.out.println(1/0d)
- Lève une ArithmeticException
- Imprime l'infini
- Imprime "NaN"
- Imprime 0
La réponseCela semble être une question très simple. Voici une simple arithmétique, quel pourrait être le problème, pourquoi seulement 28% des joueurs ont-ils donné la bonne réponse? La division d'un entier par 0 en Java entraîne une ArithmeticException
. Mais y a-t-il des entiers ici? Nous allons regarder attentivement. Quel est ce «d» après 0? Cette lettre signifie qu'il ne s'agit pas d'une constante entière 0, mais d'une valeur de type double
. Et il s'avère que l'expression est identique à 1.0 / 0.0. Et ceci est une division par une virgule flottante par zéro, dont le résultat est Double.POSITIVE_INFINITY
. La bonne réponse est donc «b».
- Le résultat de l'appel de ce code?
System.out.println( Long.MAX_VALUE==(long)Float.MAX_VALUE );
- imprimer vrai
- affichera faux
- lève une ArithmeticException
La réponseTout d'abord, vous devez comprendre de plus: Float.MAX_VALUE
ou Long.MAX_VALUE
? Bien que le float
ait une plage de valeurs plus petite que le double
, sa valeur maximale est d'environ 20 ordres de grandeur au-delà de la plage de valeurs long
possibles. Mais comment fonctionne le casting de caractères dans ce cas? On peut le deviner, mais il vaut mieux exécuter le code. Mieux encore, ouvrez la spécification du langage Java, une section sur le rétrécissement de la conversion primitive, et lisez que si la valeur d'un nombre à virgule flottante est trop grande et tombe en dehors de la plage de valeurs disponibles d'un type entier, le résultat de la conversion est égal à la valeur maximale qui peut être représentée à l'aide d'un type entier . C'est-à-dire le résultat de la conversion est Long.MAX_VALUE
. La bonne réponse a été donnée par 27% des répondants.
- Quelle classe n'est pas
Comparable
?
- java.lang.String
- java.util.TreeSet
- java.io.File
- java.lang.Enum
La réponseCette question apparemment simple a dérouté de nombreux, ou plutôt 76% de ceux qui ont répondu. Devinez vous-même laquelle des réponses ici est correcte et quelle était la réponse la plus populaire - 61% des joueurs l'ont choisie.
- À quoi le code est-il identique?
Object o = Math.min(-1, Double.MIN_VALUE)
- Objet o = -1
- Objet o = Double.MIN_VALUE
- Objet o = -1,0
La réponseLa valeur double
minimale est certainement inférieure à -1, qu'est-ce qui pourrait encore être faux? Bien sûr, tout n'est pas si simple, sinon on ne demanderait pas. Il s'avère que Double.MIN_VALUE
ne contient pas exactement ce qui est attendu, à savoir "une constante contenant la plus petite valeur positive non nulle", selon la documentation. Il serait Double.MIN_POSITIVE_VALUE
correct de l'appeler Double.MIN_POSITIVE_VALUE
. Double
encore encerclé son doigt! La bonne réponse est: Object o = -1.0
, et donc seulement 22% des joueurs ont répondu.
- Quelle ligne résultera de l'appel de ce code?
Long.toHexString(0x1_0000_0000L + 0xcafe_babe)
- 1cafebabe
- cafebabe
- ffffffffcafebabe
La réponseSi vous avez choisi la deuxième réponse, vous faites partie des 22% de ceux qui ont répondu correctement. Cette question est tirée du livre Java Puzzlers: Traps, Pitfalls, and Corner Cases, rédigé par Joshua Bloch et Neal Gafter. Si vous avez répondu incorrectement, ne vous découragez pas et courez lire ce livre!
- JDK 8 introduit la prise en charge des annotations sur les paramètres de méthode. Est-il possible d'ajouter une annotation au paramètre de
this
méthode?
- C'est impossible
- Peut-être, mais seulement en bytecode
- Peut-être définir
this
explicitement comme le premier paramètre de la méthode
La réponseLorsque la possibilité de mettre des annotations sur les paramètres de méthode a été ajoutée dans JDK 8,
this
paramètre n'a pas été privé. À cet effet,
this
peut désormais être explicitement spécifié dans les signatures de méthode:
class Foo { public void test(@Annotated Foo this) {} }
Bien que vous puissiez discuter de ses avantages pratiques, c'est maintenant une caractéristique du langage. 32% des joueurs ont deviné la bonne réponse.
- Dans JDK 8, le paramètre
concurrencyLevel
dans le constructeur ConcurrentHashMap
affecte:
- Lecture / écriture simultanée disponible
- Taille initiale de la table
- Sur les deux paramètres
La réponseSi vous avez choisi l'option 2, vous faites partie des 15% qui ont donné la bonne réponse à cette question la plus difficile du jeu. Le fait est que dans JDK 8 segments abandonnés dans ConcurrentHashMap
, concurrencyLevel
perdu son ancienne signification. Cela n'affecte que la taille initiale de la table, et même cela ne limite que la valeur initialCapacity
par le bas.