Skip to content

Latest commit

 

History

History
110 lines (90 loc) · 18.7 KB

18.md

File metadata and controls

110 lines (90 loc) · 18.7 KB

Day 18

Part 1

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)
}

Try it out on flems.io

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.

Part 2

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)
 )

flems

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.

What did I learn?

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!).