dans la ou les catégorie(s) : code et avec pour étiquette(s) : ,

Aujourd’hui, je vous propose un petit jeu avec du code JavaScript et une approche visuelle.
Il s’agit du jeu du pousse-pousse ou taquin.

Première étape, mélanger les éléments, le HTML et le CSS.

Selon votre approche, le JS sera plus ou moins complexe… j’ai commencé un prototype avec un « grid-layout » pour finalement basculer sur un placement par x et y (en transformation CSS via GSAP).

Voici le HTML :

<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
  <div class="item">11</div>
  <div class="item">12</div>
  <div class="item">13</div>
  <div class="item">14</div>
  <div class="item">15</div>
  <div class="special"></div>
</div>
<div class="win">
  YOU WIN
</div>

et le CSS simplifié :

.grid {
  position: relative;
  width: 400px;
  height: 400px;
}
.win {
  opacity: 0;
  z-index: 0;
}
.item {
  z-index: 999;
  position: absolute;
  width: 100px;
  height: 100px;
}

Pour le placement en tableau, j’utilise GSAP et TweenMax :

TweenMax.set('.grid>div',{
  x:function(i){return i%4 * 100}, //0,100,200,300, 0,100,200 …
  y:function(i){return Math.floor(i/4) * 100} // 0,0,0,0, 100,100,100,100, 200,200…
})
Avec TweenMax, le « i » dans « function(i) » va prendre les valeurs de 0 pour le 1er item, 1 pour le second, 2, jusqu’à 15.

Deuxième étape, mélanger les éléments !

Si vous parlez un peu anglais, ça aide, taper « shuffle element javascript » dans un moteur de recherche et trouver un bout de code sur StackOverflow.
J’ai trouvé plus ou moins ceci :

var grid = document.querySelector(".grid");
for (var i = grid.children.length; i >= 0; i--) {
    grid.appendChild(grid.children[Math.random() * i | 0]);
}

Le code est un peu bizarre, mais ce n’est pas important. La boucle for est en décompte, cela va un peu plus vite qu’en passant par i++.
« Math.random() * i | 0 » donne un entier au hasard.

L’astuce

1999

Au siècle dernier, j’avais lu un article pour faire un taquin avec peu de lignes, j’ai retrouvé celui-ci : http://yazo.net/racine/v2/director/pouss.html ! C’est un autre langage (Director Lingo), mais le principe marche toujours.
Quand on clique sur une case, on teste si elle « touche » la case vide et si oui, on inverse les positions, celle qui est touchée se place sur la vide et la vide sur celle qui est touchée.

2019

Pour faire un test simple, je vais mesurer la distance (juste utiliser Pythagore) entre la case cible et la case vide, si c’est ≤ 100 (dans mon cas) alors elles sont voisines (en diagonal on aura ~ 141px) sinon rien.

Le test de la victoire

Après chaque déplacement, je compte le nombre d’items bien placés.

  var score = 0
  for(var i = 0;i<items.length;i++){
    if(items[i]._gsTransform.x === i%4 * 100 && items[i]._gsTransform.y === Math.floor(i/4) * 100){ 
      score++; 
    }
  }

Version simple

See the Pen taquin parfois impossible by Benoît Wimart (@benoitwimart) on CodePen.0

Joie du code

Après avoir codé la version basique, je n’arrivais pas à finir le puzzle.

Un mélange hasardeux va donner des puzzles impossibles, cette vidéo vous explique pourquoi.

J’ai trouvé une explication pour valider les mélanges sur les « Puzzle of Fifteen ». On compte le nombre de permutations et on regarde le numéro du rang de la case vide en comptant du bas vers le haut. Si le nombre de permutation est pair, le rang doit être impair, s’il est impair, le rang doit être pair.

See the Pen taquin avec test by Benoît Wimart (@benoitwimart) on CodePen.0