Passer au puzzle
L'autre jour, un souvenir m'est venu à l'esprit d'un petit puzzle de mon enfance, un puzzle coulissant dans lequel 15 tuiles carrées sont placées dans un cadre dans un arrangement de cellules 4 x 4 laissant un espace libre. Un ensemble de crêtes et de rainures sur les bords de chaque carreau et du cadre permet aux carreaux de glisser les uns sur les autres tout en les maintenant dans le cadre. À tout moment, n'importe quelle tuile adjacente à l'espace libre peut se déplacer dans cet espace, sinon les tuiles ne peuvent pas bouger. Déplacer une tuile dans l'espace libre laisse alors un nouvel espace libre d'où vient la tuile et une autre tuile peut alors se déplacer dans ce nouvel espace. L'idée est de faire glisser plusieurs fois les tuiles de cette manière pour les disposer dans un ordre prédéterminé.
Apparemment, cela s'appelle un "15 Puzzle" et existe depuis les années 1870. La recherche sur le Web renvoie un certain nombre de récréations écrites dans une variété de langages de programmation et il existe en effet plusieurs articles ici sur dev.to, notamment https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n. , https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m et https://dev.to/claurcia/slide-puzzle-5c55 le tout en JavaScript et https :/ /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj dans Go. Il est également présenté comme un bon défi de démarrage pour ceux qui apprennent JavaScript.
Ce qui a piqué mon intérêt, c'est l'idée qu'il devrait être recréable sur le Web en utilisant aucun langage de programmation ! Autrement dit, une implémentation utilisant uniquement du HTML et du CSS purs. Je le présente donc ci-dessous. Le seul compromis que j'ai dû faire était que les 10 jeux fournis avaient des positions de départ fixes et mélangées.
Pour cela, l'ordre prédéterminé est d'afficher une image terminée.
Le principe de base de cette implémentation est que chaque tuile conserve un enregistrement d'état indiquant où elle se trouve dans le cadre. Il n'existe pas beaucoup de façons de modifier et de conserver l'état en HTML et CSS, mais la plus courante est le "piratage de case à cocher", et cette implémentation en fait un usage intensif. Pour toute personne qui n'est pas familière avec le hack de case à cocher, lorsqu'un élément
Ainsi, chaque vignette comporte une paire de groupes de boutons radio, chacun comportant quatre boutons radio. L'un de ces groupes conserve la position de la tuile sur l'axe X et l'autre sa position sur l'axe Y. (Ou respectivement position horizontale et position verticale, si vous préférez.) Les quinze tuiles reçoivent chacune initialement une combinaison différente de coordonnées X et Y via leurs boutons radio afin que chacune occupe une cellule différente dans le cadre.
Les vignettes sont initialement placées dans la cellule supérieure gauche du cadre, puis déplacées dans le cadre via CSS mesurant l'état des boutons radio en leur appliquant une transformation de traduction :
/* "X" refers to the X-axis cell positions, "Y" to the Y-axis cell positions. * 0, 1, 2, 3 refers to the position on that axis, * 0 = left and top, 3 = right and bottom respectively. */ .tile:has(.X0:checked~.Y0:checked) { transform: translate(0%, 0%); } .tile:has(.X0:checked~.Y1:checked) { transform: translate(0%, 100%); } .tile:has(.X0:checked~.Y2:checked) { transform: translate(0%, 200%); } .tile:has(.X0:checked~.Y3:checked) { transform: translate(0%, 300%); } .tile:has(.X1:checked~.Y0:checked) { transform: translate(100%, 0%); } /* and so on for the remainder of the sixteen combinations */
La vignette contient alors également huit éléments d'étiquette, correspondant aux huit boutons radio. Chaque étiquette est positionnée de manière absolue, se superposant les unes aux autres et chacune remplit complètement la tuile. Les étiquettes sont transparentes et sont initialement configurées pour ne pas répondre aux clics et aux pressions en définissant pointer-events:none sur chacune d'elles.
L'étape suivante consiste pour les sélecteurs CSS à identifier l'emplacement de la cellule vide. Cela se fait par élimination, c'est la cellule dont les coordonnées X,Y ne sont représentées par la paire de groupes de boutons radio d'aucune des quinze tuiles.
Par exemple, si cela correspond :
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
alors la cellule vide doit actuellement se trouver dans la cellule du coin supérieur gauche. Répétez cette opération pour chacune des seize cellules et exactement une d’entre elles correspondra.
Une fois cela fait, les cellules adjacentes à la cellule vide peuvent être identifiées. Si la cellule vide est dans un coin, alors il y a exactement deux tuiles qui peuvent entrer dans cette cellule, sinon, si la cellule vide est contre un des côtés du cadre, il y a trois tuiles qui peuvent entrer dans la cellule, sinon la cellule vide est dans un coin. La cellule doit être l’une des quatre cellules du milieu et quatre tuiles peuvent s’y déplacer. Pour chacune de ces vignettes, exactement l'un des huit libellés des vignettes activera le bon bouton radio nécessaire pour déplacer la vignette vers la cellule vide. Cette étiquette est activée en redéfinissant la valeur de ses événements de pointeur sur auto. Ainsi, à titre d'exemples :
/* Top, left corner */ .frame:not(:has(.tile .X0:checked ~ .Y0:checked)) { :is( .tile:has(.X0:checked ~ .Y1:checked) label.Y0, .tile:has(.X1:checked ~ .Y0:checked) label.X0 ) { pointer-events: auto; } } /* right most cell of row two */ .frame:not(:has(.tile .X1:checked ~ .Y3:checked)) { :is( .tile:has(.X1:checked ~ .Y2:checked) label.Y3, .tile:has(.X0:checked ~ .Y3:checked) label.X1, .tile:has(.X2:checked ~ .Y3:checked) label.X1 ) { pointer-events: auto; } } /* second cell from left on row three */ .frame:not(:has(.tile .X2:checked ~ .Y1:checked)) { :is( .tile:has(.X2:checked ~ .Y0:checked) label.Y1, .tile:has(.X2:checked ~ .Y2:checked) label.Y1, .tile:has(.X1:checked ~ .Y1:checked) label.X2, .tile:has(.X3:checked ~ .Y1:checked) label.X2 ) { pointer-events: auto; } }
La dernière étape du jeu consiste à identifier le moment où le puzzle est résolu. Il s'agit simplement de vérifier que les 15 tuiles ont toutes leurs boutons radio attendus sur les axes X et Y définis sur leur position "résolu".
/* Each tile is assigned a letter "a" to "o". * The puzzle is solved when the tiles are in alphabetical order * reading left to right and top to bottom */ .frame:has(.a .X0:checked ~ .Y0:checked):has(.b .X1:checked ~ .Y0:checked):has( .c .X2:checked ~ .Y0:checked ):has(.d .X3:checked ~ .Y0:checked):has(.e .X0:checked ~ .Y1:checked):has( .f .X1:checked ~ .Y1:checked ):has(.g .X2:checked ~ .Y1:checked):has(.h .X3:checked ~ .Y1:checked):has( .i .X0:checked ~ .Y2:checked ):has(.j .X1:checked ~ .Y2:checked):has(.k .X2:checked ~ .Y2:checked):has( .l .X3:checked ~ .Y2:checked ):has(.m .X0:checked ~ .Y3:checked):has(.n .X1:checked ~ .Y3:checked):has( .o .X2:checked ~ .Y3:checked ) ~ .options .success { display: block; }
Le reste est cosmétique. Le glissement se fait avec une simple transition de la transformation décrite ci-dessus
.tile { transition: 0.5s transform; @media (prefers-reduced-motion) { transition: none; } }
et chaque tuile affiche une partie de l'image du jeu en utilisant la taille et la position de l'arrière-plan
.tile { background-size: 400%; } #board1 .tile { background-image: url("https://alohci.net/image/dev.to/slidergame/mullermarc-k7bQqdUf954-unsplash.webp"); } .a { background-position: 0% 0%; } .b { background-position: 33.333% 0%; } .c { background-position: 66.667% 0%; } .d { background-position: 100% 0%; } .e { background-position: 0% 33.333%; } /* and so on for the remaining tiles */
et il y a un seul ensemble de boutons radio pour choisir lequel des dix jeux jouer.
Pour jouer au jeu, cliquez ou appuyez simplement sur la vignette que vous souhaitez faire glisser vers la cellule vide.
J'ai également fourni un mode "barebones" pour afficher les lettres des vignettes et les boutons radio, ce qui pourrait aider à comprendre le fonctionnement du HTML et du CSS.
Voici donc le jeu de réflexion terminé. S'il vous plaît laissez-moi savoir vos commentaires.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3