mathsteps-experimental-fork
Version:
Step by step math solutions. Experimental Fork
137 lines (132 loc) • 7.85 kB
JavaScript
;
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;