Advent of Code 2015, Day 12 – In Ruby
Let’s see the 12th puzzle of 2015!
The first half of the puzzle
Santa’s Accounting-Elves need help balancing the books after a recent order. Unfortunately, their accounting software uses a peculiar storage format. That’s where you come in.
They have a JSON document which contains a variety of things: arrays ([1,2,3]), objects ({“a”:1, “b”:2}), numbers, and strings. Your first job is to simply find all of the numbers throughout the document and add them together.
For example:
- [1,2,3] and {“a”:2,”b”:4} both have a sum of 6.
- [[[3]]] and {“a”:{“b”:4},”c”:-1} both have a sum of 3.
- {“a”:[-1,1]} and [-1,{“a”:1}] both have a sum of 0.
- [] and {} both have a sum of 0.
You will not encounter any strings containing numbers.
What is the sum of all numbers in the document?
The solution:
Step-by-step explanation:
- read the input file, the name of which is provided as a command line parameter (
ARGF.read
) - replace every run of characters which is not a number or a minus sign (the regexp
/[^-0-9]+/
) with a space (.gsub(/[^-0-9]+/, ' ')
– this will return a single string with numbers separated by spaces - split the string into the numbers it contains (they will still be in string form) (
.split
) - convert the numbers-in-strings into proper numbers (
.map(&:to_i)
) - add them (
.reduce(:+)
)
This will work due to the premise that none of the strings will contain numbers: we can simply ‘erase’ everything that’s not a number, and add the numbers that remain.
The second half of the puzzle
Uh oh - the Accounting-Elves have realized that they double-counted everything red.
Ignore any object (and all of its children) which has any property with the value “red”. Do this only for objects ({…}), not arrays ([…]).
- [1,2,3] still has a sum of 6.
- [1,{“c”:”red”,”b”:2},3] now has a sum of 4, because the middle object is ignored.
- {“d”:”red”,”e”:[1,2,3,4],”f”:5} now has a sum of 0, because the entire structure is ignored.
- [1,”red”,5] has a sum of 6, because “red” in an array has no effect.
The solution:
This time there’s no shortcut, we need to parse the input with Ruby’s json
module. The solution needs to be recursive, because arrays and hashes can be nested in each other in the input.
In the count
method, we first check whether the input is a Hash which contains the value red
anywhere. If it is, we ignore this object (return early).
The next step depends on the type of the input:
- if it’s a Hash or an Array (
i.class.method_defined? :each
) – recursively call the count method on each element (in case it’s an Array) or each value (in case it’s a Hash) - if it’s an Integer, simply add its value to the
$sum
The code with my input text is available in the GitHub repo.
Thanks for reading! If you have any comments, additions, or corrections, feel free to reach me via e-mail.