Evaluate the expression on each line of the input. What is the sum of the resulting values?
The addition (
+
) and multiplication (*
) operators have the same precedence, and are evaluated left-to-right regardless of the order in which they appear.
const input = `
2 * 3 + (4 * 5)
5 + (8 * 3 + 9 + 3 * 4 * 3)
5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))
((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2
`.trim()
const sum = input
.split('\n')
.map((expression) => evaluate(expression))
.reduce((a, b) => a + b)
console.log(sum)
function evaluate(expression) {
let nextExpression
if (expression.includes('(')) {
nextExpression = expression.replace(
/\(([^()]+)\)/g,
(match, subExpression) => evaluate(subExpression)
)
} else {
nextExpression = expression.replace(
/(\d+) ([+*]) (\d+)/,
(match, a, operator, b) => (operator === '+' ? +a + +b : a * b)
)
}
return isNumber(nextExpression) ? +nextExpression : evaluate(nextExpression)
}
function isNumber(expression) {
return /^\d+$/.test(expression)
}
I like this solution! The regex for sub-expressions (i.e. expressions in parentheses) is a bit noisy, but other than that, I like how clear and simple this is. It's also faster than I anticipated: with the real puzzle input, running the code takes about 7 milliseconds on my machine.
Same as Part 1, but now addition is evaluated before multiplication. What's the result now?
The solution is almost identical as in Part 1.
Instead of evaluating an addition or multiplication operation,
we need to evaluate addition operations
if the expression contains an addition operator (+
).
Otherwise we can evaluate multiplication operations.
Like so:
+const operator = expression.includes('+') ? '+' : '*'
nextExpression = expression.replace(
- /(\d+) ([+*]) (\d+)/,
- (match, a, operator, b) => (operator === '+' ? +a + +b : a * b)
+ new RegExp(`(\\d+) \\${operator} (\\d+)`),
+ (match, a, b) => (operator === '+' ? +a + +b : a * b)
)
This code is slightly slower than the code in Part 1, but still very fast: it now takes about 10 milliseconds to run on my machine.
My solution is based on
String.prototype.replace()
,
and especially on
specifying a function as its second parameter.
I did know that you can specify a replacer function for replace()
.
For example,
the fast and lightweight date library Light Date
utilizes replace()
with replacer functions.
I have used Light Date in
my blog
and also done
small contributions
to it. 🙂
I however hadn't used replace()
this way from scratch,
so now I learned to use it
(very easy –
but very nice!).