Last active
January 22, 2023 13:38
-
-
Save ndom91/1f598ec3e517d4654359987fae7e1d10 to your computer and use it in GitHub Desktop.
NDomino Recursion Problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import assert from 'node:assert/strict'; | |
import { describe, it } from 'node:test'; | |
/** | |
* @param {String} expression | |
* @description Evaluate string mathematical expression | |
*/ | |
function resolve(data) { | |
return new Function(`return ${data}`)(); | |
} | |
/** | |
* @param {String} expression | |
* @description Evaluate alternative notation expression | |
*/ | |
const calculate = (expression) => { | |
if (expression === '0') return 0 | |
let remainingExpression = '' | |
const normalizedExpressionChunks = [] | |
const evaluatedExpressions = [] | |
/** | |
* @param {String} string | |
* @param {Number} position | |
* @returns {String[]} | |
* @description Recursively walk backward through expression, parsing individual steps | |
*/ | |
const walkBackString = (string, position = string.length) => { | |
if (position < 0) return | |
remainingExpression = String(string).substring(0, position) | |
const operator = new RegExp(/^[^!\d!\s]$/).test(String(string).charAt(position)) | |
if (operator) { | |
return [ | |
String(string).substring(position + 2, position + 3) || 'none', | |
String(string).charAt(position), | |
String(string).substring(position + 4, position + 5) || 'none' | |
] | |
} | |
return walkBackString(string, position - 1) | |
} | |
/** | |
* @param {String} string | |
* @returns {Array<[]>} | |
* @description Recursively merge normalized expressions | |
*/ | |
const combineExpressions = (string) => { | |
const normalizedExp = walkBackString(string) | |
if (remainingExpression) { | |
normalizedExpressionChunks.push(normalizedExp) | |
return combineExpressions(remainingExpression) | |
} else { | |
normalizedExpressionChunks.push(normalizedExp) | |
return normalizedExpressionChunks | |
} | |
} | |
const expressions = combineExpressions(expression) | |
/** | |
* @param {String[]|Number} expressions | |
* @returns {Array<Number>} | |
* @description Evaluate merged expressions | |
*/ | |
let answer = (expressions) => { | |
let combined = [] | |
if (typeof expressions === 'number') return expressions | |
expressions.forEach((exp, i) => { | |
if (Array.isArray(exp) && exp.includes('none')) { | |
const noneCount = exp.filter(e => e === 'none').length | |
if (i === expressions.length - 1) { | |
// TODO: Make all of these less reliant on magic numbers, i.e. | |
// dynamically find the required integers in the string and | |
// dynamically build resulting array no matter the length of 'none' | |
// values in the expression array. | |
if (noneCount === 2) { | |
combined.push(resolve([String(evaluatedExpressions[0]), exp[1], String(evaluatedExpressions[1])].join(''))) | |
} else if (noneCount === 1) { | |
combined.push(resolve([exp[0], exp[1], String(combined[evaluatedExpressions.length])].join(''))) | |
} | |
} else { | |
combined.push(resolve([String(evaluatedExpressions[0]), exp[1], String(evaluatedExpressions[1])].join(''))) | |
} | |
} else if (Array.isArray(exp)) { | |
evaluatedExpressions.push(resolve(exp.join(' '))) | |
combined.push(resolve(exp.join(' '))) | |
} | |
return exp | |
}) | |
return combined | |
} | |
const answerResult = answer(expressions) | |
return answerResult[answerResult.length - 1] | |
} | |
describe('Calculate Expressions', () => { | |
const expression0 = calculate('0') // 0 | |
const expression1 = calculate('+ 3 4') // 7 | |
const expression2 = calculate('* - 5 3 + 5 2') // 14 | |
const expression3 = calculate('* 3 + / 3 1 + 1 7') // 33 | |
it('0', () => { | |
assert.strictEqual(expression0, 0, 'Expression 0 Fail') | |
}); | |
it('+ 3 4', () => { | |
assert.strictEqual(expression1, 7, 'Expression 1 Fail') | |
}); | |
it('* - 5 3 + 5 2', () => { | |
assert.strictEqual(expression2, 14, 'Expression 2 Fail') | |
}); | |
it('* 3 + / 3 1 + 1 7', () => { | |
assert.strictEqual(expression3, 33, 'Expression 3 Fail') | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uses Node's built-in test runner and expect functionality. Therefore requires Node 18.8.0+ or 19+.
Usage and output example: