Pour partager cette vidéo sur les réseaux sociaux ou sur un site, voici son url :
Sujets que vous pourriez aussi aimer :Contrôler les saisies - Jeu du pendu 3/3
Dans ce dernier des trois volets
Javascript consistant à monter l'application du
jeu du pendu pour le Web, nous devons
contrôler les lettres saisies par l'internaute. L'objectif est de comparer chaque proposition, avec les
caractères encapsulés dans le mot masqué à dévoiler. Dès qu'une
lettre est trouvée, elle doit être divulguée. Dans le cas contraire, une erreur est comptabilisée pour décrémenter le score final. 4 erreurs sont permises par mot. A l'issue, le
pendu est complètement dévoilé et un
nouveau mot est suggéré. Au bout de 10 mots mystères, la partie est terminée et le score final est proposé.
La capture ci-dessus illustre l'application finalisée du
jeu du pendu. La partie est en cours. Selon l'indication donnée, l'internaute doit retrouver le mot :
Symétrique. Il ne manque plus que deux caractères, le I et le U. Toutes les lettres proposées par le joueur sont matérialisées dans le clavier virtuel, en bas de la page Web. Elles sont grisées pour qu'il sache quelles sont celles à ne plus proposer. Deux erreurs ont été commises puisque l'image du pendu est restituée à moitié. Il reste 9 mots à trouver après celui-ci, qui est donc le premier.
Sources et présentation de la problématique
Dans les deux volets précédents, nous avions commis les travaux permettant de récolter le questionnaire, interpréter les touches du clavier et encoder le mot mystère à dévoiler. Il convient donc de poursuivre l'élaboration du jeu, à partir des résultats obtenus.
La décompression fournit le fichier de la page Web principale nommée :
controler-saisies-jeu-pendu.html. Ce dernier est accompagné de ses ressources externes dans les sous dossiers. Notamment le
dossier img_pendu stocke les miniatures du pendu, à retranscrire au gré des erreurs commises. Le
dossier js quant à lui, propose le script externe du questionnaire que nous avons déjà récupéré lors de la première de ces formations.
- Double cliquer sur le fichier de la page Web principale pour l'ouvrir dans un navigateur,
- Cliquer sur le bouton Débuter pour commencer une nouvelle partie,
Une indication apparaît pour le mot mystère à dévoiler, encodé par des tirets.
- Enfoncer quelques touches du clavier,
Les lettres correspondantes sont marquées dans le clavier virtuel, en bas de page, comme l'illustre la capture ci-dessous.
Il s'agit précisément des travaux accomplis jusqu'alors. Mais à ce stade, les lettres proposées ne sont pas comparées à celles de l'expression à retrouver. Il s'agit de l'enjeu de ce troisième et dernier volet.
- A la racine du dossier de décompression, cliquer avec le bouton droit de la souris sur le fichier de la page Web principale : controler-saisies-jeu-pendu.html,
Nous accédons ainsi au
code Html de la page Web que nous venons de tester.
- Faire défiler l'affichage vers le bas jusqu'à atteindre la section du script, située sous la balise fermante du corps de la page (</body>),
Nous y retrouvons les développements précédents en l'état. Tout d'abord, nous remarquons la présencede toutes les
variables publiques, déclarées en haut du script, en dehors de toute fonction. La
fonction recuperer, comme son nom l'indique, est celle qui récolte le questionnaire issu du
script externe, en rangeant chaque mot dans une ligne indépendante d'un tableau de variables. Nous l'avons développée dans le premier volet sur l'
interprétation des touches du clavier par le code. La
fonction debuter est déclenchée au clic sur le bouton du même nom, implanté sur la page Web. Elle permet de démarrer une nouvelle partie en réinitialisant toutes les variables de décompte. Elle appelle la
fonction suivant pour lui passer la main. Cette dernière a été conçue lors de la
formation précédente pour traiter et encoder les chaînes de caractères. Elle consiste à générer un nombre aléatoire inédit, pour piocher un nouveau mot au hasard, dans le tableau de variables. Puis elle encode le mot mystère grâce aux expressions régulières pour afficher des tirets à la place des lettres. Le nombre de ces tirets donne l'indication sur la longueur de l'expression à découvrir.
Comparer les lettres saisies
Cette
fonction suivant doit aussi être appelée par la
fonction clavier, à chaque nouveau mot à proposer. Cet appel doit intervenir dans deux cas, soit lorsque l'internaute a totalement dévoilé le mot précédent, soit lorsqu'il a commis le nombre maximum de fautes autorisées, soit 4.
Il s'agit donc de reprendre le développement de la
fonction clavier, là où nous l'avions laissé. Après la retranscription des touches frappées au clavier, nous avions marqué les lettres correspondantes dans le clavier virtuel. Pour ce faire, nous avions affecté la couleur de fond du calque correspondant :
document.getElementById('calque_' + touche.toLowerCase()).style.backgroundColor = '#666666';
Il s'agit de passer en revue chacune des lettres de l'expression à dévoiler, grâce à une
boucle For. Par traitement récursif, nous pourrons donc les comparer avec le caractère proposé par l'internaute et mémorisé dans la
variable touche.
- A la suite de la dernière instruction de la fonction clavier, ci-dessus rappelée, ajouter le traitement récursif suivant :
for(indice=0; indice<=mem_mot.length-1; indice++)
{
la_lettre = mem_mot.substr(indice,1);
if(la_lettre==touche)
{
trouve = true;
le_mot = le_mot.substr(0,indice) + la_lettre + le_mot.substr(indice + 1);
document.getElementById('leMot').innerHTML = le_mot;
}
}
Le mot mystère non encodé avait été enregistré dans la
variable publique mem_mot. Grâce à une boucle for, nous passons en revue chacune de ses lettres, en commençant par la première (indice=0) et en poursuivant jusqu'à la dernière (indice<=mem_mot.length-1). La
propriété length renvoie en effet le nombre de caractères contenus dans la chaîne sur laquelle elle est appliquée. Comme le premier caractère est repéré à la position 0, le dernier est repéré à la position située juste avant le nombre de lettres (-1).
A chaque passage dans la boucle, nous mémorisons le caractère extrait dans la variable la_lettre, pour faciliter la comparaison. C'est pourquoi dans la foulée, nous enclenchons un test sur l'équivalence de la lettre et de la touche enfoncée (if(la_lettre==touche)). Si ce critère est vérifié, la proposition est un succès. Nous basculons la
variable booléenne trouve Ã
true, pour l'exploiter plus tard. Si à l'issue de la boucle elle vaut toujours false, nous saurons que la proposition est un échec. Nous exploiterons cet indicateur en conséquence. Puis, nous reconstruisons le mot mystère de manière à remplacer le ou les tirets correspondants, par la lettre proposée. Un caractère peut en effet apparaître plusieurs fois dans une expression ou un mot. Pour cela, nous exploitons la
méthode Javascript substr. Cette dernière permet de prélever un morceau dans la chaîne désignée. Nous prélevons tout d'abord la partie situé jusqu'à la lettre trouvée (le_mot.substr(0,indice)). Le premier argument indique la position de départ (0 pour le début). Le second indique la longueur sur laquelle il faut prélever. Ainsi, nous conservons les tirets en l'état. Puis, nous concaténons ce résultat à la lettre proposée par l'internaute. Et nous assemblons la fin de la chaîne intacte, avec les tirets (le_mot.substr(indice + 1)). Cette fois en effet, nous prélevons juste après la lettre dévoilée (indice + 1). Comme nous ne renseignons pas le deuxième argument sur la longueur, la
fonction Javascript substr prélève jusqu'à la fin de la chaîne. Enfin, comme ce traitement est inclus dans une boucle, il se répète à chaque fois que la lettre est trouvée. Toutes les occurrences d'une même proposition sont ainsi restituées.
Nous pouvons effectuer un premier test à ce stade.
- Enregistrer les modifications (CTRL + S) et basculer sur la fenêtre du navigateur,
- Rafraîchir la page Html avec la touche F5 du clavier,
- Cliquer sur le bouton Débuter,
- Enfoncer une touche dont la lettre se trouve vraisemblablement dans l'expression à reconstruire,
Le caractère est dévoilé sur toutes les positions où il est repéré. Dans l'exemple de la capture ci-dessus, l'expression à trouver est
LE PERIMETRE. La lettre E est bien présente quatre fois. Comme la
fonction clavier est appelée à chaque fois qu'une touche est enfoncée, vous pouvez poursuivre jusqu'à dévoiler le mot complet. Mais le code permettant de compter les erreurs ou de vérifier que le mot est intégralement découvert, n'existe pas encore. En conséquence, la partie ne peut pas enchaîner avec le mot suivant.
- Revenir dans l'éditeur de code de la page Html,
Dans un premier temps, nous proposons de traiter le cas où la suggestion de lettre est un succès. Cette situation est repérée par la
variable trouve lorsqu'elle porte la valeur booléenne
true. Nous devons donc la tester avec une
instruction conditionnelle if.
- Pour ce faire, à la suite du code de la fonction clavier, après la boucle, ajouter les bornes de l'instruction conditionnelle, comme suit :
if(trouve == true)
{
}
else
{
}
Dans le cas où la proposition a échoué (else), nous devrons notamment incrémenter le compteur d'erreurs (nb_erreurs). Dans le cas où la lettre est trouvée (if), il s'agit de vérifier si le mot est complètement dévoilé.
- Pour ce faire, dans la branche If de l'instruction conditionnelle, ajouter le nouveau test suivant :
if(le_mot == mem_mot)
{
}
Dans le cas où l'expression en cours de reconstruction (le_mot) est strictement équivalente à celle recherchée (mem_mot), cela signifie que tous les tirets ont été remplacés par des lettres. En conséquence, le mot est terminé. Si le mot est terminé, nous devons commencer par incrémenter la
variable publique nb_passe. C'est elle qui renseigne sur l'évolution de la partie. Si elle atteint la valeur 10, elle indique que les 10 mots ont été joués et que le jeu est terminé. Mais ce n'est pas tout. Dans ce contexte, deux cas de figure se proposent. Soit effectivement la partie est terminée (nb_passe = 10), soit, comme le mot est trouvé, le prochain doit être proposé. Donc la
fonction suivant doit de nouveau être appelée.
A l'intérieur de cette deuxième instruction conditionnelle, nous devons donc en inclure une troisième.
- Entre les bornes du If précédent, ajouter l'instruction conditionnelle suivante :
nb_passe++;
if(nb_passe==10)
{
document.getElementById('leScore').innerHTML = 'Votre score :<strong>' + (le_score-nb_erreurs/4) + ' / 10</strong> - Mots restants : <strong>' + (10 - nb_passe) + '</strong>- <strong>Victoire !</strong>';
fin = true;
}
else
{
window.setTimeout(function attendre(){ suivant(); }, 1000);
}
Lorsque les 10 mots ont été atteints (nb_passe==10), nous restituons tout d'abord les résultats dans le
calque d'identifiant leScore, prévu à cet effet. Nous le désignons comme toujours, grâce à la
méthode getElementById de l'objet Javascript document. Nous affectons ensuite son contenu grâce à sa
propriété innerHTML. Nous concaténons à la partie statique, le score mémorisé jusqu'alors dans la
variable publique le_score, en le décrémentant des potentielles dernières erreurs commises (le_score-nb_erreurs/4). Nous réactualisons de même l'information sur le nombre de mots restants (10 - nb_passe), qui dans ce cas précis, confirme qu'il n'y en a plus. Ensuite, nous affectons la
variable fin à true. C'est elle qui est utilisée au début de la
fonction clavier pour définir si l'interception des touches du clavier peut commencer. A true, elle indique que la partie est finie. Donc rien ne se produit. C'est un clic sur le
bouton Débuter qui la rebasculera à false.
Dans le cas où la partie n'est pas finie (else), comme le mot est découvert, le suivant doit être proposé. Nous devons donc appeler la
fonction suivant moyennant une temporisation. C'est ce que nous faisons grâce à la
méthode setTimeout de l'
objet Javascript window. Elle permet d'exécuter des actions inscrites dans une fonction passée en premier paramètre, au bout d'un délai défini en second paramètre. Ce délai s'exprime en millisecondes. Réglé à 1000, la
méthode setTimeout attend 1 seconde avant d'exécuter les actions du premier argument qui consistent à appeler la
fonction suivant. Ainsi, avant de déboucher sur le nouveau mot, l'internaute a le temps de visualiser et d'apprécier le résultat. Nous avions présenté et décortiqué cette
méthode setTimeout dans la
formation Javascript pour créer un diaporama Web automatisé.
Dans le cas où la lettre n'est pas trouvée, nous devons incrémenter la variable des erreurs mais pas seulement. Nous devons aussi afficher l'image correspondante du pendu, pour rendre compte de l'état en cours. Enfin, s'il s'agit de la quatrième faute, le mot suivant doit être proposé, considérant que celui-ci est un échec. Donc la
variable nb_passe doit être incrémentée et la
fonction suivant doit être appelée, toujours en respectant un petit délai d'une seconde.
- Dans la branche else du premier if, ajouter les instructions suivantes :
nb_erreurs++;
document.getElementById('lePendu').src = 'img_pendu/pendu' + nb_erreurs + '.png';
if(nb_erreurs==4)
{
nb_passe++;
if(nb_passe==10)
fin = true
window.setTimeout(function attendre(){ suivant(); }, 1000);
}
C'est la
propriété src d'un contrôle Html image (balise img) qui permet de définir sa source. Il s'agit de lui affecter le chemin complet de la miniature à afficher, ce que nous faisons. La miniature est située dans le
sous dossier img_pendu. Le nom de l'image quant à elle, débute nécessairement par la partie statique
pendu. Puis elle se poursuit par un chiffre correspondant au nombre d'erreurs commises. Nous l'avions constaté dans la formation précédente. Donc, nous concaténons ce nom avec la
variable nb_erreurs. Et nous n'oublions pas d'ajouter l'extension. Dans le cas où les quatre fautes ont été atteintes (nb_erreurs==4), nous comptabilisons bien le mot supplémentaire (nb_passe++), avant de passer la main à la
fonction suivant, grâce à la
méthode setTimeout, comme précédemment. Mais avant de proposer le prochain mot, nous vérifiions qu'il ne s'agit pas du dernier. Si tel est le cas, nous basculons la variable booléenne pour verrouiller la partie.
- Enregistrer les modifications et basculer sur le navigateur,
- Rafraîchir la page Html avec la touche F5 du clavier,
- Cliquer sur le bouton Débuter,
- Jouer une partie en proposant des lettres au clavier,
Dès qu'une lettre est trouvée, elle est dévoilée autant de fois qu'elle est repérée, comme nous l'avions constaté. Dès qu'une erreur est commise, la faute est sanctionnée par l'image du pendu qui progresse. Si le mot est intégralement découvert, il reste affiché une seconde, puis le suivant est proposé. Les statistiques se mettent à jour en tenant compte des erreurs et du nombre de mots passés. Si 4 fautes sont commises, après un délai d'une seconde, le mot suivant est proposé avec mise à jour des statistiques.
Nettoyer tous les Div d'un calque parent
Le jeu du pendu semble tout à fait fonctionnel et satisfaisant. Au bout de 10 mots, la partie se fige en effet, grâce à la
variable fin réglée Ã
true, interdisant de fait la réception de nouvelles touches. Mais à ce stade, un réglage est cruellement manquant. Le
clavier virtuel conserve en permanence la mémoire des touches enfoncées. Il doit se réinitialiser à chaque nouveau mot, puisque toutes les lettres sont de nouveau permises. Nous devons pour cela développer la
fonction init_calques qui est appelée par la fonction suivant.
Mais ces calques ne sont pas nommés selon une suite logique. Ils sont certes préfixés d'un nom statique :
calque_. Leur suffixe quant à lui est le caractère de la touche enfoncée et non un numéro incrémenté. Difficile dans ces conditions d'envisager une
boucle for permettant de les parcourir tous, en incrémentant un numéro. Nous avions apporté la solution dans la
formation Javascript sur les traitements récursifs. L'astuce consiste à identifier le calque conteneur et à le désigner comme le
calque parent. Une de ses propriétés renverra alors une collection recensant tous les calques qu'il contient. Nous n'aurons plus qu'à parcourir l'ensemble des calques enfants de la collection.
L'aperçu du code Html ci-dessous rappelle la structure du clavier virtuel.
...
<div class='centre' id='le_clavier'>
<div class='titre_centre' id='apercu' style='height:140px;padding-left:74px;width:650px;'>
<div class='lettre' id='calque_a'>A</div><div class='lettre' id='calque_b'>B</div>
<div class='lettre' id='calque_c'>C</div><div class='lettre' id='calque_d'>D</div>
<div class='lettre' id='calque_e'>E</div><div class='lettre' id='calque_f'>F</div>
...
A l'intérieur du calque d'
identifiant le_clavier se trouve un autre calque d'
identifiant apercu. Sa balise fermante n'intervient qu'après l'énumération de tous les calques correspondant aux touches du clavier. Le calque parent le plus judicieux à désigner est donc le
contrôle Html Div d'
identifiant apercu.
- Dans les bornes de la fonction init_calques, ajouter les deux déclarations suivantes :
var parent = document.getElementById('apercu');
var enfants = parent.getElementsByTagName('div');
Comme toujours, c'est bien la
méthode getElementById de l'
objet document qui permet de pointer sur un contrôle Html par son identifiant passé en paramètre. Mais comme cette fois nous n'associons pas cette méthode à une propriété, c'est l'objet calque lui-même qui est retourné. Donc la
variable parent est reconnue comme un objet calque représentant le
Div le_clavier. Du coup, il propose la
méthode getElementsByTagName. Cette dernière retourne la collection de tous les contrôles contenus, dont le type est passé en paramètre. Ici, nous cherchons à récupérer tous les calques enfants, donc nous lui passons le
paramètre div pour les identifier. Cette collection est stockée dans la
variable enfants qui se transforme pour l'occasion en
tableau de variables. Chaque calque à passer en revue est contenu dans une ligne différente du tableau. Nous n'avons plus qu'à le parcourir à l'aide d'une boucle.
- Pour ce faire, Ã la suite du code de la fonction init_calques, ajouter la boucle suivante :
for (var i = 0; i < enfants.length; i++)
{
enfants[i].style.backgroundColor = '#EDEEEE';
}
La
propriété length du
tableau de variables enfants retourne le nombre d'éléments qu'il contient. Nous initialisons donc une boucle qui parcourt ce tableau de la première à la dernière ligne. A chaque passage dans la
boucle, nous pointons sur le calque enfant de la ligne en cours, en lui passant l'indice de la variable de boucle (enfants[i]). Il ne nous reste plus qu'à exploiter les attributs Html, pour réinitialiser sa couleur de fond.
- Enregistrer les modifications et basculer sur la fenêtre du navigateur,
- Rafraîchir la page Html avec la touche F5 du clavier,
- Puis, cliquer sur le bouton Débuter,
La
fonction debuter appelle la
fonction suivant qui appelle la
fonction init_calques. Et vous remarquez qu'un défaut surgit. Il se répètera à chaque réinitialisation au passage de mots.
Deux calques particuliers sont intégrés dans ce clavier virtuel. Ils permettent simplement de réaliser un saut de ligne, afin de poursuivre l'énumération plus bas. Ils ne doivent pas être intégrés dans ce traitement. Dans le
code Html, ils sont respectivement repérés par les identifiants
saut1 et
saut2. Nous devons exploiter ces derniers pour les exclure du traitement, grâce à une instruction conditionnelle.
- Dans la boucle, ajouter le test suivant :
for (var i = 0; i < enfants.length; i++)
{
if(enfants[i].id != 'saut1' && enfants[i].id != 'saut2')
enfants[i].style.backgroundColor = '#EDEEEE';
}
Le calque en cours de lecture ne doit pas être repéré ni avec l'identifiant saut1, ni avec l'identifiant saut2 pour que les réglages de mise en forme lui soient appliqués.
Si vous réalisez une partie complète après avoir enregistré les modifications, vous constatez que le
jeu du pendu est désormais totalement fonctionnel. Les statistiques se mettent à jour à chaque passage de mot. Les lettres du clavier virtuel sont parfaitement réinitialisées. A l'issue du jeu, les touches ne sont plus interprétées. L'internaute doit de nouveau cliquer sur le
bouton Débuter, pour reprendre une partie.
Nous sommes parvenus à créer le jeu du pendu pour le Web, au cours de ces trois formations grâce au
langage Javascript.
Le code complet des deux
fonctions clavier et
init_calques que nous avons poursuivi et développé dans ce dernier volet, est le suivant :
function init_calques()
{
var parent = document.getElementById('apercu');
var enfants = parent.getElementsByTagName('div');
for (var i = 0; i < enfants.length; i++)
{
if(enfants[i].id != 'saut1' && enfants[i].id !='saut2')
enfants[i].style.backgroundColor = '#EDEEEE';
}
}
function clavier(evenement)
{
var indice=0;
var la_lettre='';
var trouve = false;
if(fin==true)
return;
var touche = window.event ? evenement.keyCode : evenement.which;
touche = String.fromCharCode(touche).substr(0,1);
//alert(touche);
if(touche==' ')
{
la_touche = ' ';
return;
}
if(lettres_ok.indexOf(touche)==-1)
return;
document.getElementById('calque_' + touche.toLowerCase()).style.backgroundColor = '#666666';
for (indice=0; indice<=mem_mot.length-1; indice++)
{
la_lettre = mem_mot.substr(indice,1);
if(la_lettre==touche)
{
trouve = true;
le_mot = le_mot.substr(0,indice) + la_lettre + le_mot.substr(indice + 1);
document.getElementById('leMot').innerHTML = le_mot;
}
}
if(trouve == true)
{
if(le_mot == mem_mot)
{
nb_passe++;
if(nb_passe==10)
{
document.getElementById('leScore').innerHTML = 'Votre score :<strong>' + (le_score-nb_erreurs/4) + ' / 10</strong> - Mots restants : <strong>' + (10 - nb_passe) + '</strong>- <strong>Victoire !</strong>';
fin = true;
}
else
{
window.setTimeout(function attendre(){ suivant(); }, 1000);
}
}
}
else
{
nb_erreurs++;
document.getElementById('lePendu').src = 'img_pendu/pendu' + nb_erreurs + '.png';
if(nb_erreurs==4)
{
nb_passe++;
if(nb_passe==10)
fin = true
window.setTimeout(function attendre(){ suivant(); }, 1000);
}
}
}