Aller au contenu

Soirée quiz dans le terminal avec Enquirer

Passons de la théorie à la pratique en créant votre propre quiz dans le terminal.

Image by macrovector on Freepik

Dans un précédent article, nous avons exploré les possibilités offertes par la bibliothèque Enquirer. Cet article fait suite à cette exploration initiale. Nous allons nous lancer dans la création d'un quiz interactif en ligne de commande.

Avant toute chose, nous allons installer deux nouvelles dépendances en exécutant npm install ansi-colors chalk@4.1.2. À partir de la version 5, chalk est passé au format ESM (Modules ECMAScript). Puisque j'ai opté pour le CommonJS dans le premier article, je vais donc me contenter de la version 4. Passer à ESM ? Peut-être une autre fois…

Questions pour un dev !

Pour mettre en place notre quiz, nous allons utiliser la méthode prompt qui a l'avantage d'accepter une liste de questions, contrairement à la classe Quiz.

const { prompt } = require("enquirer");

prompt([
    {
        type: "quiz",
        name: "countries",
        message: 'How many countries are there in the world?',
        choices: ['165', '175', '185', '195', '205'],
        correctChoice: 3
    },
    {
        type: "quiz",
        name: "math",
        message: 'What is 9 + 10?',
        choices: ['19', '20', '21'],
        correctChoice: 0
    }
]).then((answer) => console.log("Answer:", answer)).catch(console.error);

// Answer: {
//     countries: { selectedAnswer: '165', correctAnswer: '195', correct: false },
//     math: { selectedAnswer: '19', correctAnswer: '19', correct: true }
// }

quiz.cjs

Une question a besoin d'un type qui sera quiz puisqu'on veut créer un quiz, un name, un message qui est la question pour l'utilisateur, choices qui est une liste de propositions et enfin correctChoice, qui correspond à l'indice dans le tableau choices de la bonne réponse.

Si vous lancez le quiz dans le terminal avec node quiz.cjs, vous allez sans doute trouver les contrôles très rapidement : et pour naviguer parmi les propositions et Entrée pour valider votre choix.

À la fin de toutes les questions, on récupère un objet avec pour chaque question le choix de l'utilisateur, la réponse attendue correctAnswer et un booléen indiquant si l'utilisateur a choisi la bonne réponse ou non.

Pour alimenter notre quiz avec des questions plus intéressantes, on va s'appuyer sur l'API de l'Open Trivia Database. Ce service est libre (pas besoin de clé d'API) et gratuit. On peut sélectionner le nombre de questions, le thème et la difficulté.

const loadQuestions = async () => {
    const res = await fetch(TRIVIA_URL);
    if (res.ok) {
        const data = await res.json();
        const questions = data.results.map((question, index) => {
            const choices = [...question.incorrect_answers, question.correct_answer];
            choices.sort(() => Math.random() - 0.5);
            return {
                type: "quiz",
                name: `Question ${index + 1}`,
                message: question.question,
                choices,
                correctChoice: choices.indexOf(question.correct_answer)
            }
        })
        return questions
    }
};

quiz.cjs

La méthode ci-dessus va récupérer des questions à partir d'Open Trivia Database et les transformer au format attendu par Enquirer. Pour éviter d'avoir la réponse toujours au même endroit dans la liste des propositions, je rajoute un peu d'aléatoire avec Math.random().

Maintenant que nous avons des questions plus variées et au bon format, nous pouvons les soumettre au prompt.

const runQuiz = async () => {
    const questions = await loadQuestions();
    const answers = await prompt(questions);
}

runQuiz().catch(console.error)

quiz.cjs

Comme nous avons vu plutôt, answers est un objet dont les clés sont les noms des questions et les valeurs le résultat. Comme sortie finale, nous allons afficher le score ainsi que les réponses incorrectes afin que le joueur dorme moins bête cette nuit.

On va importer les modules ansi-colors et chalk pour l'affichage du score. En itérant sur les réponses à la fin du questionnaire, on incrémente le score quand la réponse est correcte et on donne la correction dans le cas contraire.

const { green, red } = require('ansi-colors');
const { bold, strikethrough } = require('chalk');

const runQuiz = async () => {
    let score = 0;
    const questions = await loadQuestions();
    const answers = await prompt(questions);
    Object.entries(answers).forEach(([questionName, result]) => {
        if(result.correct) {
            score++;
        } else {
            console.log(`${questionName} : ${strikethrough(red(result.selectedAnswer))} ${green(result.correctAnswer)}`);
        }
    });
    console.log(`${bold("Score")} : ${score}/${questions.length}`);
}

runQuiz().catch(console.error)

quiz.cjs

Voici ce que donne notre quiz dans mon terminal.

De nouveaux défis

Nous avons réussi à coder un quiz interactif et fonctionnel ! Cependant, il y a encore de la place à l'innovation et à l'optimisation.

Par exemple, le point d'interrogation qui préfixe la question est systématiquement remplacé par une coche dès qu'une réponse est sélectionnée. Bien que cela indique que l'input de l'utilisateur a été reçu, cela pourrait prêter à confusion en suggérant que la réponse choisie est correcte, même si ce n'est pas le cas.

De plus, pourquoi attendre la fin du questionnaire pour révéler les bonnes réponses ? Nous pourrions améliorer l'expérience utilisateur en remplaçant immédiatement les réponses sélectionnées en bleu par la correction en vert ou en rouge.

Si cela vous inspire, je vous laisse regarder comment ajouter la fonction onSubmit() dans les questions que l'on génère, voire comment créer votre propre prompt en héritant des classes Quiz ou SelectPrompt.

Et si le terminal n'est pas assez pour vous, et que vous aspirez à créer une interface graphique élégante et réactive, n'attendez pas à quai. Le train ViteJS est prêt au départ, et vous ne voudrez pas le manquer !

ViteJS, ne ratez pas le train !
ViteJS, dernier né de Evan You, est le bolide des outils de build front-end. Propulsant votre développement avec des fichiers servis à la demande et optimisé par Rollup en production, c’est le compagnon de route rêvé. ViteJS, c’est la promesse d’un développement web à grande vitesse.

Ci-dessous, vous trouverez le code complet du fichier pour une consultation complète.

const { prompt } = require("enquirer");
const { green, red } = require('ansi-colors');
const { bold, strikethrough } = require('chalk');
const TRIVIA_URL = ''; 		// URL à générer via l'Open Trivia DB

const loadQuestions = async () => {
    const res = await fetch(TRIVIA_URL);
    if (res.ok) {
        const data = await res.json();
        const questions = data.results.map((question, index) => {
            const choices = [...question.incorrect_answers, question.correct_answer];
            choices.sort(() => Math.random() - 0.5);
            return {
                type: "quiz",
                name: `Question ${index + 1}`,
                message: question.question,
                choices,
                correctChoice: choices.indexOf(question.correct_answer)
            }
        })
        return questions
    }
}

const runQuiz = async () => {
    let score = 0;
    const questions = await loadQuestions();
    const answers = await prompt(questions);
    Object.entries(answers).forEach(([questionName, result]) => {
        if(result.correct) {
            score++;
        } else {
            console.log(`${questionName} : ${strikethrough(red(result.selectedAnswer))} ${green(result.correctAnswer)}`);
        }
    });
    console.log(`${bold("Score")} : ${score}/${questions.length}`);
}

runQuiz().catch(console.error)

quiz.cjs

Dernier