Source: QuizzerWithDSA.js

const { Quizzer } = require('./Quizzer');
const { Maid, increasePerformance } = require('./utils');
const constants = require('./constants');
const DSATrainer = require('./dsa-cli/dsa-trainer');
const DEBUG = false;
const { cloze_problems_list } = require('./dsa-cli/cloze');
const DSAConstants = require('./dsa-cli/constants');
const { getProblemsData, getRandomProblem, copyFileToTemp } = require('./data-science-cli/index');

const { TermScheduler } = require('./termScheduler');
const settings = require('./settings');
/**
 * This class also supports DSATrainer Implementation.
 */
class QuizzerWithDSA extends Quizzer {
    constructor(questions, enabled, masterDeck) {
        super(questions, enabled, masterDeck);
        this.dsaTrainer = new DSATrainer({
            skip_problems: ["hello-world", "simple-sum"]
        });
    }

    async askQuestion({ ask_until_one_is_correct = true, disable_math = false, disable_dsa = false, increase_performance = true } = {}) {
        let exit = false;
        let problem_types = ['math', 'term'];
        problem_types = settings.quiz_enabled ?? problem_types;

        const exitMethod = () => {
            if (DEBUG) console.log("Exit method requested");
            exit = true;
            return false;
        };

        /**
         * Returns true if answer is correct, false otherwise using a random question method.
         * @param {emthod} exitMethod 
         * @returns {boolean} true if answer is correct, false otherwise
         */
        const askQuestionRandom = async ({ exitMethod = () => { }, force_mode = true } = {}) => {
            let problem_type_selected = constants.get_random(problem_types);

            switch (problem_type_selected) {
                case 'math':
                    const math_answered = await this.ask_math_question({ exitMethod: exitMethod });
                    if (math_answered && increase_performance) {

                        increasePerformance('math_ss');

                    }
                    return math_answered;

                case 'term':
                    if (force_mode) {
                        const term_answered = await this.forceLearnTermQuestions({ exitMethod: exitMethod });
                        if (term_answered && increase_performance) {

                            increasePerformance('terms');

                        }
                        return term_answered;
                    } else {

                        const term_answered = await this.pick_and_ask_term_question({ exitMethod: exitMethod });
                        if (term_answered && increase_performance) {

                            increasePerformance('terms');

                        }
                    }

                case 'algorithm':
                    // Wont be called for now
                    const algo_answered = await this.ask_algorithm_question({ exitMethod: exitMethod });
                    if (algo_answered && increase_performance) {
                        increasePerformance('algo_w');
                    }

                    return algo_answered;

                case 'cloze-algo':
                    const cloze_answered = await this.ask_cloze_algorithm_question({ exitMethod: exitMethod });

                    return cloze_answered;

                default:
                    return false;
            }
        }

        let answerIsCorrect = false;
        if (ask_until_one_is_correct)
            while (!answerIsCorrect && !exit) {
                if (DEBUG) console.log("Answer is correct", answerIsCorrect, "exit", exit);
                answerIsCorrect = await askQuestionRandom({ exitMethod: exitMethod });
            }
        else {
            const _ = askQuestionRandom();
        }

        return true;

    }

    ask_algorithm_question = () => {
        const problem_status = this.dsaTrainer.openRandomProblem();
        return problem_status;
    }

    ask_cloze_algorithm_question = async ({ exitMethod = () => { } } = {}) => {
        // TODO, create an openRandomProblem where it cleans and loads for you.

        const problem_status = this.dsaTrainer.openRandomClozeDSAProblem();
        return problem_status;
    }




    cloze_study_session = async ({ reset_scheduler = false }) => {

        // Pick all the available string keys.

        await this.dsaTrainer.loaded_problem_manager;
        const cloze_problems = cloze_problems_list;
        const clozeScheduler = new TermScheduler({
            cards_category: "Algo"
        });
        await clozeScheduler.setLearningCards(cloze_problems, { shuffle: true, reset_scheduler: reset_scheduler });
        let exit = false;

        const printCardsLeft = (cardsLeft, cardsLearnt) => {
            console.log(`\nAlgorithms left: ${cardsLeft} || Algorithms completed: ${cardsLearnt}\n`);
        }

        while (!clozeScheduler.is_completed && !exit) {
            const [cardsLeft, cardsLearnt] = [clozeScheduler.getCardsToLearn(), clozeScheduler.getCardsLearnt()];

            const card = await clozeScheduler.getCard();
            let problem = this.dsaTrainer.problems_manager.getProblem(card.problem_slug);

            console.log("Card", card);
            problem.is_cloze = true;
            const solution_metadata = await this.dsaTrainer.solveProblem(problem, { base: DSAConstants.PATHS.base_cloze, populate_with_cloze_filepath: card.file_path });

            const answerIsCorrect = solution_metadata.status == DSAConstants.ProblemStatus.solved;
            clozeScheduler.solveCard(answerIsCorrect);
            await clozeScheduler.saveCards();
            printCardsLeft(cardsLeft, cardsLearnt);
        }
    }

    jupyter_study_session = async () => {

        // Pick all the available string keys.

        const jupyter_problems = getProblemsData();
        const jupyterScheduler = new TermScheduler({
            cards_category: "Jupyter"
        });
        await jupyterScheduler.setLearningCards(jupyter_problems);
        let exit = false;

        const printCardsLeft = (cardsLeft, cardsLearnt) => {
            console.log(`\nJupyter left: ${cardsLeft} || Jupyter completed: ${cardsLearnt}\n`);
        }

        let maid = new Maid();
        maid.runServer();

        while (!jupyterScheduler.is_completed && !exit) {
            const [cardsLeft, cardsLearnt] = [jupyterScheduler.getCardsToLearn(), jupyterScheduler.getCardsLearnt()];

            const card = await jupyterScheduler.getCard();

            console.log("Card", card.problem);
            const answerIsCorrect = await maid.openJupyter({ FILE: card.problem });

            jupyterScheduler.solveCard(answerIsCorrect);
            await jupyterScheduler.saveCards();
            printCardsLeft(cardsLeft, cardsLearnt);
        }

    }

}

module.exports = { QuizzerWithDSA };