Maison  >  Article  >  interface Web  >  JavaScript Essentials : partie Mastermind en Javascript)

JavaScript Essentials : partie Mastermind en Javascript)

Barbara Streisand
Barbara Streisandoriginal
2024-10-30 17:09:02869parcourir

JavaScript Essentials: Part Mastermind in Javascript)

Dans cette section, nous allons implémenter un jeu appelé Mastermind en JavaScript. Ce développement de jeu couvrirait un grand nombre des concepts dont nous avons discuté jusqu'à présent. Nous définirons des fonctions, leur passerons des arguments, utiliserons des variables et utiliserons des boucles et des instructions if. Nous examinerions brièvement un autre concept autour des fonctions, connu sous le nom d'IIFE, Immédiatement Invoked Function Expression. Nous verrons également comment prendre en compte les entrées de l'utilisateur via la ligne de commande. À ce stade, il ne s’agit que d’applications console.

Vous pouvez référencer une implémentation similaire ici, Master mind in python

Mastermind est un jeu de société simple qui utilise des couleurs mais nous utiliserions plutôt des chiffres.

Résumé : Derrière une barre se trouvent quatre couleurs proposées par un seul joueur. L'autre joueur ne peut pas voir les couleurs du premier joueur. Les couleurs du premier joueur sont appelées le créateur de code et les couleurs de l'autre joueur sont le briseur de code. Le déchiffreur de code a, inclusivement, entre 2 et 12 tentatives pour deviner les créateurs du code. Le nombre de tentatives doit être pair.

Mise en œuvre

  • Créez un dossier appelé mastermind sur votre PC (ou là où vous mettez vos projets) et dans mastermind, initialisez un projet de nœud en utilisant npm init -y (sur la ligne de commande) . Je suis sur une machine Linux donc c'est ainsi que je vais mettre en place mon projet.

    • Ouvrez mon terminal, exécutez, cd pour me déplacer vers le dossier utilisateur.
    • Ensuite, cd ~/projects. projets, c'est là que je garde mes projets.
    • Ensuite, mkdir mastermind et cd mastermind pour créer le dossier mastermind et accéder à ce dossier.
    • Initialisez un projet de nœud avec npm init -y. Un fichier package.json sera créé.
    • Créez app.js avec touch app.js.
    • Écrivez console.log("Mastermind") dans app.js et exécutez-le avec le nœud app.js. Je m'attends à voir Mastermind sinon j'ai un problème avec ma configuration.
  • Le point de départ (d'entrée) de ce jeu sera dans App, une fonction. Créons une fonction appelée App et ajoutons console.log("App"). On peut alors appeler App() et exécuter le code avec le nœud app.js. Je ne vous dirai pas d'exécuter votre code, mais c'est quelque chose que vous devriez faire pendant que vous codez. Ceci est le contenu actuel de mon fichier app.js.

console.log("Mastermind");

function App() {
  console.log("App");
}

App();
  • Quand le jeu commence

    • l'utilisateur saisit le nombre de tours qu'il souhaite jouer et la valeur saisie doit être validée
    • l'utilisateur choisit d'autoriser ou non les doublons
    • quelque part, le créateur de code est généré aléatoirement
    • l'utilisateur a entré le disjoncteur de code
    • le briseur de code est comparé au créateur de code et un indice est donné s'il ne correspond pas
    • dans la foulée, on fait le nombre de tours
    • et pour rendre cela plus ludique, nous avons mis l'ensemble de l'application dans une boucle infinie
  • Implémentons une fonction pour générer des nombres aléatoires pour la création du code, définissant ainsi des valeurs aléatoires pour le créateur de code.

  • Tout d’abord, nous avons besoin d’un moyen de générer des nombres aléatoires. Pour ne pas interférer avec le code dans app.js, créons un autre fichier appelé scratch_pad.js et dans ce fichier nous expérimentons.

  • JavaScript propose un moyen simple de générer des nombres aléatoires en appelant Math.random(). Dans le bloc-notes, enregistrons 4 nombres aléatoires à l'aide d'une construction en boucle.

console.log("Mastermind");

function App() {
  console.log("App");
}

App();
  • ce que nous voulons, ce sont des entiers (des nombres comme) 0, 1, 2, ..., 9 et non des décimaux. Nous pouvons multiplier la valeur renvoyée par Math.random() par 10 et nous aurions x.something où x sera désormais dans 1,2,3,...,9. N'oubliez pas que ces expériences sont toutes réalisées sur le bloc-notes. Essayez-le.

  • Ce que nous voulons, c'est un nombre avant le point, la partie entière du nombre. Nous pouvons écrire du code pour convertir le nombre en chaîne, puis le diviser par le "." et obtenez le premier élément. Cependant, il existe une fonctionnalité pour cela appelée étage que nous pouvons utiliser.

for (let i = 0; i < 4; i++) {
  console.log(Math.random());
}
// 0.10037268097853191
// 0.20981624777230534
// 0.47828165742292583
// 0.8160883929470153
  • La façon dont cela fonctionne est que, si nous voulons obtenir des nombres aléatoires entre un certain nombre min et max, où max est supérieur à min, alors nous pouvons faire, min Math.floor(Math.random() * (max - min 1)). min est la valeur minimale attendue et max est la valeur maximale attendue. Dans notre cas, notre valeur minimale est 0 et notre valeur maximale est 9.
  • Ceci est mon extrait pour générer le nombre aléatoire. J'ai ajouté des paramètres à la fonction car je ne veux pas que la fonction ait un état interne.
for (let i = 0; i < 4; i++) {
  console.log(Math.floor(Math.random() * 10));
}
// 4
// 7
// 3
// 4
  • À ce stade, nous pouvons maintenant retourner dans notre app.js et ajouter la fonction ci-dessus pour générer les nombres aléatoires pour le créateur de code. Placez-le au-dessus de la fonction App.

  • D'après le résumé, le nombre de couleurs utilisées est de 4. Nous devons donc générer 4 nombres pour le créateur de code. Nous devons également déterminer si les doublons sont autorisés. Retour au bloc-notes.

  • Nous avons des fonctions, des instructions if et else, les boucles for et while, etc. Ces constructions ont toutes un bloc ou un corps. Les variables initialisées dans ces blocs peuvent être utilisées à l'intérieur du bloc et non à l'extérieur de celui-ci. C'est ce qu'on appelle la portée d'une variable. Une variable peut donc exister dans la portée globale, ce qui signifie que cette variable peut être utilisée ou évaluée partout. Quand on déclare une variable dans un bloc. La variable devient interne ou limitée dans cette portée. Exécutez ceci dans le bloc-notes.

console.log("Mastermind");

function App() {
  console.log("App");
}

App();
  • Maintenant, mettez à jour ceci en initialisant une variable,x, dans l'instruction if, console.log(x) en dehors du bloc if et exécutez votre bloc-notes. Vous devriez obtenir une erreur similaire à celle-ci.
for (let i = 0; i < 4; i++) {
  console.log(Math.random());
}
// 0.10037268097853191
// 0.20981624777230534
// 0.47828165742292583
// 0.8160883929470153

À ce stade, je souhaite attirer votre attention sur l'idée des scopes.

  • Lors de la génération du créateur de code, nous voulons savoir si les doublons sont autorisés et à ce stade, nous savons que le créateur de code est un tableau de nombres (ou de chaînes numériques). Commençons par le bloc-notes. Nous voulons implémenter une fonction qui prend un argument booléen indiquant si les doublons sont autorisés. La fonction ajoutera (poussera) quatre nombres dans le créateur de code, mais avant cela, nous devons vérifier si les doublons sont autorisés et gérer le cas échéant.
for (let i = 0; i < 4; i++) {
  console.log(Math.floor(Math.random() * 10));
}
// 4
// 7
// 3
// 4
  • nous avons également écrit notre code de telle manière que le créateur de code ne soit pas accessible globalement dans la fonction créateur de code. Cela renverra donc le créateur de code à la place.
function generateRandomNumbersBetween(min, max) {
  return min + Math.floor(Math.random() * (max - min + 1));
}

for (let i = 0; i < 4; i++) {
  console.log(generateRandomNumbersBetween(0, 9));
}
  • Dans app.js nous pouvons maintenant ajouter la fonction de création de code et une variable pour la création du code.
  • Revenons maintenant au bloc-notes. Nous voulons prendre en compte les commentaires de l'utilisateur depuis le terminal. Javascript a également un moyen de le faire. Essayez cet extrait.
const HP = 100;

if (true) {
  console.log("IF BLOCK::", HP);
}

console.log("End::", HP);

// IF BLOCK:: 100
// End:: 100
  • Il n'y a aucun problème avec cette approche consistant à prendre en compte les commentaires des utilisateurs. C'est juste que nous devons utiliser une fonction de rappel et il n'y a aucun moyen de transmettre l'entrée saisie à la portée externe de la fonction de rappel de readlineOInstance.question.

  • A quoi penses-tu ? Essayez-le dans le "bloc-notes". Si vous envisagez de déclarer une variable dans la portée externe de readlineOInstance.question pour lui attribuer l'entrée saisie, alors c'est une bonne approche mais... Essayez-la quand même.

  • Vous souvenez-vous du concept de Promesses ? Nous pouvons utiliser la promesse ici et résoudre l'entrée. Cependant, nous devons mettre en pratique l’ensemble du processus. Il y a quelques parties de readlineOInstance.question qui a un en-tête similaire à question(query: string, callback: (answer: string) => void. La requête est la requête (ou l'invite) adressée à l'utilisateur et le rappel indique comment nous gérons la collection d'entrées. Puisque nous pourrions réutiliser la même fonction quelque part plus tard, nous passerions la requête en argument.

    console.log("Mastermind");
    
    function App() {
      console.log("App");
    }
    
    App();
    
    • Nous pouvons maintenant ajouter la fonction getInput au app.js. N'oubliez pas l'import, const readline = require("readline"). Le contenu de app.js devrait être similaire à l'extrait ci-dessous.
    for (let i = 0; i < 4; i++) {
      console.log(Math.random());
    }
    // 0.10037268097853191
    // 0.20981624777230534
    // 0.47828165742292583
    // 0.8160883929470153
    
    • Nous demandons maintenant à l'utilisateur de saisir le nombre de tours et si un doublon est autorisé. On sait que le nombre de tours doit être pair et compris entre 2 et 12. Nous allons implémenter une fonction pour valider une valeur (nombre) paire et comprise entre 2 et 12. Elle renverra un booléen. Un nombre est pair lorsque le nombre modulo 2 est nul. (c'est-à-dire nombre % 2 == 0).
    for (let i = 0; i < 4; i++) {
      console.log(Math.floor(Math.random() * 10));
    }
    // 4
    // 7
    // 3
    // 4
    
    • Dans le corps de la fonction App, nous pouvons demander les entrées et les valider. Nous demanderons continuellement la saisie appropriée du nombre de tours. Pour les valeurs en double dans le code, lorsque l'utilisateur saisit autre chose que ce qui est attendu, nous supposerons que l'utilisateur ne veut pas de doublons. Nous utiliserons une boucle while et définirons la condition sur true et ne s'arrêterons que lorsque les tours sont valides. Cependant, en utilisant un try et un catch (pour la gestion des erreurs), lorsque l'utilisateur entre une valeur invalide, nous enregistrons un message indiquant que la valeur saisie est invalide. Essayez-le.
    function generateRandomNumbersBetween(min, max) {
      return min + Math.floor(Math.random() * (max - min + 1));
    }
    
    for (let i = 0; i < 4; i++) {
      console.log(generateRandomNumbersBetween(0, 9));
    }
    

    Exécutez app.js et interagissez avec lui. Il s'agit d'un résultat similaire lors de l'interaction.

    const HP = 100;
    
    if (true) {
      console.log("IF BLOCK::", HP);
    }
    
    console.log("End::", HP);
    
    // IF BLOCK:: 100
    // End:: 100
    
    • Nous avons pris le nombre de tours et la valeur de duplication. Nous pouvons maintenant générer le créateur de code. Pour ce faire, nous pouvons appeler la fonction generateCodeMaker et lui transmettre la valeur de l'option de duplication (ou la laisser car elle est fausse par défaut).
     IF BLOCK:: 100
     /home/Projects/mastermind/scratch_pad.js:8
     console.log(x)
        ^
    
     ReferenceError: x is not defined
        at Object.<anonymous> (/home/Projects/mastermind/scratch_pad.js:8:13)
        at Module._compile (node:internal/modules/cjs/loader:1469:14)
        at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
        at Module.load (node:internal/modules/cjs/loader:1288:32)
        at Module._load (node:internal/modules/cjs/loader:1104:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
        at node:internal/main/run_main_module:28:49
    
     Node.js v20.17.0
    
    • Nous pouvons maintenant demander à l'utilisateur le briseur de code et le comparer au créateur de code. Le briseur de code est également un tableau de nombres. Nous ajouterons également un indice permettant à l'utilisateur de savoir à quelle distance il se trouve d'un code particulier. Donc, si le code du briseur de code est supérieur au code du créateur de code, nous disons plus. Nous disons égaux lorsqu'ils sont égaux et sinon nous disons moins lorsque le code du briseur de code est inférieur au code du briseur de code. Passons au bloc-notes.
    • Nous allons créer une fonction qui prendra un tableau numérique de 4 éléments puis comparera la saisie de l'utilisateur (code breaker).
    // a global code maker that is accessible inside any other scope
    let CODE_MAKER = [];
    
    function generateRandomNumbersBetween(min, max) {
      return min + Math.floor(Math.random() * (max - min + 1));
    }
    
    function generateCodeMaker(isDuplicatesAllowed = false) {
      let counter = 0;
    
      while (counter < 4) {
        let code = generateRandomNumbersBetween(0, 9);
    
        if (isDuplicatesAllowed) {
          CODE_MAKER.push(code);
          counter += 1;
        } else if (!CODE_MAKER.includes(code)) {
          CODE_MAKER.push(code);
          counter += 1;
        }
      }
    }
    
    console.log(CODE_MAKER);
    generateCodeMaker(true);
    console.log(CODE_MAKER);
    
    // reset the code maker
    CODE_MAKER = [];
    generateCodeMaker(false);
    console.log(CODE_MAKER);
    // []
    // [ 6, 6, 0, 9 ]
    // [ 2, 5, 0, 8 ]
    
    • Nous avons une variable pour gérer les astuces et une valeur pour chaque code lié au créateur et au disjoncteur de code.
    • Nous transmettons le créateur de code à la fonction pour le comparer à l'entrée de l'utilisateur.
    • Nous mettons à jour les astuces pour indiquer à l'utilisateur comment mettre à jour les valeurs dans le disjoncteur de code
    • Nous pouvons maintenant ajouter les fonctions HINTS et compareCode au app.js. C'est le moment idéal pour exécuter votre app.js, au-dessus de la fonction App.

    • Maintenant que nous avons implémenté une fonction pour comparer le créateur de code et le briseur de code, nous pouvons maintenant mettre cela en boucle pour tenir compte des tours (tours = nombre de fois pour jouer au jeu). Donc, si le nombre de tours est de 6, alors le jeu serait joué 6 fois mais nous devrons terminer le jeu lorsque l'utilisateur devine correctement tous les codes, c'est-à-dire lorsque les valeurs dans les HINTS sont toutes des 0. Ainsi, lorsque nous comptons le nombre de 0 dans HINTS et qu'il est 4, nous pouvons terminer le jeu et dire que l'utilisateur a gagné.

    console.log("Mastermind");
    
    function App() {
      console.log("App");
    }
    
    App();
    
    • Le nombre de tours est réduit et on saurait si l'utilisateur a gagné ou non si le nombre de tours n'est pas 0.
    for (let i = 0; i < 4; i++) {
      console.log(Math.random());
    }
    // 0.10037268097853191
    // 0.20981624777230534
    // 0.47828165742292583
    // 0.8160883929470153
    
    • Quelques sorties lorsque vous exécutez le programme
    for (let i = 0; i < 4; i++) {
      console.log(Math.floor(Math.random() * 10));
    }
    // 4
    // 7
    // 3
    // 4
    
    • Quand j'appuie sur Entrée
    function generateRandomNumbersBetween(min, max) {
      return min + Math.floor(Math.random() * (max - min + 1));
    }
    
    for (let i = 0; i < 4; i++) {
      console.log(generateRandomNumbersBetween(0, 9));
    }
    
    • Je suppose que nous pouvons profiter de notre travail acharné jusqu’à présent. J'ai environ 130 lignes. Combien en avez-vous ?

    • Voici le code complet

    const HP = 100;
    
    if (true) {
      console.log("IF BLOCK::", HP);
    }
    
    console.log("End::", HP);
    
    // IF BLOCK:: 100
    // End:: 100
    

    Y a-t-il place à amélioration ?

    Même s'il s'agit d'une simple application console/terminal/textuelle, nous pouvons faire plus à ce sujet.

    • Nous pouvons remplacer toutes les constantes telles que les chaînes et les nombres.
    • Nous pourrions extraire (refactoriser) l'entrée du disjoncteur de code et la diviser, hors du code de comparaison, puis transmettre le disjoncteur de code et le créateur de code comme arguments. Nous pourrions même laisser la fonction renvoyer les indices plutôt que d'y accéder globalement. Nous allons créer une nouvelle variable d'indices et la retourner. CompareCode renverra donc les indices attribués à la variable indices.
     IF BLOCK:: 100
     /home/Projects/mastermind/scratch_pad.js:8
     console.log(x)
        ^
    
     ReferenceError: x is not defined
        at Object.<anonymous> (/home/Projects/mastermind/scratch_pad.js:8:13)
        at Module._compile (node:internal/modules/cjs/loader:1469:14)
        at Module._extensions..js (node:internal/modules/cjs/loader:1548:10)
        at Module.load (node:internal/modules/cjs/loader:1288:32)
        at Module._load (node:internal/modules/cjs/loader:1104:12)
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
        at node:internal/main/run_main_module:28:49
    
     Node.js v20.17.0
    
    • nous pouvons également envelopper console.clear() dans une fonction.
    • on peut laisser le programme ralentir avant le prochain match
    • nous pouvons extraire HINTS.filter((value) => 0 === value).length === 4 en fonction. Le but est de vérifier si le briseur de code a deviné correctement le créateur du code.
    • on peut aussi faire la même chose pour déclarer qui a gagné la partie
    // a global code maker that is accessible inside any other scope
    let CODE_MAKER = [];
    
    function generateRandomNumbersBetween(min, max) {
      return min + Math.floor(Math.random() * (max - min + 1));
    }
    
    function generateCodeMaker(isDuplicatesAllowed = false) {
      let counter = 0;
    
      while (counter < 4) {
        let code = generateRandomNumbersBetween(0, 9);
    
        if (isDuplicatesAllowed) {
          CODE_MAKER.push(code);
          counter += 1;
        } else if (!CODE_MAKER.includes(code)) {
          CODE_MAKER.push(code);
          counter += 1;
        }
      }
    }
    
    console.log(CODE_MAKER);
    generateCodeMaker(true);
    console.log(CODE_MAKER);
    
    // reset the code maker
    CODE_MAKER = [];
    generateCodeMaker(false);
    console.log(CODE_MAKER);
    // []
    // [ 6, 6, 0, 9 ]
    // [ 2, 5, 0, 8 ]
    
    • Mettez toutes les fonctions qui peuvent être autonomes dans leur propre fichier,functions.js et exportez-les. Nous pouvons ensuite refactoriser des fonctions autonomes qui dépendent d'une variable globale, puis transmettre ces données comme argument à la fonction à l'aide d'un paramètre.
    • Nous pouvons même avoir un fichier séparé pour
    // a global code maker that is accessible inside any other scope
    let CODE_MAKER = [];
    
    function generateRandomNumbersBetween(min, max) {
      return min + Math.floor(Math.random() * (max - min + 1));
    }
    
    function generateCodeMaker(isDuplicatesAllowed = false) {
      let counter = 0;
      let codeMaker = [];
    
      while (counter < 4) {
        let code = generateRandomNumbersBetween(0, 9);
    
        if (isDuplicatesAllowed) {
          codeMaker.push(code);
          counter += 1;
        } else if (!codeMaker.includes(code)) {
          codeMaker.push(code);
          counter += 1;
        }
      }
    
      return codeMaker;
    }
    
    console.log(CODE_MAKER);
    CODE_MAKER = generateCodeMaker(true);
    console.log(CODE_MAKER);
    
    CODE_MAKER = generateCodeMaker(false);
    console.log(CODE_MAKER);
    
    // []
    // [ 6, 6, 0, 9 ]
    // [ 2, 5, 0, 8 ]
    

    Conclusion

    Nous avons utilisé tout ce que nous avons appris dans ce projet et il y a bien plus encore. J'ai mentionné que nous pourrions regrouper certaines fonctions et les exporter. Pour cela, nous verrons comment importer et exporter en Javascript. Je vais vous proposer un autre projet qui, je pense, vous sera utile. C'est la fin du jeu du cerveau et j'espère que vous ferez également du refactoring car il y a beaucoup d'endroits qui doivent être refactorisés. Bonne chance...

    const readline = require("readline");
    
    const readlineOInstance = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });
    
    readlineOInstance.question("Enter code maker: ", (userInput) => {
      console.clear();
      console.log(`INPUT: ${userInput}`);
      readlineOInstance.close();
    });
    

    Sources

    • wiki-play-mastermind
    • cerveau-wikipedia
    • Maître l'esprit en python

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn