Comment créer un clone de Wordle en JavaScript

Dans cet article, vous allez recréer le jeu de devinette Wordle. Cet article couvre la logique de base du jeu mais n’implémente pas le partage de vos résultats. L’article ne couvre pas non plus la fonctionnalité qui génère les statistiques du jeu.

Ce tutoriel est destiné aux développeurs frontaux débutants qui souhaitent créer un projet JavaScript amusant et simple.

Conditions préalables

Ce tutoriel suppose une compréhension de base de.. :

Comment construire le clone de Wordle

Voici les étapes à suivre pour créer le clone de Wordle :

  • Configuration du projet
  • Création du plateau de jeu
  • Création du clavier à l’écran
  • Accepter les entrées de l’utilisateur
  • Ajout de notifications
  • Faire en sorte que le clavier à l’écran génère des entrées
  • Ajout d’une animation

Configuration du projet

Avant de construire le jeu, vous devez mettre en place certains composants. Tout d’abord, vous devez créer un dossier pour tout le code source de notre clone. Appelez ce dossier « build ».

Après avoir fait cela, configurez votre serveur de développement.

Serveur réel

Vous allez utiliser un serveur de développement appelé live-server. Cette étape est facultative, mais elle vous évite de devoir recharger la page après chaque modification du code source.

Installez live-server en tapant ce qui suit dans votre terminal :

npm install live-server

HTML Setup

Dans le build, créez un fichier HTML et nommez-le index.html. Mettez le code suivant dans ce fichier :




    
    
    
    

Clone de Wordle



Le code HTML crée un en-tête pour notre jeu et crée le conteneur pour le plateau de jeu.

Vous allez utiliser une bibliothèque JavaScript appelée Toastr pour les notifications dans le jeu et une bibliothèque CSS appelée Animate.css pour les animations du plateau.

Pour les inclure dans votre projet, ajoutez les liens suivants à l’en-tête de votre fichier index.html.

 
 

Ces liens récupèreront les CSS pour Animate.css et Toastr. Placez le code suivant dans index.html, juste avant la balise de fermeture body :

  

Ce code récupérera le JavaScript de Toastr et de jQuery (car Toastr en dépend).

Configuration du JavaScript

Votre JavaScript sera placé dans un fichier appelé script.js. Créez script.js, et placez-le dans build.

Placez ce code en haut de script.js :

importez { WORDS } de "./words.js" ;

const NUMBER_OF_GUESSES = 6 ;
let guessesRemaining = NUMBER_OF_GUESSES ;
let currentGuess = [] ;
let nextLetter = 0 ;
let rightGuessString = MOTS[Math.floor(Math.random() * MOTS.length)]
console.log(rightGuessString)

Cet extrait de code initialise les variables globales que nous utiliserons pour notre jeu et choisit un mot aléatoire dans le tableau WORDS comme bonne réponse pour ce tour. Nous enregistrons également la bonne réponse dans la console, afin de déboguer notre code si nécessaire.

La liste des mots autorisés que nous utiliserons sera codée en dur et stockée dans un tableau dans le fichier words.js. Créez words.js, dans build, et copiez le JavaScript de ce lien dans ce fichier.

Words.js devrait ressembler à ceci :

wordsjs_screenshot-1
à quoi devrait ressembler words.js

Configuration du CSS

Nommez votre fichier CSS style.css. Style.css doit également être placé dans build.

h1 {
 text-align : center ;
}

La seule configuration CSS dont nous avons besoin est un peu de code pour centrer le texte de notre en-tête

Mise en place de l’ensemble

Enfin, liez script.js en tant que module dans votre index.html, puis liez style.css.

Voir aussi :  JavaScript Uppercase - Comment mettre une chaîne en majuscules en JS avec .toUpperCase

À ce stade, votre index.html devrait ressembler à ceci :




    
    
    
    
    
    
    

Clone de Wordle

    

et votre structure de fichiers devrait ressembler à ceci :

Screenshot-from-2022-02-28-13-49-21
capture d’écran de l’arborescence des fichiers

Démarrez live-server en tapant ceci dans votre console :

construction du serveur en direct

C’est tout pour la configuration.

Comment créer le plateau de jeu

Vous allez créer le plateau de jeu en écrivant une fonction JavaScript. Appelons cette fonction initBoard. Ajoutez ce code à votre fichier script.js :

function initBoard() {
    let board = document.getElementById("game-board") ;

    for (let i = 0 ; i < NUMBER_OF_GUESSES ; i++) {
        let row = document.createElement("div")
        row.className = "letter-row" (rangée de lettres)
        
        for (let j = 0 ; j < 5 ; j++) {
            let box = document.createElement("div")
            box.className = "boîte aux lettres"
            row.appendChild(box)
        }

        board.appendChild(row)
    }
}

initBoard()

Que fait ce code ? initBoard crée une ligne pour chaque réponse donnée à l’utilisateur et crée 5 cases pour chaque ligne. Il y a une case pour chaque lettre de la réponse, et la fonction les rend toutes enfants de la ligne.

initBoard ajoute ensuite chaque ligne au conteneur du tableau. Chaque ligne reçoit la classe letter-row, et chaque boîte reçoit la classe letter-box.

Ensuite, vous allez styliser le tableau à l’aide de CSS. Placez le code suivant dans votre fichier style.css :

#game-board {
  display : flex ;
  align-items : center ;
  flex-direction : column ;
}

.letter-box {
  border : 2px solid gray ;
  border-radius : 3px ;
  margin : 2px ;
  font-size : 2.5rem ;
  font-weight : 700 ;
  hauteur : 3rem ;
  width : 3rem ;
  display : flex ;
  justify-content : center ;
  align-items : center ;
  text-transform : uppercase ;
}

.filled-box {
  border : 2px solid black ;
}

.letter-row {
  affichage : flex ;
}

Ce CSS fait plusieurs choses :

  • centre les rangées du tableau horizontalement et verticalement
  • définit une hauteur, une largeur et une bordure pour chaque case du tableau
  • crée un aspect distinct pour une case remplie d’une lettre

A ce stade, lorsque vous chargez le fichier index.html dans votre navigateur, il devrait ressembler à ceci :

screenshot1
capture d’écran du jeu

Comment créer le clavier à l’écran

La façon la plus simple de créer le clavier est d’utiliser le HTML. Ajoutez ce code à votre index.html, après le div du plateau de jeu :

Maintenant, donnez du style au balisage en ajoutant ce CSS à la fin de style.css :

#keyboard-cont {
  margin : 1rem 0 ;
  display : flex ;
  flex-direction : column ;
  align-items : center ;
}

#keyboard-cont div {
  display : flex ;
}

.second-row {
  margin : 0.5rem 0 ;
}

.keyboard-button {
  font-size : 1rem ;
  font-weight : 700 ;
  padding : 0.5rem ;
  margin : 0 2px ;
  curseur : pointeur ;
  text-transform : uppercase ;
}

Voilà à quoi devrait ressembler votre index.html dans le navigateur :

screenshot2
capture d’écran du clavier à l’écran

Comment accepter les entrées de l’utilisateur

La stratégie pour les entrées utilisateur est simple : lorsque le joueur appuie sur une touche du clavier, nous voulons placer cette touche au bon endroit sur le plateau. Pour ce faire, vous allez écouter l’événement keyup.

Lorsque le joueur appuie sur une touche, vous voulez savoir quelle était cette touche. Si la touche était une seule lettre, vous voulez la placer au bon endroit sur le tableau.

Pour savoir où se trouve le bon endroit sur le plateau, vous vérifiez le nombre de suppositions qu’il reste au joueur et le nombre de lettres qu’il a entrées jusqu’à présent.

Si la touche pressée était Entrée ou Retour arrière, vous vérifiez la réponse ou supprimez une lettre de la réponse actuelle. Toute autre touche est ignorée.

Ajoutez ce code à script.js :


document.addEventListener("keyup", (e) => {

    if (guessesRemaining === 0) {
        return
    }

    let pressedKey = String(e.key)
    si (pressedKey === "Backspace" && nextLetter !== 0) {
        deleteLetter()
        return
    }

    if (pressedKey === "Enter") {
        checkGuess()
        return
    }

    let found = pressedKey.match(/[a-z]/gi)
    if (!found || found.length > 1) {
        return
    } else {
        insertLetter(pressedKey)
    }
})

Le code utilise une expression régulière pour vérifier que la touche sur laquelle nous avons appuyé était une touche alphabétique représentant une seule lettre. Si le nom de la touche ne comporte aucune lettre (il s’agissait d’un chiffre), ou s’il comporte plusieurs lettres (Shift, Tab), nous ignorons l’événement. Sinon, nous insérons la lettre dans le tableau.

Voir aussi :  10 React Interview Questions You Should Know in 2022

insertLetter

Définissons la fonction insertLetter. Elle ressemble à ceci :

fonction insertLetter (pressedKey) {
    if (nextLetter === 5) {
        return
    }
    pressedKey = pressedKey.toLowerCase()

    let row = document.getElementsByClassName("letter-row")[6 - guessesRemaining]
    let box = row.children[nextLetter]
    box.textContent = pressedKey
    box.classList.add("filled-box")
    currentGuess.push(pressedKey)
    nextLetter += 1
}

insertLetter vérifie qu’il y a encore de la place dans le guess pour cette lettre, trouve la ligne appropriée et place la lettre dans la boîte.

deleteLetter

deleteLetter ressemble à ceci :

function deleteLetter () {
    let row = document.getElementsByClassName("letter-row")[6 - guessesRemaining]
    let box = row.children[nextLetter - 1]
    box.textContent = ""
    box.classList.remove("filled-box")
    devinette actuelle.pop()
    nextLetter -= 1
}

deleteLetter récupère la bonne ligne, trouve la dernière case et la vide, puis réinitialise le compteur nextLetter.

checkGuess

La fonction checkGuess ressemble à ceci :

function checkGuess () {
    let row = document.getElementsByClassName("letter-row")[6 - guessesRemaining]
    let guessString = ''
    let rightGuess = Array.from(rightGuessString)

    for (const val of currentGuess) {
        guessString += val
    }

    si (guessString.length != 5) {
        alert("Pas assez de lettres !")
        retournez
    }

    if (!WORDS.includes(guessString)) {
        alert("Le mot n'est pas dans la liste !")
        return
    }

    
    for (let i = 0 ; i < 5 ; i++) {
        let letterColor = ''
        let box = row.children[i]
        let letter = currentGuess[i]
        
        let letterPosition = rightGuess.indexOf(currentGuess[i])
        // La lettre est-elle dans la bonne position ?
        if (letterPosition === -1) {
            letterColor = 'grey' (gris)
        } else {
            // maintenant, la lettre est définitivement dans le mot
            // si l'indice de la lettre et l'indice de la bonne estimation sont les mêmes
            // la lettre est dans la bonne position 
            if (currentGuess[i] === rightGuess[i]) {
                // coloration verte 
                letterColor = 'green' (couleur de la lettre)
            } else {
                // teinte jaune de la boîte
                letterColor = 'yellow' (couleur de la lettre)
            }

            rightGuess[letterPosition] = "#"
        }

        let delay = 250 * i
        setTimeout(()=> {
            //d'ombrager la boîte
            box.style.backgroundColor = letterColor
            shadeKeyBoard(lettre, letterColor)
        }, delay)
    }

    si (guessString === rightGuessString) {
        alert("Vous avez deviné juste ! La partie est terminée !")
        reste des réponses = 0
        retournez à
    } else {
        guessesRemaining -= 1 ;
        devin actuel = [] ;
        lettre suivante = 0 ;

        si (reste des réponses === 0) {
            alert("Vous n'avez plus d'indices, la partie est terminée !")
            alert(`Le bon mot était : "${rightGuessString}"`)
        }
    }
}

checkGuess est assez longue, alors décomposons-la. Elle fait plusieurs choses :

  • Assure-toi que le mot à deviner comporte 5 lettres
  • Vérifie que le mot deviné est une liste valide
  • Vérifie chaque lettre du mot et les nuance
  • Indique à l’utilisateur la fin du jeu

checkGuess utilise un algorithme simple pour décider de la couleur à donner à chaque lettre :

  1. Vérifie si la lettre se trouve dans le bon mot
  2. Si la lettre ne se trouve pas dans le mot, la lettre est grisée
  3. Si la lettre est dans le mot, vérifiez si elle est dans la bonne position
  4. Si la lettre est dans la bonne position, elle devient verte
  5. Sinon, coloration en jaune

checkGuess utilise une fonction shadeKeyboard pour colorer les touches du clavier à l’écran, mais elle n’est pas encore définie. Faisons-le maintenant.

shadeKeyboard

function shadeKeyBoard(letter, color) {
    for (const elem of document.getElementsByClassName("keyboard-button")) {
        if (elem.textContent === lettre) {
            let oldColor = elem.style.backgroundColor
            if (oldColor === 'green') {
                return
            } 

            if (oldColor === 'yellow' && color !== 'green') {
                return
            }

            elem.style.backgroundColor = couleur
            pause
        }
    }
}

shadeKeyBoard reçoit la lettre du clavier à l’écran que nous voulons colorer et la couleur que nous voulons lui donner. Voici l’algorithme :

  1. Trouver la clé qui correspond à la lettre donnée
  2. Si la clé est déjà verte, ne faites rien
  3. Si la clé est actuellement jaune, ne lui permettez que de devenir verte
  4. Sinon, nuance la clé passée à la fonction

Comment ajouter des notifications

Ensuite, vous allez remplacer les alertes JavaScript dans checkGuess par des toasts, en utilisant Toastr.

Passez en revue checkGuess, et remplacez toutes les alertes qui informent l’utilisateur d’une erreur par des appels à toastr .error().

L’alerte qui informe l’utilisateur d’une bonne réponse doit être remplacée par toastr.success(), et l’alerte qui informe l’utilisateur de la bonne réponse doit être remplacée par toastr.info().

Voici à quoi devrait ressembler checkGuess une fois que vous aurez terminé :

function checkGuess () {
    let row = document.getElementsByClassName("letter-row")[6 - guessesRemaining]
    let guessString = ''
    let rightGuess = Array.from(rightGuessString)

    for (const val of currentGuess) {
        guessString += val
    }

    si (guessString.length != 5) {
        toastr.error("Pas assez de lettres !")
        return
    }

    if (!WORDS.includes(guessString)) {
        toastr.error("Le mot n'est pas dans la liste !")
        return
    }

    
    for (let i = 0 ; i < 5 ; i++) {
        let letterColor = ''
        let box = row.children[i]
        let letter = currentGuess[i]
        
        let letterPosition = rightGuess.indexOf(currentGuess[i])
        // la lettre est-elle dans la bonne position ?
        if (letterPosition === -1) {
            letterColor = 'grey' (gris)
        } else {
            // maintenant, la lettre est définitivement dans le mot
            // si l'indice de la lettre et l'indice de la bonne estimation sont les mêmes
            // la lettre est dans la bonne position 
            if (currentGuess[i] === rightGuess[i]) {
                // coloration verte 
                letterColor = 'green' (couleur de la lettre)
            } else {
                // teinte jaune de la boîte
                letterColor = 'yellow' (couleur de la lettre)
            }

            rightGuess[letterPosition] = "#"
        }

        let delay = 250 * i
        setTimeout(()=> {
            //d'ombrager la boîte
            box.style.backgroundColor = letterColor
            shadeKeyBoard(lettre, letterColor)
        }, delay)
    }

    si (guessString === rightGuessString) {
        toastr.success("Vous avez deviné juste ! La partie est terminée !")
        guessRemaining = 0
        retournez à
    } else {
        guessesRemaining -= 1 ;
        currentGuess = [] ;
        lettre suivante = 0 ;

        if (guessesRemaining === 0) {
            toastr.error("Vous n'avez plus de mots à deviner, la partie est terminée")
            toastr.info(`Le bon mot était : "${rightGuessString}"`)
        }
    }
}

Comment faire en sorte que le clavier à l’écran génère des entrées ?

Pour faire fonctionner votre clavier à l’écran, il vous suffit d’envoyer un événement key up chaque fois que vous cliquez sur une touche de votre clavier à l’écran. Pour ce faire, ajoutez ce code à script.js :

document.getElementById("clavier-cont").addEventListener("click", (e) => {
    const target = e.target
    
    if (!target.classList.contains("keyboard-button")) {
        return
    }
    let key = target.textContent

    if (key === "Del") {
        key = "Backspace" (retour arrière)
    } 

    document.dispatchEvent(new KeyboardEvent("keyup", {'key' : key}))
})

Cette fonction est à l’écoute d’un clic sur le conteneur du clavier ou sur l’un de ses enfants (les boutons). Si l’élément cliqué n’est pas un bouton, nous quittons la fonction. Sinon, nous envoyons un événement key up correspondant à la touche cliquée.

Voir aussi :  parseInt() in JavaScript - Exemple de conversion d'une chaîne de caractères en un nombre entier de caractères

Comment ajouter une animation

Nous avons déjà installé animate.css, alors écrivons maintenant une fonction JavaScript pour l’utiliser.

const animateCSS = (element, animation, prefix = 'animate__') =>
  // Nous créons une Promise et la retournons
  new Promise((resolve, reject) => {
    const animationName = `${prefix}${animation}` ;
    // const node = document.querySelector(element) ;
    const node = element
    node.style.setProperty('--animate-duration', '0.3s') ;
    
    node.classList.add(`${prefix}animated`, animationName) ;

    // Lorsque l'animation se termine, nous nettoyons les classes et résolvons la Promise
    function handleAnimationEnd(event) {
      event.stopPropagation() ;
      node.classList.remove(`${prefix}animated`, animationName) ;
      resolve('Animation terminée') ;
    }

    node.addEventListener('animationend', handleAnimationEnd, {once : true}) ;
}) ;

Cette fonction provient de la page d’accueil d’Animate.css. Elle applique des classes à la cible de l’animation pour déclencher une animation, et lorsque l’animation se termine, elle supprime les classes qu’elle a ajoutées.

La fonction renvoie une promesse pour vous permettre d’effectuer des actions qui ne doivent être exécutées qu’après la fin de l’animation, mais vous n’aurez pas besoin de mettre cela en œuvre dans ce tutoriel.

Maintenant que nous disposons d’une fonction permettant d’animer n’importe quel élément, appliquons-la. Revenez à notre fonction insertLetter et ajoutez la ligne suivante avant de remplacer le textContent de box:

    animateCSS(box, "pulse")

Voici à quoi insertLetter devrait ressembler maintenant :

function insertLetter (pressedKey) {
    if (nextLetter === 5) {
        return
    }
    pressedKey = pressedKey.toLowerCase()

    let row = document.getElementsByClassName("letter-row")[6 - guessesRemaining]
    let box = row.children[nextLetter]
    animateCSS(box, "pulse")
    box.textContent = pressedKey
    box.classList.add("filled-box")
    currentGuess.push(pressedKey)
    nextLetter += 1
}

Le code indique à insertLetter de pulser rapidement chaque case, juste avant de la remplir avec une lettre.

Ensuite, vous voulez animer chaque lettre d’une proposition pendant que vous la vérifiez.

Revenez en arrière et modifiez checkGuess, comme suit :

let delay = 250 * i
setTimeout(()=> {
    //flip box
    animateCSS(boîte, 'flipInX')
    //obscurcir la boîte
    box.style.backgroundColor = letterColor
    ombrageKeyBoard(lettre, lettreCouleur)
}, delay)

Ce code ajoute une animation pour retourner chaque case verticalement, juste avant de changer la couleur.

Conclusion

Ce tutoriel est terminé. Vous venez de construire un clone de Wordle, et j’espère que vous vous êtes amusé en chemin. Vous pouvez trouver le code complet sur le dépôt GitHub de ce projet.