UNPKG

mathsteps-experimental-fork

Version:

Step by step math solutions. Experimental Fork

137 lines (132 loc) 7.85 kB
'use strict'; Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const index = require('../index.js'); const SpecialCrossMultiplication = require('../kemuEquation/Special-CrossMultiplication.js'); const expressionEqualsAndNormalization = require('../newServices/expressionEqualsAndNormalization.js'); const myNodeToString = require('../newServices/nodeServices/myNodeToString.js'); const termRemovalOperations = require('../newServices/nodeServices/termRemovalOperations.js'); const equationCache = require('./equationCache.js'); const regexPemdasMistakes = require('./mistakes/regexPemdasMistakes.js'); const changeAndMistakeUtils = require('../types/changeType/changeAndMistakeUtils.js'); const ChangeTypes = require('../types/changeType/ChangeTypes.js'); const arrayUtils = require('../util/arrayUtils.js'); const cleanString = require('../util/cleanString.js'); const regex = require('../util/regex.js'); const parseText = require('../newServices/nodeServices/parseText.js'); const { SIMPLIFY_ARITHMETIC__ADD, SIMPLIFY_ARITHMETIC__SUBTRACT } = ChangeTypes.ChangeTypes; const expressionEquals = (exp0, exp1) => expressionEqualsAndNormalization.areExpressionEqual(exp0, exp1, equationCache.getValidStepEqCache()); function _normalizeExpressionForCountingSubtractions(expr) { return expr.replace(/\+-/g, "-").replace(/-\+/g, "-").replace(/--/g, "+").replace(/^-/, ""); } function _correctSimplifyAdditionToSubtraction(steps) { steps.forEach((step) => { if (step.changeType === SIMPLIFY_ARITHMETIC__ADD && step.from.includes("-")) { const fromRaw = _normalizeExpressionForCountingSubtractions(step.from); const toRaw = _normalizeExpressionForCountingSubtractions(step.to); const fromMinusCount = [...fromRaw.matchAll(/-/g)].length; const toMinusCount = [...toRaw.matchAll(/-/g)].length; if (toMinusCount < fromMinusCount) { step.changeType = SIMPLIFY_ARITHMETIC__SUBTRACT; } } }); const newAvailableChangeTypes = steps.filter((step) => !step?.isMistake).map((step) => step?.changeType); steps.forEach((step) => { step.availableChangeTypes = newAvailableChangeTypes; }); } function _convertRawStepsToProcessedStep(steps) { const processedStepsSet = /* @__PURE__ */ new Set(); return steps.filter((step) => step.to).flatMap((step) => step.to.map((toStr) => ({ ...step, availableChangeTypes: steps.filter((step2) => !step2?.isMistake).map((step2) => step2?.changeType), // TODO remove availableChangeTypes from here? We add it again in _addAllAvailableChangeTypesToEachStep to: cleanString.cleanString(toStr), from: cleanString.cleanString(step.from) }))).filter((step) => !processedStepsSet.has(step.to) && processedStepsSet.add(step.to)).filter((step) => step.to !== step.from); } function _addAllAvailableChangeTypesToEachStep(steps) { const availableChangeTypes = steps.filter((step) => !step?.isMistake).map((step) => step?.changeType); steps.forEach((step) => { step.availableChangeTypes = availableChangeTypes; }); } function _addAllPossibleCorrectTosToEachStep(steps) { const allPossibleCorrectTos = steps.filter((step) => !step.isMistake).map((step) => step.to); steps.forEach((step) => { step.allPossibleCorrectTos = allPossibleCorrectTos; }); } function findAllNextStepOptions(userStep_, neededForEquations, { getMistakes = true, isDebugMode = false } = {}) { let userStep = typeof userStep_ === "string" ? myNodeToString.myNodeToString(parseText.parseText(userStep_)) : myNodeToString.myNodeToString(userStep_); userStep = userStep.replaceAll(/\b0[a-z]\b/gmi, "0").replaceAll(/\b0\*[a-z]\b/gmi, "0"); const potentialSteps = []; index.default.simplifyExpression({ expressionAsText: userStep, isDebugMode, getMistakes, getAllNextStepPossibilities: true, onStepCb: (step) => potentialSteps.push(step) }); const processedSteps = arrayUtils.filterUniqueValues(_convertRawStepsToProcessedStep(potentialSteps), (itemA, itemB) => expressionEquals(itemA.to, itemB.to)); if (neededForEquations?.otherSide && neededForEquations?.history) { const removedDepth = neededForEquations.history.filter((step) => step.removeNumberOp).map((step) => step.removeNumberOp).length; const addedDepth = neededForEquations.history.filter((step) => step.addedNumOp).map((step) => step.addedNumOp).length; if (neededForEquations.history.length <= 1 && removedDepth === 0 && addedDepth === 0) { const crossMultiplied = SpecialCrossMultiplication.getCrossMultiplication(userStep, neededForEquations.otherSide); if (crossMultiplied) { processedSteps.push({ from: userStep, to: myNodeToString.myNodeToString(crossMultiplied.crossRight), changeType: "EQ_CROSS_MULTIPLY", isMistake: false, availableChangeTypes: ["EQ_CROSS_MULTIPLY"] }); processedSteps.push({ from: userStep, to: myNodeToString.myNodeToString(crossMultiplied.crossLeft), changeType: "EQ_CROSS_MULTIPLY", isMistake: false, availableChangeTypes: ["EQ_CROSS_MULTIPLY"] }); } } if (neededForEquations.history.length <= 2 && removedDepth === 0 && addedDepth === 0) { const hasSingleNegative = (str) => (str.match(/-/gmi)?.length || 0) === 1; const hasVariable = (str) => (str.match(/[a-z]/gmi)?.length || 0) === 1; const hasNumber = (str) => (str.match(regex.RGIntOrDecimal)?.length || 0) === 1; const thisSideIsVariableAndNegative = hasSingleNegative(userStep) && hasVariable(userStep); const thisSideIsNumberAndNegative = hasSingleNegative(userStep) && hasNumber(userStep); const otherSideIsVariableAndNegative = hasSingleNegative(neededForEquations.otherSide) && hasVariable(neededForEquations.otherSide); const otherSideIsNumberAndNegative = hasSingleNegative(neededForEquations.otherSide) && hasNumber(neededForEquations.otherSide); if (thisSideIsVariableAndNegative && otherSideIsNumberAndNegative || otherSideIsVariableAndNegative && thisSideIsNumberAndNegative) { processedSteps.push({ from: userStep, to: `(${userStep}) * -1`, changeType: "EQ_MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE", isMistake: false, availableChangeTypes: ["EQ_MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE"] }); } } if (removedDepth < 2 && addedDepth < 1) { processedSteps.push(...termRemovalOperations.findAllOperationsThatCanBeRemoved(userStep, neededForEquations.history)); } if (removedDepth < 1 && addedDepth < 2) { let makeAddedFn = function(expression0, otherSide, history) { const steps = termRemovalOperations.findAllOperationsThatCanBeRemoved(otherSide, history, { isAdded: true }); const removedNumOps = steps.map((step) => step.removeNumberOp).filter((removedNumOp) => removedNumOp !== void 0); const newExpressions = removedNumOps.map((removedNumOp) => { return { from: expression0, to: `(${expression0}) ${removedNumOp.op} ${removedNumOp.number}`, removeNumberOp: void 0, addedNumOp: removedNumOp, changeType: changeAndMistakeUtils.getAddRemoveTermTypeBasedOnOp(removedNumOp.op, "add"), availableChangeTypes: ["EQ_ADD_TERM"], isMistake: false }; }); return newExpressions; }; processedSteps.push(...makeAddedFn(userStep, neededForEquations.otherSide, neededForEquations.history)); } } if (!neededForEquations?.otherSide) { const manualMistakes = regexPemdasMistakes.mistakeSearches(userStep); processedSteps.push(...manualMistakes); } _addAllAvailableChangeTypesToEachStep(processedSteps); _addAllPossibleCorrectTosToEachStep(processedSteps); _correctSimplifyAdditionToSubtraction(processedSteps); return processedSteps; } exports.findAllNextStepOptions = findAllNextStepOptions;