Advent of Code '24 — Day 2
Day two! And things are already tricksy!
Today's puzzle was about deciphering reports, to determine if each level in the report is deemed safe.
A safe "level" is on that each number in the row increases or decreases only, and only by a maximum of 3.
Part 1
In the first part, we needed to work out how many levels were safe.
E.g. given:
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
Only the first and last reports are safe as they're the only ones that follow the 2 rules.
A simple enough solution for this one:
def part1(input)
input.map do |line|
dir = nil
vals = line.split(" ").each_cons(2).map do |first, second|
next_dir = if Integer(first) > Integer(second)
:increase
elsif Integer(first) < Integer(second)
:decrease
else
:no_change
end
dir = next_dir if dir.nil?
(Integer(first) - Integer(second)).abs > 3 || dir != next_dir
end
vals.all?(false) ? 1 : 0
end.sum
end
First, mapping over each line, checking items in pairs of 2 and checking if we're constantly increasing or decreasing, or if we're stepping in increments greater than 3.
⭐️ Success! Albeit a little verbose!
Part 2
The second part was tricky!
My solution to the first part wasn't really flexible enough to accommodate the second part, so a rewrite was required.
In part 2, we learned that some levels can be made safe, by removing an entry in the level. I totally misread this, and thought that only otherwise unsafe entries could be removed. So made a number of wrong entries before realising that any entry could be removed to make the level safe.
So here's my brute-force attempt after banging my head against it for a bit:
def part2(input)
input.count { |levels|
levels = levels.split(" ")
safe?(levels) || safe_by_removing_level?(levels)
}
end
def safe?(report_result)
res = report_result.each_cons(2).map do |first, second|
if Integer(first) < Integer(second) && Integer(second) - Integer(first) <= 3
:increase
elsif Integer(first) > Integer(second) && Integer(first) - Integer(second) <= 3
:decrease
else
:bad_step
end
end
res.all? { |x| x == :increase } || res.all? { |x| x == :decrease }
end
def safe_by_removing_level?(report)
0.upto(report.size).find do |i|
sub = report.dup
sub.delete_at(i)
safe?(sub)
end
end
This time, we still check that every level is safe, but if it's not, we then remove one entry from the level at a time to see if it would be safe.
⭐️ Success!
Performance
Even though this was brute-forced, it still performed OK. Though each level only had ~6 entries to loop through, so not a huge set of data to work with.
day 02
├─ part 1 — 0.002105s
╰─ part 2 — 0.008360s
Day two: https://github.com/dNitza/advent-of-code/tree/main/2024/02
in posts
Tagged