The problem
I need to compute all the “instructions” within a corrupted string.
For now, the only instruction available is mul, which stands for multiplication. After the instruction, there are two numbers that are supposed to be multiplied, e.g., mul(2,4).
The issue? The string carrying these instructions got corrupted, so I need to sift through the noise.
The plan
This seems pretty straightforward:
- Use a regex to extract all valid mul instructions.
- Parse the numbers, multiply them, and sum up the products.
Here’s an example of the corrupted input:
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
The implementation
The first task is extracting valid mul instructions. I started with this regex:
/mul\([0-9],[0-9]\)/
This worked for simple cases, but it missed one instruction: mul(11,8). Why? The regex only matched single-digit numbers!
So, I improved it:
/mul\([0-9]+,[0-9]+\)/
Now it captures all mul instructions with one or more digits for each number.
Once I had the valid instructions, I stripped away the noise (mul( and )) to get simpler strings to work with:
["2,4", "5,5", "11,8", "8,5"]
From here, the rest was easy:
- Split each string on the comma.
- Parse the numbers into integers.
- Give it a little kiss, with
inject(:*). - Add the results to a running total (sum).
The inject method in Ruby made this process elegant. It applies the specified operation across elements in an enumerable.
Here’s the snippet:
valid_strings.each do |m|
sum += m.split(',').map(&:to_i).inject(:*)
end
The final implementation
# input = File.read("puzzle_input.txt")
input = File.read "./example.txt"
sum = 0
valid_strings = input.scan(/mul\([0-9]+,[0-9]+\)/).map do |s|
# I could use capture groups etc., but this works well enough :]
s.gsub('mul(', '').gsub(')', '')
end
valid_strings.each do |m|
sum += m.split(',').map(&:to_i).inject(:*)
end
puts sum
Final thoughts
Regex is a powerful beast, but it’s always a good idea to revisit the edge cases (like multi-digit numbers).