Solve day 8 of AoC 2024
This commit is contained in:
parent
f6da5e2e12
commit
0c6bf7e054
6 changed files with 319 additions and 0 deletions
152
advent-of-code/2024/day_08/README.md
Normal file
152
advent-of-code/2024/day_08/README.md
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
# Day 8: Resonant Collinearity
|
||||||
|
|
||||||
|
[Advent of Code 2024](https://adventofcode.com/2024/day/8)
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
|
Scanning across the city, you find that there are actually many such antennas.
|
||||||
|
Each antenna is tuned to a specific frequency indicated by a single lowercase letter, uppercase letter, or digit.
|
||||||
|
You create a map (your puzzle input) of these antennas. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
............
|
||||||
|
........0...
|
||||||
|
.....0......
|
||||||
|
.......0....
|
||||||
|
....0.......
|
||||||
|
......A.....
|
||||||
|
............
|
||||||
|
............
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
............
|
||||||
|
............
|
||||||
|
```
|
||||||
|
|
||||||
|
The signal only applies its nefarious effect at specific antinodes based on the resonant frequencies of the antennas.
|
||||||
|
In particular, an antinode occurs at any point that is perfectly in line with two antennas of the same frequency - but only when
|
||||||
|
one of the antennas is twice as far away as the other. This means that for any pair of antennas with the same frequency,
|
||||||
|
there are two antinodes, one on either side of them.
|
||||||
|
|
||||||
|
So, for these two antennas with frequency a, they create the two antinodes marked with #:
|
||||||
|
|
||||||
|
```
|
||||||
|
..........
|
||||||
|
...#......
|
||||||
|
..........
|
||||||
|
....a.....
|
||||||
|
..........
|
||||||
|
.....a....
|
||||||
|
..........
|
||||||
|
......#...
|
||||||
|
..........
|
||||||
|
..........
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding a third antenna with the same frequency creates several more antinodes. It would ideally add four antinodes,
|
||||||
|
but two are off the right side of the map, so instead it adds only two:
|
||||||
|
|
||||||
|
```
|
||||||
|
..........
|
||||||
|
...#......
|
||||||
|
#.........
|
||||||
|
....a.....
|
||||||
|
........a.
|
||||||
|
.....a....
|
||||||
|
..#.......
|
||||||
|
......#...
|
||||||
|
..........
|
||||||
|
..........
|
||||||
|
```
|
||||||
|
|
||||||
|
Antennas with different frequencies don't create antinodes; A and a count as different frequencies.
|
||||||
|
However, antinodes can occur at locations that contain antennas. In this diagram, the lone antenna with frequency capital A
|
||||||
|
creates no antinodes but has a lowercase-a-frequency antinode at its location:
|
||||||
|
|
||||||
|
```
|
||||||
|
..........
|
||||||
|
...#......
|
||||||
|
#.........
|
||||||
|
....a.....
|
||||||
|
........a.
|
||||||
|
.....a....
|
||||||
|
..#.......
|
||||||
|
......A...
|
||||||
|
..........
|
||||||
|
..........
|
||||||
|
```
|
||||||
|
|
||||||
|
The first example has antennas with two different frequencies, so the antinodes they create look like this,
|
||||||
|
plus an antinode overlapping the topmost A-frequency antenna:
|
||||||
|
|
||||||
|
```
|
||||||
|
......#....#
|
||||||
|
...#....0...
|
||||||
|
....#0....#.
|
||||||
|
..#....0....
|
||||||
|
....0....#..
|
||||||
|
.#....A.....
|
||||||
|
...#........
|
||||||
|
#......#....
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
..........#.
|
||||||
|
..........#.
|
||||||
|
```
|
||||||
|
|
||||||
|
Because the topmost A-frequency antenna overlaps with a 0-frequency antinode, there are 14 total unique locations
|
||||||
|
that contain an antinode within the bounds of the map.
|
||||||
|
|
||||||
|
Calculate the impact of the signal. How many unique locations within the bounds of the map contain an antinode?
|
||||||
|
|
||||||
|
|
||||||
|
## Part Two
|
||||||
|
|
||||||
|
Watching over your shoulder as you work, one of The Historians asks if you took the effects of resonant harmonics into your calculations.
|
||||||
|
|
||||||
|
Whoops!
|
||||||
|
|
||||||
|
After updating your model, it turns out that an antinode occurs at any grid position exactly in line with at least two antennas
|
||||||
|
of the same frequency, regardless of distance. This means that some of the new antinodes will occur at the position
|
||||||
|
of each antenna (unless that antenna is the only one of its frequency).
|
||||||
|
|
||||||
|
So, these three T-frequency antennas now create many antinodes:
|
||||||
|
|
||||||
|
```
|
||||||
|
T....#....
|
||||||
|
...T......
|
||||||
|
.T....#...
|
||||||
|
.........#
|
||||||
|
..#.......
|
||||||
|
..........
|
||||||
|
...#......
|
||||||
|
..........
|
||||||
|
....#.....
|
||||||
|
..........
|
||||||
|
```
|
||||||
|
|
||||||
|
In fact, the three T-frequency antennas are all exactly in line with two antennas, so they are all also antinodes!
|
||||||
|
This brings the total number of antinodes in the above example to 9.
|
||||||
|
|
||||||
|
The original example now has 34 antinodes, including the antinodes that appear on every antenna:
|
||||||
|
|
||||||
|
```
|
||||||
|
##....#....#
|
||||||
|
.#.#....0...
|
||||||
|
..#.#0....#.
|
||||||
|
..##...0....
|
||||||
|
....0....#..
|
||||||
|
.#...#A....#
|
||||||
|
...#..#.....
|
||||||
|
#....#.#....
|
||||||
|
..#.....A...
|
||||||
|
....#....A..
|
||||||
|
.#........#.
|
||||||
|
...#......##
|
||||||
|
```
|
||||||
|
|
||||||
|
Calculate the impact of the signal using this updated model. How many unique locations within the bounds of the map contain an antinode?
|
50
advent-of-code/2024/day_08/input.txt
Normal file
50
advent-of-code/2024/day_08/input.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
..........M..........j.............y.....O........
|
||||||
|
...B...............q......m........lGO............
|
||||||
|
....................q......2.l.GQ...O.............
|
||||||
|
.....X.......................................4....
|
||||||
|
.....................q............................
|
||||||
|
....M......P...............xl.K.............2.....
|
||||||
|
....F.........L.......C.K..............m..........
|
||||||
|
..........FM......P....jy......m..........o...r...
|
||||||
|
..X.......P.....RL..............G..x..........4...
|
||||||
|
............L..........NC.....q...................
|
||||||
|
.....C.X...............K....y..........4..........
|
||||||
|
........S...R.............j.x.....V...4...........
|
||||||
|
.....................R..x.....V..i......m.........
|
||||||
|
...........................R.V......N.......X.....
|
||||||
|
.....F.........M......N......E....................
|
||||||
|
................v................T.......F......O.
|
||||||
|
.............................N...V.......Q........
|
||||||
|
...v.....................C.....i..................
|
||||||
|
......c.....W..n.w........................E.......
|
||||||
|
3...................c.....................Q..6....
|
||||||
|
...........h......................j...............
|
||||||
|
.......n.0......h.................E..............2
|
||||||
|
.v.............7.......120.....c..................
|
||||||
|
......n.0............w...........D.t.........E...r
|
||||||
|
....8..3......0.w.hP....z...D..T...............r..
|
||||||
|
.................f........T........G......eQ......
|
||||||
|
......f.n.....7..p................................
|
||||||
|
.....Y..7.......f......I......D......K............
|
||||||
|
............Uf....T..W.....D..r...i...............
|
||||||
|
......I...............................Z...........
|
||||||
|
....5....B.......b..............s..............Z..
|
||||||
|
..........d...W..Uwh.............c..........i.....
|
||||||
|
..I.3..Y......................e...................
|
||||||
|
.....p.b..........k......7........................
|
||||||
|
p...........k....I..b..........s..................
|
||||||
|
.....k.......o...........W........................
|
||||||
|
.A..Y..........U.................a........6.......
|
||||||
|
..A...Y.p...................................6.....
|
||||||
|
B......k..........................Z............u..
|
||||||
|
...3.....................s..............a.........
|
||||||
|
......A.........................g.....a...........
|
||||||
|
.......A....8...b.U......H....sS..................
|
||||||
|
.........................S1.............t.........
|
||||||
|
.....................9z..e.....5..1.g.u...........
|
||||||
|
.......................z....d....g....H.J....o.6..
|
||||||
|
........B................d.....u....9.J.H.........
|
||||||
|
.8........S.................u9.............J.....H
|
||||||
|
.....................Z5.............t1...........a
|
||||||
|
.....................e..v...................o..t..
|
||||||
|
.....8...............L.....z.............J........
|
83
advent-of-code/2024/day_08/lib.rb
Normal file
83
advent-of-code/2024/day_08/lib.rb
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
class Vec2
|
||||||
|
attr_accessor :x, :y
|
||||||
|
|
||||||
|
def initialize(x, y)
|
||||||
|
@x = x
|
||||||
|
@y = y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def count_antinodes(matrix, limit_length)
|
||||||
|
station_coords = extract_stations(matrix)
|
||||||
|
|
||||||
|
# Create zero matrix.
|
||||||
|
antinodes = Array.new(matrix.length) { Array.new(matrix[0].length, 0) }
|
||||||
|
|
||||||
|
station_coords.each_value do |loc|
|
||||||
|
(0..loc.length - 2).each do |i|
|
||||||
|
(i + 1..loc.length - 1).each do |j|
|
||||||
|
x_diff = loc[j].x - loc[i].x
|
||||||
|
y_diff = loc[j].y - loc[i].y
|
||||||
|
|
||||||
|
x1 = loc[i].x - x_diff
|
||||||
|
y1 = loc[i].y - y_diff
|
||||||
|
while in_range?(matrix, x1, y1)
|
||||||
|
antinodes[x1][y1] += 1
|
||||||
|
break if limit_length
|
||||||
|
|
||||||
|
x1 -= x_diff
|
||||||
|
y1 -= y_diff
|
||||||
|
end
|
||||||
|
|
||||||
|
x2 = loc[j].x + x_diff
|
||||||
|
y2 = loc[j].y + y_diff
|
||||||
|
while in_range?(matrix, x2, y2)
|
||||||
|
antinodes[x2][y2] += 1
|
||||||
|
break if limit_length
|
||||||
|
|
||||||
|
x2 += x_diff
|
||||||
|
y2 += y_diff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless limit_length
|
||||||
|
station_coords.each_value do |locations|
|
||||||
|
locations.each do |loc|
|
||||||
|
antinodes[loc.x][loc.y] += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
antinodes.each do |row|
|
||||||
|
row.each do |value|
|
||||||
|
next if value.zero?
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
count
|
||||||
|
end
|
||||||
|
|
||||||
|
def in_range?(matrix, x, y)
|
||||||
|
x >= 0 and y >= 0 and x < matrix.length and y < matrix[x].length
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_stations(matrix)
|
||||||
|
station_coords = {}
|
||||||
|
|
||||||
|
(0..matrix.length - 1).each do |x|
|
||||||
|
(0..matrix[x].length - 1).each do |y|
|
||||||
|
ch = matrix[x][y]
|
||||||
|
next if ch == '.'
|
||||||
|
|
||||||
|
station_coords[ch] = [] unless station_coords.include?(ch)
|
||||||
|
station_coords[ch].push(Vec2.new(x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
station_coords
|
||||||
|
end
|
8
advent-of-code/2024/day_08/main.rb
Normal file
8
advent-of-code/2024/day_08/main.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
require_relative "lib.rb"
|
||||||
|
|
||||||
|
input = File.readlines('input.txt', chomp: true)
|
||||||
|
res1 = count_antinodes(input, true)
|
||||||
|
puts("Part 1: #{res1}")
|
||||||
|
|
||||||
|
res2 = count_antinodes(input, false)
|
||||||
|
puts("Part 2: #{res2}")
|
14
advent-of-code/2024/day_08/test.rb
Normal file
14
advent-of-code/2024/day_08/test.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
require_relative "lib.rb"
|
||||||
|
require "test/unit"
|
||||||
|
|
||||||
|
class TestAntinodeCounter < Test::Unit::TestCase
|
||||||
|
def test_part_1
|
||||||
|
input = File.readlines("test.txt", chomp: true)
|
||||||
|
assert_equal(14, count_antinodes(input, true))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_part_2
|
||||||
|
input = File.readlines("test.txt", chomp: true)
|
||||||
|
assert_equal(34, count_antinodes(input, false))
|
||||||
|
end
|
||||||
|
end
|
12
advent-of-code/2024/day_08/test.txt
Normal file
12
advent-of-code/2024/day_08/test.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
............
|
||||||
|
........0...
|
||||||
|
.....0......
|
||||||
|
.......0....
|
||||||
|
....0.......
|
||||||
|
......A.....
|
||||||
|
............
|
||||||
|
............
|
||||||
|
........A...
|
||||||
|
.........A..
|
||||||
|
............
|
||||||
|
............
|
Loading…
Reference in a new issue