Advent of Code 2024 — Day 2: Red-Nosed Reports
Part One
The engineers run up to me for my help with determining the safety of reports from the Red-Nosed reactor. Each report is a sequence of numerical levels, and the goal is to identify which reports meet specific safety criteria. Let’s break it down step by step.
The Problem
The engineers provided us with a list of reports, each consisting of several numerical levels. A report is considered safe if both of the following rules are satisfied:
- Monotonic Trend: The levels must be either entirely increasing or entirely decreasing.
- Reasonable Differences: The difference between any two adjacent levels must be at least 1 and at most 3.
Example Walkthrough
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
In the example above, the reports can be found safe or unsafe by checking those rules:
7 6 4 2 1
: Safe because the levels are all decreasing by 1 or 2.1 2 7 8 9
: Unsafe because2 7
is an increase of 5.9 7 6 2 1
: Unsafe because6 2
is a decrease of 4.1 3 2 4 5
: Unsafe because1 3
is increasing but3 2
is decreasing.8 6 4 4 1
: Unsafe because4 4
is neither an increase or a decrease.1 3 6 7 9
: Safe because the levels are all increasing by 1, 2, or 3.
So, in this example, 2 reports are safe.
Code Implementation
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_num
Explanation
- Parsing Input: We read the input file and parse each line into a list of integers.
- Monotonic Trend Check: We determine if the report is entirely increasing or decreasing.
- Reasonable Differences Check: We ensure all adjacent levels differ by at least 1 and at most 3.
- Final Count: If both conditions are met, we increment the safe report count.
Part Two
In Part Two, the engineers introduced a "Problem Dampener" to handle reports that could become safe by ignoring a single problematic level. The challenge is to adjust the safety evaluation to account for this, allowing for the removal of one bad level per report if necessary.
The safety rules from Part One remain the same:
- Levels in a report must either increase or decrease consistently.
- Differences between adjacent levels must be at least 1 and at most 3.
In Part Two, a new condition is added:
- A report is considered safe if removing one level makes it conform to the above rules.
This additional rule means we need to recheck each report by simulating the removal of each level, one at a time.
Example Walkthrough
7 6 4 2 1
: Safe without removing any level.1 2 7 8 9
: Unsafe regardless of which level is removed.9 7 6 2 1
: Unsafe regardless of which level is removed.1 3 2 4 5
: Safe by removing the second level, 3.8 6 4 4 1
: Safe by removing the third level, 4.1 3 6 7 9
: Safe without removing any level.
Step-by-Step:
- For each report, check if it satisfies the rules as-is (Part One logic).
- If not, iterate through the report:
- Temporarily remove one level at a time.
- Check if the modified report becomes safe.
- If at least one modification makes the report safe, count it as safe.
Code Implementation
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_num
And that's it for the second day of the Advent of Code 2024!