← Back to articles

Advent of Code 2024 — Day 2: Red-Nosed Reports

By

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 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:

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_num

Part 2

Now there's a Problem Dampener: a report also counts as safe if removing one single level makes it safe.

Same example again:

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_num

And that's day 2.