UNPKG

mathsteps-experimental-fork

Version:

Step by step math solutions. Experimental Fork

123 lines (110 loc) 5.33 kB
'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;