{return [...raw.matchAll(/mul\(\d+,\d+\)/g)]
.reduce((acc, nxt) => {
const nums = [...nxt[0].matchAll(/\d+/g)].map(elem => +elem[0])
return (nums[0] * nums[1]) + acc
, 0)
} }
2024 Day 3: Mull it Over
Advent of Code
Back for day 3!
Part 1
Hopping back in OJS for today, felt like the regex is more natural to do in OJS than R.
The first part here is pretty quick – we take our input and use regex to extract all mult(#, #)
patterns in the string. Once we have all those extracted, all we have to do is pull out the numbers and multiply them together, and reduce to get our final answer.
Not too shabby.
⭐
Part 2
In part 2, we have to only calculate the mult()
tags that come after a do()
instruction, but not after don't()
tags.
The first cell below was my initial attempt to get the answer, but after thinking through my process, I was able to refactor and simplify it WAY down.
{const instructions = [...raw.matchAll(/mul\(\d+,\d+\)|do\(\)|don\'t\(\)/g)]
.map(d => d[0])
let enable = true // set flag
return instructions.reduce( (acc, nxt) => {
if ( /do\(\)/.test(nxt) ) { // matches do()
= true
enable return acc
else if ( /don\'t\(\)/.test(nxt) ) { // matches don't()
} = false
enable return acc
else { // matches mult
} if (enable) { // if enabled add
const nums = [...nxt.matchAll(/\d+/g)]
.map(elem => +elem[0])
return (nums[0] * nums[1]) + acc
else { // otherwise skip
} return acc
}
}, 0)
} }
First up, the long solution. I basically modified the Part 1 regex to also extract all do()
and don't()
tags, as well as mult()
.
Then, all we have to do is keep an enable
boolean flag in memory, and as we map across the extracted commands, toggle it as needed. This way, we can skip all the unneeded mult()
s and just sum up the products that we need.
{const cleaned_input = raw
.replaceAll(/\n|\r/g, '')
.replaceAll( /\n|don\'t\(\).*?do\(\)|don\'t\(\).*/g, '')
return [...cleaned_input.matchAll(/mul\(\d+,\d+\)/g)]
.reduce((acc, nxt) => {
const nums = [...nxt[0].matchAll(/\d+/g)]
.map(elem => +elem[0])
return (nums[0] * nums[1]) + acc
, 0)
} }
In a much cleaner (and quicker?) solution, I realized I could remove all the don't()...do()
instruction sets. Notably, this includes the special case of an unbounded don't()
tag – the very last one that does not have a do()
after it.
This way, the input is as clean as Part 1, and we can apply the same solution – extracting and mapping across the resultant mult()
tags.
Keen eyes might notice an extra line removing all line breaks and carriage returns. They were causing issues with some don't()
tags not allowing the regex to carry into the next line, so adios to those!
⭐
-CH