Advent of Code 2024 — Day 2: Red-Nosed Reports
Part 1
Today the engineers at the Red-Nosed reactor need help with their reports. Each report is one line of numbers (levels), and we need to count how many of them are safe.
A report is safe when:
- the levels are all increasing or all decreasing
- any two neighbours differ by at least 1 and at most 3
The example input:
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
Going through them one by one:
7 6 4 2 1safe, always going down by 1 or 21 2 7 8 9unsafe,2 7jumps by 59 7 6 2 1unsafe,6 2drops by 41 3 2 4 5unsafe, it goes up then down8 6 4 4 1unsafe,4 4doesn't move at all1 3 6 7 9safe, always going up by 1, 2 or 3
So 2 safe reports.
For the code I check the two rules separately. The first loop tells me if the report only goes up or only goes down, the second one checks the gaps. If both pass, the report is safe.
def solve_part_1():
reports = []
with open("example.txt", "r") as f:
lines = f.read().strip().split("\n")
for l in lines:
reports.append(list(map(int, l.split(" "))))
safe_reports_num = 0
for r in reports:
is_increasing = True
is_decreasing = True
for i in range(len(r) - 1):
if r[i] >= r[i + 1]:
is_increasing = False
if r[i] <= r[i + 1]:
is_decreasing = False
is_safe = True
for i in range(len(r) - 1):
difference = abs(r[i] - r[i + 1])
if not (1 <= difference <= 3):
is_safe = False
break
if (is_increasing or is_decreasing) and is_safe:
safe_reports_num += 1
return safe_reports_numPart 2
Now there's a Problem Dampener: a report also counts as safe if removing one single level makes it safe.
Same example again:
7 6 4 2 1safe already1 2 7 8 9unsafe, no matter which level we remove9 7 6 2 1unsafe, same thing1 3 2 4 5safe if we remove the38 6 4 4 1safe if we remove one of the4s1 3 6 7 9safe already
That makes 4.
I went with brute force. If a report fails, I try removing each level one at a time and run the same checks on what's left. It's basically part 1 again, inside a loop that skips one index each time. Reports are short, so it's fast enough.
def solve_part_2():
reports = []
with open("example.txt", "r") as f:
lines = f.read().strip().split("\n")
for l in lines:
reports.append(list(map(int, l.split(" "))))
safe_reports_num = 0
for r in reports:
is_increasing = True
is_decreasing = True
for i in range(len(r) - 1):
if r[i] >= r[i + 1]:
is_increasing = False
if r[i] <= r[i + 1]:
is_decreasing = False
is_safe = True
for i in range(len(r) - 1):
difference = abs(r[i] - r[i + 1])
if not (1 <= difference <= 3):
is_safe = False
break
if (is_increasing or is_decreasing) and is_safe:
safe_reports_num += 1
continue
# PART TWO
print("------")
for skip_idx in range(len(r)):
modified_r = r[:skip_idx] + r[skip_idx + 1 :]
print(modified_r, skip_idx)
is_increasing = True
is_decreasing = True
for i in range(len(modified_r) - 1):
if modified_r[i] >= modified_r[i + 1]:
is_increasing = False
if modified_r[i] <= modified_r[i + 1]:
is_decreasing = False
is_safe = True
for i in range(len(modified_r) - 1):
difference = abs(modified_r[i] - modified_r[i + 1])
if not (1 <= difference <= 3):
is_safe = False
break
if (is_increasing or is_decreasing) and is_safe:
safe_reports_num += 1
break
return safe_reports_numAnd that's day 2.