Advent of Code '24 — Day 3

Day three! Back on easy street.

Today's puzzle was about parsing a set of corrupted instructions, and extracting the good instructions. Then "executing" them and summing the results.

Link to puzzle

Part 1

Extracting the corrupted instructions. Correct instructions look like mul(x,y) where x and y are up 1-3 digit numbers. Any other instruction is corrupt and invalid.

E.g. given:

xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))

Only:

  • mul(2,4)
  • mul(5,5)
  • mul(11,8)
  • mul(8,5)

Are valid, and when all multiplications are added up, we would get 161.

This one could have gone one of two ways ;)

I did start writing a parser and a lexer to turn the input string in to an AST, and then do the math™.

But regex is much easier. So I quickly abandoned the first approach, in favour of:

PATTERN = /mul[(](\d{1,3}),(\d{1,3})[)]/i

  def part1(input)
    muls = input.first.scan(PATTERN)
    muls.map do |pair|
      Integer(pair[0]) * Integer(pair[1])
    end.sum
  end

First up, defining a pattern to match our good instructions. Then, mapping over them, extracting the 2 values and multiplying before adding everything up.

⭐️ Success!

Part 2

In part 2, we found out that there are conditionals still intact in the instruction set. These take the form of dos and don'ts. When there is a do, all subsequent instructions are to be evaluated. When there is a don't, all future instructions are to be skipped, until the next do.

Again, would have been really nice with an AST, but also, super quick with an update to our regex.

Now we also care about our conditional statements in the instructions, so let's grab those:

PATTERN_TWO = /mul[(](\d{1,3}),(\d{1,3})[)]|(don[']t)|(do)/i

Making sure to grab the don'ts first, so we don't accidentally confuse it for a do.

def part2(input)
  should_multiply = true
  isns = input.first.scan(PATTERN_TWO)

  isns
    .map(&:compact)
    .map do |vals|
      case vals.first
      when "don't"
        should_multiply = false
        nil
      when "do"
        should_multiply = true
        nil
      else
        if should_multiply
          Integer(vals[0]) * Integer(vals[1])
        else
          0
        end
      end
    end
    .compact
    .sum
end

Then, we can extract our instructions, and iterate over them, only multiplying pairs of numbers when we previously saw a do.

⭐️ Success!

Performance

Pretty quick again, though our input was also pretty small again today.

day 03
├─ part 1 — 0.000221s
╰─ part 2 — 0.000444s

Day three: https://github.com/dNitza/advent-of-code/tree/main/2024/03

Published

by Daniel Nitsikopoulos

in posts

Tagged

© 2010 - 2024 Daniel Nitsikopoulos. All rights reserved.

🕸💍  →