mathsteps-experimental-fork
Version:
Step by step math solutions. Experimental Fork
123 lines (110 loc) • 5.33 kB
JavaScript
'use strict';
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const clone = require('../newServices/nodeServices/clone.js');
const myNodeToString = require('../newServices/nodeServices/myNodeToString.js');
const index = require('../checks/index.js');
const treeUtil = require('../newServices/treeUtil.js');
const ChangeTypes = require('../types/changeType/ChangeTypes.js');
const print = require('../util/print.js');
const getAllRuleResponsesForNextStepHelper = require('./getAllRuleResponsesForNextStepHelper.js');
const kemuSimplifyCommonServices = require('./kemuSimplifyCommonServices.js');
const kemuSortArgs = require('./kemuSortArgs.js');
const theIndexRulePool = require('./theIndexRulePool.js');
function getAllRuleResponsesForNextStep(node, options = {}) {
// Pre-process node.
node = kemuSimplifyCommonServices.kemuFlatten(node);
// Add hard-coded first step with original expression.
if (options.onStepCb)
options.onStepCb({ changeType: ChangeTypes.ChangeTypes.KEMU_ORIGINAL_EXPRESSION, rootNode: clone(node) });
const isAllowed = !index.default.hasUnsupportedNodes(node);
if (!isAllowed)
return
// Apply simplify rules to the expression.
const originalNode = clone(node);
const oldNode0 = originalNode;
const root = node;
// Apply common rules first.
for (const [ruleId, fct] of Object.entries(theIndexRulePool.POOL_OF_RULES)) {
if (options[`disable${ruleId}`])
continue
const res = getAllResponsesForRule(fct, root, options);
if (res)
options.onStepCb(res);
}
//
// Post-process node.
//
node = oldNode0;
// Possible improvement: Optimize it.
const newNode = kemuSortArgs(clone(oldNode0));
const oldNodeAsText = print.printAscii(oldNode0);
const newNodeAsText = print.printAscii(newNode);
if (oldNodeAsText !== newNodeAsText) {
if (options.onStepCb)
options.onStepCb({ changeType: ChangeTypes.ChangeTypes.REARRANGE_COEFF, rootNode: newNode });
node = newNode;
}
return node
}
function getNodeFromTopNodeHack(obj, getResultCB) {
const context = obj.context;
const newNode = obj.newNode?.rootNode || obj.newNode;
const ogRootNode = obj.ogRootNode?.rootNode || obj.ogRootNode;
const ogTopNode = obj.ogTopNode?.rootNode || obj.ogTopNode;
// Convert node back to its root node version. ex. new subnode 5 is placed back into topNode equation as 3 + 2 * 5
// Change everything to use new updated node
treeUtil.setUpNewNodeTree(context, newNode);
// Log the string
const result = myNodeToString.myNodeToString(context.topNode);
// resultLog.add(result)
getResultCB(result);
// Change everything back to the original node.
// TODO Note. Sometimes the reference may change? Its fixed inside travelTreeExpanded so maybe that's okay?
treeUtil.setUpNewNodeTree(context, ogRootNode, ogTopNode);
}
function getAllResponsesForRule(fct, root, options) {
let changeTypeFound = null; // i.e. ChangeTypes.SIMPLIFY_ARITHMETIC__ADD || ChangeTypes.SIMPLIFY_ARITHMETIC__MULTIPLY etc.
const resultLog = new Set();
const errorResultLog = new Set();
const ogTopNode = clone(root);
let isMistakeRuleFound = false;
treeUtil.travelTreeExpanded(root, (_node, context) => {
const ogRootNode = clone(_node);
const rulesReses = getRuleResponseForEachUsefulPermutation(fct, _node, {}, null, options);
if (!rulesReses || rulesReses.length === 0)
return
// log the type we found. Its going to be the same for all these nodes.
changeTypeFound = rulesReses[0].changeType;
isMistakeRuleFound = rulesReses[0].isMistake;
for (const newNode of rulesReses) {
// places result string in resultLog
getNodeFromTopNodeHack({ context, newNode, ogTopNode, ogRootNode }, resultStr => resultLog.add(resultStr));
if (newNode.mistakes) {
for (const mistakeNode of newNode.mistakes)
getNodeFromTopNodeHack({ context, newNode: mistakeNode, ogTopNode, ogRootNode }, resultStr => errorResultLog.add({ to: resultStr, changeType: mistakeNode.changeType }));
}
}
});
if (!changeTypeFound || !resultLog.size === 0)
return null
return { changeType: changeTypeFound, to: Array.from(resultLog), isMistake: isMistakeRuleFound, mTo: Array.from(errorResultLog), from: myNodeToString.myNodeToString(root), rootNode: root }
}
function getRuleResponseForEachUsefulPermutation(fct, node, simplifyCtxNode = {}, activeNodeOrArgsParent = null, options = null) {
const rulesReses = [];
const newNode = node.rootNode || node;
// Get all permutations of the node but only the first two nodes. ex. 1 + (2 * 3) + 2 => [1 + (2 * 3) + 2, (2 * 3) + 2 + 1, 2 + 1 + (2 * 3)]
const perm = getAllRuleResponsesForNextStepHelper.getFirstOperationChoicePermutations(newNode, true);
const seenNodes = new Set();
for (const _node of perm) {
const rulesRes = fct(_node, simplifyCtxNode, activeNodeOrArgsParent, options);
if (rulesRes) {
const nodeStr = myNodeToString.myNodeToString(rulesRes);
if (!seenNodes.has(nodeStr)) {
seenNodes.add(nodeStr);
rulesReses.push(rulesRes);
}
}
}
return rulesReses
}
exports.getAllRuleResponsesForNextStep = getAllRuleResponsesForNextStep;