Advent of Code: Red-Nosed Reports


Day 2 assignment

2024-12-02-generated.png

Fortunately, the first location The Historians want to search isn’t a long walk from the Chief Historian’s office.

While the Red-Nosed Reindeer nuclear fusion/fission plant appears to contain no sign of the Chief Historian, the engineers there run up to you as soon as they see you. Apparently, they still talk about the time Rudolph was saved through molecular synthesis from a single electron.

-- Day 2 - Advent of Code 2024

Solution in Java

Full source can be found: in GitHub

Part 1

For the first part of todays assignment I parse each line of text to a list of int, to pass them to a function lineIsSafe that determines if all numbers are increasing, or all numbers are decreasing.

For the first two numbers I store if it is increasing or decreasing and all following numbers are compared to this. Since an increase between 1 and 3 is allowed this is checked in the invalidIncrease method.

 1public void part1() {  
 2    var safe = inputLoader.splitOnNewLine()  
 3            .map(this::convertLine)  
 4            .filter(this::lineIsSafe)  
 5            .count();  
 6  
 7    validator.part1(safe);  
 8}
 9
10private List<Integer> convertLine(String line) {  
11    return Arrays.stream(line.split(" +"))  
12            .map(Integer::parseInt)  
13            .toList();  
14}  
15  
16private boolean lineIsSafe(List<Integer> line) {  
17    var previous = line.get(0);  
18    var increasing = previous < line.get(1);  
19    for (var x = 1; x < line.size(); x++) {  
20        if (invalidIncrease(increasing, previous, line.get(x))) {  
21            return false;  
22        }  
23  
24        previous = line.get(x);  
25    }  
26  
27    return true;  
28}
29
30private boolean invalidIncrease(boolean increasing, int left, int right) {  
31    var difference = Math.abs(left - right);  
32    var stillIncreasing = left < right;  
33    return (difference < 1 || difference > 3) || (stillIncreasing != increasing);  
34}

Part 2

In the second part of today a lot of the first part can be re-used. And the easiest way to determine if a line could be valid if a single number is skipped is to remove each number from left to right for any invalid line, this is done in the method lineIsSafeWithTolerance.

The resulting list of int is then passed to the same method lineIsSafe from part 1 to see if the updated list of numbers is safe.

 1public void part2() {  
 2    var safe = inputLoader.splitOnNewLine()  
 3            .map(this::convertLine)  
 4            .filter(this::lineIsSafeWithTolerance)  
 5            .count();  
 6  
 7    validator.part2(safe);  
 8}
 9
10private boolean lineIsSafeWithTolerance(List<Integer> line) {  
11    if (lineIsSafe(line)) {  
12        return true;  
13    }  
14  
15    for (int i = 0; i < line.size(); i++) {  
16        // Create a copy of the list without the element at position 'i'  
17        var modifiedLevels = new ArrayList<>(line);  
18        modifiedLevels.remove(i);  
19        // Check if the modified list is strictly decreasing  
20        if (lineIsSafe(modifiedLevels)) {  
21            return true;  
22        }  
23    }  
24    return false;  
25}

See also