Advent of Code - Day 8: Resonant Collinearity


2024-12-08-generated.png

You find yourselves on the roof of a top-secret Easter Bunny installation.

While The Historians do their thing, you take a look at the familiar huge antenna. Much to your surprise, it seems to have been reconfigured to emit a signal that makes people 0.1% more likely to buy Easter Bunny brand Imitation Mediocre Chocolate as a Christmas gift! Unthinkable!

-- Day 8 - Advent of Code 2024

Solution in Java

Full source can be found: in GitHub

The first step is to create a map of all distinct characters in the grid, where the key is the character and the value is a list of all points containing that character.

 1public void readInput() {  
 2    parsedGrid.clear();  
 3  
 4    var grid = inputLoader.charGrid();  
 5    for (int y = 0; y < grid.rows(); y++) {  
 6        for (int x = 0; x < grid.cols(); x++) {  
 7            var c = grid.at(x, y);  
 8            if ('.' != c) {  
 9                parsedGrid.computeIfAbsent("" + c, k -> new ArrayList<>())  
10                        .add(Point.of(x, y));  
11            }  
12        }  
13    }  
14  
15    bounds = grid.bounds();  
16}

Part 1

With the map we can iterate over all unique characters nodes. For each node we loop over all the other nodes and create an exact opposite in the grid. If for example you have a node at point [2,2] and one at point [1,1] the algorithm will create an antinode at point [3,3].

 1public void part1() {  
 2    var answer = parsedGrid.entrySet()  
 3            .stream()  
 4            .flatMap(e -> getAntiNodes(e.getValue()))  
 5            .distinct()  
 6            .count();  
 7  
 8    validator.part1(answer);  
 9}
10
11public Stream<Point> getAntiNodes(List<Point> nodes) {  
12    var antiNodes = new HashSet<Point>();  
13    if (isLine) {  
14        antiNodes.addAll(nodes);  
15    }  
16  
17    for (int i = 0; i < nodes.size() - 1; i++) {  
18        for (int j = i + 1; j < nodes.size(); j++) {  
19            var node1 = nodes.get(i);  
20            var node2 = nodes.get(j);  
21  
22            var diff = node1.subtract(node2);  
23            var antiNode1 = node1.translate(diff);  
24            if (bounds.inBounds(antiNode1)) {  
25                antiNodes.add(antiNode1);  
26            } 
27  
28            var invertedDiff = diff.inverse();  
29            var antiNode2 = node2.translate(invertedDiff);  
30            if (bounds.inBounds(antiNode2)) {  
31                antiNodes.add(antiNode2);  
32            }
33        }  
34    }  
35  
36    return antiNodes.stream();  
37}

Part 2

For part 2 the change to the algorithm to create antinodes is not that different. Except that we continue moving outwards until we exceed the bounds of the grid. This is indicated by the highlighted sections of code.

 1public void part2() {  
 2    var answer = parsedGrid.entrySet()  
 3            .stream()  
 4            .flatMap(e -> getAntiNodesLine(e.getValue(), true))  
 5            .distinct()  
 6            .count();  
 7  
 8    validator.part2(answer);  
 9}
10
11public Stream<Point> getAntiNodesLine(List<Point> nodes) {  
12    var antiNodes = new HashSet<Point>();  
13    if (isLine) {  
14        antiNodes.addAll(nodes);  
15    }  
16  
17    for (int i = 0; i < nodes.size() - 1; i++) {  
18        for (int j = i + 1; j < nodes.size(); j++) {  
19            var node1 = nodes.get(i);  
20            var node2 = nodes.get(j);  
21  
22            var diff = node1.subtract(node2);  
23            var antiNode1 = node1.translate(diff);  
24            while (bounds.inBounds(antiNode1)) {  
25                antiNodes.add(antiNode1);  
26                antiNode1 = antiNode1.translate(diff);  
27            }  
28  
29            var invertedDiff = diff.inverse();  
30            var antiNode2 = node2.translate(invertedDiff);  
31            while (bounds.inBounds(antiNode2)) {  
32                antiNodes.add(antiNode2);  
33                antiNode2 = antiNode2.translate(invertedDiff);  
34            }  
35        }  
36    }  
37  
38    return antiNodes.stream();  
39}

See also