mathsteps-experimental-fork
Version:
Step by step math solutions. Experimental Fork
93 lines (90 loc) • 4.6 kB
JavaScript
import { makeStartingLeftAndRightEqSteps, makeEquationProcessSteps, findMatchingAddRemoveTerms, findNonAddRemoveRuleMatches } from './utils.js';
import { getAssessSolvedProblemSteps } from '../kemuEquation/SimpleSolveEquationFunction.js';
import { areEquationsEqual } from '../newServices/expressionEqualsAndNormalization.js';
import { isRemoveTermChangeType, isAddTermChangeType } from '../types/changeType/changeAndMistakeUtils.js';
import { ChangeTypes } from '../types/changeType/ChangeTypes.js';
import { getChangesTypesForRule } from '../types/changeType/MathRuleTypes.js';
import { UndoableString } from '../util/UndoableString.js';
function getEquationMatches(currentEquation) {
const startingLeftRight = makeStartingLeftAndRightEqSteps(currentEquation);
const eqProcessedSteps = makeEquationProcessSteps(currentEquation);
const addRemoveCombo = findMatchingAddRemoveTerms(eqProcessedSteps);
const nonAddRemoveRuleMatches = findNonAddRemoveRuleMatches(
eqProcessedSteps,
startingLeftRight
);
const allRuleMatches = addRemoveCombo.concat(nonAddRemoveRuleMatches).map((option) => ({
left: option.left,
right: option.right,
newTo: `${option.left.to}=${option.right.to}`
// full equation after applying that step
}));
return allRuleMatches;
}
const getFastestAmountOfStepsToSolveEquation = (assessedSteps) => {
const removeNoChangeTypeStepsFn = (side) => side.filter((s) => s.attemptedChangeType !== ChangeTypes.NO_CHANGE);
const removeStuffFromRightFn = (side) => {
return side.filter((s) => !isRemoveTermChangeType(s.attemptedChangeType)).filter((s) => !isAddTermChangeType(s.attemptedChangeType)).filter((s) => s.attemptedChangeType !== ChangeTypes.EQ_SWAP_SIDES).filter((s) => s.attemptedChangeType !== ChangeTypes.EQ_MULTIPLY_BOTH_SIDES_BY_NEGATIVE_ONE);
};
const removeRemoveAddingZeroFn = (side) => side.filter((s) => s.attemptedChangeType !== ChangeTypes.REMOVE_ADDING_ZERO);
assessedSteps = assessedSteps.map((step) => {
const left = removeRemoveAddingZeroFn(removeNoChangeTypeStepsFn(step.left));
const right = removeRemoveAddingZeroFn(removeNoChangeTypeStepsFn(removeStuffFromRightFn(step.right)));
return { ...step, left, right };
});
let count = 0;
for (const step of assessedSteps) {
count += step.left.length;
count += step.right.length;
}
return count;
};
class EquationCommander {
equationHistory;
finalCorrectAnswer;
correctAnswerSteps;
assessedSteps;
constructor(initialValue = "") {
this.equationHistory = new UndoableString(initialValue);
const { steps, assessedSteps } = getAssessSolvedProblemSteps(initialValue);
this.correctAnswerSteps = steps;
this.assessedSteps = assessedSteps;
this.finalCorrectAnswer = steps[steps.length - 1].equationString;
}
redo = () => this.equationHistory.redo();
undo = () => this.equationHistory.undo();
setValue = (newValue) => this.equationHistory.setValue(newValue);
getValue = () => this.equationHistory.getValue();
isSolved = () => areEquationsEqual(this.finalCorrectAnswer, this.getValue());
// TODO add cache
getHistory = () => this.equationHistory.getHistory();
getFuture = () => this.equationHistory.getFuture();
swap() {
const currentEquation = this.getValue();
const [left, right] = currentEquation.split("=");
this.setValue(`${right}=${left}`);
}
getAssessedSteps = () => this.assessedSteps;
getCorrectAnswerSteps = () => this.correctAnswerSteps;
getFastestAmountOfStepsToSolve = () => getFastestAmountOfStepsToSolveEquation(this.assessedSteps);
getCurrentNumberOfSteps = () => this.assessedSteps.length;
getCurrentMatches() {
const allRuleMatches = getEquationMatches(this.getValue());
const skippedZeroPlusMatches = allRuleMatches.map((match) => {
const cleanStartingZeroToFn = (to) => to.replace(/^0[a-z]*[\+\-]/gmi, "");
const left = cleanStartingZeroToFn(match.left.to);
const right = cleanStartingZeroToFn(match.right.to);
match.left.to = left;
match.right.to = right;
match.newTo = `${left}=${right}`;
return match;
});
return skippedZeroPlusMatches;
}
getMatchesForRule(rule) {
const matches = this.getCurrentMatches();
const changeTypesForGivenRule = rule !== "all" ? getChangesTypesForRule(rule) : Object.values(ChangeTypes).flat();
return matches.filter((match) => changeTypesForGivenRule.includes(match.left.changeType) || changeTypesForGivenRule.includes(match.right.changeType));
}
}
export { EquationCommander, EquationCommander as default, getFastestAmountOfStepsToSolveEquation };