← Back to articles

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:

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:

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

  1. Parsing Input: We read the input file and parse each line into a list of integers.
  2. Monotonic Trend Check: We determine if the report is entirely increasing or decreasing.
  3. Reasonable Differences Check: We ensure all adjacent levels differ by at least 1 and at most 3.
  4. 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:

  1. Levels in a report must either increase or decrease consistently.
  2. Differences between adjacent levels must be at least 1 and at most 3.

In Part Two, a new condition is added:

This additional rule means we need to recheck each report by simulating the removal of each level, one at a time.

Example Walkthrough

Step-by-Step:

  1. For each report, check if it satisfies the rules as-is (Part One logic).
  2. If not, iterate through the report:
    • Temporarily remove one level at a time.
    • Check if the modified report becomes safe.
  3. 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!