Advent of Code, Day 18

Day 18 of Advent of Code is here! This one was refreshingly easier than some of the others. See all of my other solutions here. If you’re interested, check out what my colleagues at Slalom are doing with their Advent of Code! You can see this and my other solutions on github.

Do your best!

I highly encourage you to get through the day’s challenge on your own. Certainly refer to this and other’s examples to help you get through it. I would love to hear how you did! Did you find a better approach than I did? Do tell!

Day 18: Operation Order

Part I

All we have to do is handle some math!

But of course, it’s not that easy. For Part 1, we do math from left to right, addition and multiplication are the same. We do, however, have to process groups of equations inside of parenthesis first, then move left to right doing the adding and multiplying as it comes.

Once again, import that data

const fs = require('fs')
const maths = fs.readFileSync('./input.txt', 'utf-8').trim().split('\n')

Let’s loop through each equation and find the answers

maths.forEach(math => {
  let reducedMath = math

  while(reducedMath.indexOf('(') > -1) {
    const parenths = reducedMath.match(/\((?![0-9\s\*\+]*\()[0-9\s\+\*]*\)/ig)
    parenths.forEach(p => {
      reducedMath = reducedMath.replace(p,basicMath(p))
    })
  }

  reducedMath = basicMath(reducedMath)
  console.log(reducedMath)
  total += Number(reducedMath)
})
  • As we loop, we first check for parenthesis. If they exist, our goal is to remove them for the answer of the equation in them.
  • We’re going to use a while(), as long as there are parenthesis in the math, we need to reduce it down
  • I then use this fancy regex to get the numbers in the parenthesis. We have to start with the inner most pair of parenthesis, which is what this regex does:
    • [0-9\s*+] is our selector for numbers, spaces, and the math
    • ?! is a negative look ahead, meaning, there is not another ( after this one, so this will ensure we get the inner most parenthesis. If this hits an outer one, it will find an inner one and skip that for us
  • Once we have the inner most math equation, we may have more than one that matches so it’s an array, we then replace the equation with the answer from that equation, calling basicMath (below)
  • After we handle all the parenthesis, we run basicMath against the entire equation that’s left and add it all up

DISCLAIMER basicMath is not basic math, it’s basic for this problem, NOT for real math :D

const basicMath = (equation) => {
  let newMath = equation.replace(/[\(\)]*/g, '')
  while(isNaN(newMath)) {
    const firstMath = newMath.match(/([0-9]*\s[\+\*]\s[0-9]*)/)[1]
    newMath = newMath.replace(firstMath, eval(firstMath))
  }
  return newMath
}
  • Right off the bat, I remove any parenthesis if we have them. The first block of code finds and gets the parenthesis wrapped equations, but doesn’t remove the parenthesis, here we do.
  • Then we loop through the math, while() the newMath is not a number, implying it’s still an equation.
  • Then we grab the first little math. Normal math says do multiplication first, then add, but here, we’re going left to right, regardless if its addition or multiplication. The regex goes like
    • [0-9]*\s – any number with a space after it
    • [+*]\s – a plus, (+), or multiplier (*) is next, with a space
    • [0-9]* – and finally a number
  • We then just do the math. JavaScript has this neat little method called eval(). This will run whatever you put in it, including math.
    • Just like I could do const answer = 1 + 1 in code, as code, eval() can execute a string as code: eval('1+1').
    • Using this makes it MUCH easier than parsing and doing the math based on the string operand value
  • Then we replace the little math we just did, with the answer we got. Each loop our math equation reduces itself.

Part II

This was surprisingly easy. Instead of computing the math left to right in basicMath, we want to handle additions first, then multiplications. Taking the code from Part 1, I made 1 change in the basicMath function:

const basicMath = (equation) => {
  let newMath = equation.replace(/[\(\)]*/g, '')
  // do addition first
  while(newMath.indexOf('+') > -1) {
    const firstMath = newMath.match(/([0-9]*\s\+\s[0-9]*)/)[1]
    newMath = newMath.replace(firstMath, eval(firstMath))
  }
  while(isNaN(newMath)) {
    const firstMath = newMath.match(/([0-9]*\s[\+\*]\s[0-9]*)/)[1]
    newMath = newMath.replace(firstMath, eval(firstMath))
  }
  return newMath
}
  • You’ll see a new while() in there. We loop through as long as newMath has a + in it.
  • A regex helps us find the additions
    • [0-9]* – any number
    • \s+\s – with a space and a plus symbol after it
    • [0-9]* – with any number after it
  • We do the math and replace the equation with the answer
  • Then we do the math left to right like in Part 1. This will basically only be multiplications this time.

How did it go for you?

How did you find the answer on your own? How did you do it? Anything stump you? I’d love to hear how you did! Please comment below! I have also loaded up just the challenge and code from this and my other days on github, you can follow along there too: pretty Git pages or the code in the repo.

Series Navigation

Leave a Reply

Up ↑

%d bloggers like this: