Skip to content

Instantly share code, notes, and snippets.

@ndom91
Last active January 22, 2023 13:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndom91/1f598ec3e517d4654359987fae7e1d10 to your computer and use it in GitHub Desktop.
Save ndom91/1f598ec3e517d4654359987fae7e1d10 to your computer and use it in GitHub Desktop.
NDomino Recursion Problem
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')
});
});
@ndom91
Copy link
Author

ndom91 commented Jan 22, 2023

Uses Node's built-in test runner and expect functionality. Therefore requires Node 18.8.0+ or 19+.

Usage and output example:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment