UNPKG

mathsteps-experimental-fork

Version:

Step by step math solutions. Experimental Fork

119 lines (108 loc) 5 kB
import clone from '../newServices/nodeServices/clone.js'; import { myNodeToString } from '../newServices/nodeServices/myNodeToString.js'; import checks from '../checks/index.js'; import { travelTreeExpanded, setUpNewNodeTree } from '../newServices/treeUtil.js'; import { ChangeTypes } from '../types/changeType/ChangeTypes.js'; import { printAscii } from '../util/print.js'; import { getFirstOperationChoicePermutations } from './getAllRuleResponsesForNextStepHelper.js'; import { kemuFlatten } from './kemuSimplifyCommonServices.js'; import _kemuSortArgs from './kemuSortArgs.js'; import { POOL_OF_RULES } from './theIndexRulePool.js'; function getAllRuleResponsesForNextStep(node, options = {}) { // Pre-process node. node = kemuFlatten(node); // Add hard-coded first step with original expression. if (options.onStepCb) options.onStepCb({ changeType: ChangeTypes.KEMU_ORIGINAL_EXPRESSION, rootNode: clone(node) }); const isAllowed = !checks.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(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 = printAscii(oldNode0); const newNodeAsText = printAscii(newNode); if (oldNodeAsText !== newNodeAsText) { if (options.onStepCb) options.onStepCb({ changeType: 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 setUpNewNodeTree(context, newNode); // Log the string const result = 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? 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; 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(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 = getFirstOperationChoicePermutations(newNode, true); const seenNodes = new Set(); for (const _node of perm) { const rulesRes = fct(_node, simplifyCtxNode, activeNodeOrArgsParent, options); if (rulesRes) { const nodeStr = myNodeToString(rulesRes); if (!seenNodes.has(nodeStr)) { seenNodes.add(nodeStr); rulesReses.push(rulesRes); } } } return rulesReses } export { getAllRuleResponsesForNextStep };