Aller au contenu

Exercices Solitaire jQuery

Exercice - Solitaire jQuery#

Préparation#

Cet exercice n'est pas réalisable sans utiliser la documentation officielle de jQuery dans laquelle vous trouverez les informations manquantes.

Pour réaliser ce jeu nous avons besoin de :

  • 3 images (png ou gif) :

    • Le pion (50x50px) Pion
    • Le pion cliqué (50x50px) Pion cliqué
    • Une image transparente pour les cases vides (50x50px) Pion vide
  • La bibliothèque Jquery

  • l'extension "user-interface" de jQuery (version 1.7 avec le minimum requis pour le solitaire)
  • une page HTML

Commençons par la page HTML, elle sera simple car le but est de créer le jeu entièrement en JavaScript.Elle va contenir l'entête habituelle avec les liens vers les fichiers JS et dans la partie body une simple div id="solitaire"

<DOCTYPE html>
<html lang="fr">
     <head>
          <meta charset="utf-8" />
    <title>Solitaire</title>
    <script type="text/javascript" src="jquery.js" ></script>
    <script type="text/javascript" src="jquery-ui.js"></script>
    <script type="text/javascript" src="solitaire.js"></script>
    <link rel="stylesheet" href="solitaire.css" type="text/css" />
     </head>
     <body>
          <h1>JQUERY SOLITAIRE</h1>
    <div id="solitaire"></div>
     </body>
</html>

Le reste vous l'aurez compris se passe dans le fichier "solitaire.js" (et un petit peu dans solitaire.css).

Déroulement du jeu#

Avant de se lancer à corps perdu dans la programmation de notre jeux, il est nécessaire d'en faire une analyse préalable.

Les règles du jeu sont simple, un déplacement est autorisé si:\n 1. la case de destination est vide\n 1. la case de destination est située à 2 cases dans une des 4 directions\n 1. un pion est présent entre la case de destination et la case de départ

Les différentes étapes de la programmation du jeu sont:

  • construire le plateau de jeu avec les cases et les pions
  • associer le comportement draggable de jQuery.UI aux pions
  • associer le comportement droppable aux cases vides (au début 1 seule case est vide)
    • définir les conditions d'acceptation du drop
    • effectuer le changement de position et la suppression du pion sauté
    • vérifier la fin du jeu

Initialisation#

Tout d'abord, nous allons lancer le script une fois le DOM chargé :

// **** solitaire en jQuery ****
// nécessite jQuery et jQuery.UI
$(function(){
     //chargement du jeux solitaire
});

Puis nous allons définir la méthode init() qui va préparer le plateau de jeu. On va donc sélectionner la div id="solitaire", la vider (au cas ou) et y insérer le tableau HTML avec les pions dans les bonnes cases (voir exemple en haut de page )

Il y a 3 type de cases:

  • Les cases inaccessibles: <td class="vide" ><img src="vide.png" alt="" /></td>
  • Les pions: <td class="on" ><img src="pion_r.png" alt="X" /></td>
  • Les case vides: <td class="off" ></td> (celle du centre au départ)

Un peu de CSS dans le fichier solitaire.css pour rendre cela joli.

#solitaire table{
   border-collapse: collapse;
}
#solitaire table td{
   padding: 0;
   border: 1px dotted ;
   text-align: center;
}
#solitaire table td.vide{
     background: orange;
}
#solitaire table td img{
   vertical-align: middle;
}

Résultat à obtenir

function init(){
//on ajoute le code HTML ( incomplet ici !!! )
$("#solitaire").empty().append('<table>'+
'<tr><td class="vide" ><img src="vide.png" alt="" /></td>.........</tr>'+
//.......
//.......
'</table>'); 

} // fin init

Déplacer un pion#

Pour déplacer un pion, nous utilisons la fonction draggable() de l'extension jQuery.UI. Cette fonction permet de déplacer un élément DOM afin de le 'déposer' dans un autre. Cet autre élément utilise alors la fonction droppable() qui permet de recevoir les éléments déplacés.

Dans un premier temps nous allons simplement déplacer un pion, puis nous affinerons les paramètres de cette fonction. Durant le jeu, nous seront amenés à redéfinir un pion comme 'déplaçable', nous allons donc créer une fonction dédiée à cette tâche, qui prends en paramètre un élément DOM (une image).

La fonction deplacable()

function deplacable(pion){
     $(pion).draggable();
     return pion;
}

Pour appliquer cette fonction à l'ensemble des pions de notre solitaire, nous faisons appel à la fonction each() de jQuery qui permet d'appliquer un traitement à l'ensemble des résultats d'un sélecteur

Applique la fonction deplacable() à toutes les images (pions)

$("#solitaire td.on img").each(function(){ deplacable(this); });

Vous devriez pouvoir déplacer l'ensemble des pions du plateau de jeu.

En y réfléchissant, ce n'est pas vraiment le pion qu'il faut déplacer car on n'est pas sur que le déplacement sera valide. Nous allons donc utiliser la notion de "fantôme" pour déplacer notre pièce, en précisant que le pion (le vrai) devient invisible au début du drag et redevient visible à la fin. Pour définir les options d'un élément jQuery.UI deux solutions:

  • soit on définit toutes les options lors de l'initialisation du draggable. On utilise alors un pseudo-Objet comme attribut de la forme: {nomOption1:valeurOption1,nomOption2:valeurOption2}
  • soit on ajoute les options après initialisation:$(pion).draggable();$(pion).draggable('option','opacity',0.7);

Ajout d'options aux éléments

$(pion).draggable({
     helper: function(){return $('<img src="pion_n.png" alt="X" />'); },
     start: function(){ $(this).css({opacity:0}); },
     stop: function(){ $(this).css({opacity:100}); }
});

On peut ajouter à cet élément les options opacity, zIndex, cursorAt, containment afin d'affiner l'effet graphique.

Recevoir un pion#

La case qui doit recevoir un pion doit être droppable. La fonction recevante() va jouer ce rôle. Les principales options de la fonction droppable() sont les suivantes:

  • accept : désigne les éléments qui sont acceptés dans la zone de drop

    • soit en donnant un sélecteur correspondant aux éléments acceptables.
    • soit avec une fonction qui renvoi vrai ou faux.
  • drop: une fonction exécutée lors d'un drop réussi.

Testons donc cette fonction sur nos cases vides :

La fonction recevante() appliquées aux case vides

function recevante(reception){
     $(reception).droppable({
          accept: 'img',
          drop: function(){ console.log("DROP!"); }
    });
return reception;
}

// on applique à toutes les cases vides
$("#solitaire td.off").each(function(){recevante(this);});

Normalement, la console de Firebug nous affiche bien "DROP!" si nous lâchons une image dans les(la) cases vides.

Nous allons donc adapter cette fonction à notre besoin. Il nous faut limiter le drop aux pions sautant un pion et situés à 2 cases de distance.Afin de visualiser cette affectation, nous allons ajouter l'option activeClass. Modifions donc l'option accept dans le cas ou notre table fait 9x9 cases:

Test de déplacement

$(reception).droppable({
     activeClass: 'acceptable',
     accept: function(pion){
          var id_case = $("#solitaire td").index(this);
          var id_pion = $("#solitaire td").index($(pion).parent());
          var delta = Math.abs(id_case-id_pion);
          var is_pion_present = $("#solitaire td").eq(id_pion+(id_case-id_pion)/2).find("img").size();
          return (delta==18 || delta==2) && (is_pion_present==1);
     },
     drop: function(){ console.log("DROP!"); }
});

La fonction jQuery index(obj) renvoi le rang de l'objet cherché parmi la sélection. La fonction jQuey eq(i) renvoi le iéme élément. La fonction jQuery find(selecteur) renvoi les éléments enfants correspondants au sélecteur. La fonction jQuery size() compte le nombre d'élément dans l'objet jQuery.

Il nous reste à déterminer les actions à effectuer lorsque le drop est accepté:

  • Définir la case d'arrivée comme 'pleine' et y ajouter un pion 'deplacable'
  • La case d'origine devient vide et 'recevante'
  • La case du milieu devient vide et 'recevante'

On obtient pour l'option drop :

//...
drop: function(event,ui){
     console.log("DROP!");
    // détruit la case recevante et ajoute un pion 'deplacable' à la case d'arrivée
    $(this).removeClass("off").addClass("on").droppable("destroy").append(
        deplacable($('<img src="pion_r.png" alt="X" />'))
    );
    var case_origine = $(ui.draggable).parent();
    var id_case = $("#solitaire td").index(this);
    var id_pion = $("#solitaire td").index(case_origine);
    var case_saute =  $("#solitaire td").eq(id_pion+(id_case-id_pion)/2);
    //la case de départ est vide et 'recevante'
    recevante($(case_origine).empty().removeClass("on").addClass("off"));
    //la case du milieu est vide et 'recevante'
    recevante($(case_saute).empty().removeClass("on").addClass("off"));
 }
//...

Pour améliorer la jouabilité, nous allons utiliser un effet de fondu pour faire disparaître le pion sauté. Pour cela, il nous faut mettre en place un 'callback', c'est à dire une fonction appelée à la fin d'un évènement. On obtient pour l'option drop:

//...
    // la case de départ est vide et 'recevante'
    recevante($(case_origine).empty().removeClass("on").addClass("off"));
    // le pion saute disparait
    $(case_saute).find("img").fadeOut(function(){
         // à la fin de l'animation, la case sautée est vide et 'recevante'
         recevante($(case_saute).empty().removeClass("on").addClass("off"));
    });
 }
//...

Essayez ensuite de tester la fin de la partie, deux cas sont possibles :

  • Vous avez gagné (un seul pion restant)
  • Il ne reste plus de coup possible