Skip to content

Commit 049fe97

Browse files
committed
Day 8 Part 1
1 parent 34eb6e4 commit 049fe97

File tree

4 files changed

+286
-0
lines changed

4 files changed

+286
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Each day will be setup as a separate folder.
1414
- [Day 5](/day-5/) - Print Queue
1515
- [Day 6](/day-6/) - Guard Gallivant
1616
- [Day 7](/day-7/) - Bridge Repair
17+
- [Day 8](/day-8/) - Resonant Collinearity
1718

1819
## Environment Setup
1920

day-8/README.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Day 8 - Resonant Collinearity
2+
3+
## Part 1
4+
5+
You find yourselves on the roof of a top-secret Easter Bunny installation.
6+
7+
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!
8+
9+
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:
10+
11+
```
12+
............
13+
........0...
14+
.....0......
15+
.......0....
16+
....0.......
17+
......A.....
18+
............
19+
............
20+
........A...
21+
.........A..
22+
............
23+
............
24+
```
25+
26+
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.
27+
28+
So, for these two antennas with frequency a, they create the two antinodes marked with #:
29+
30+
```
31+
..........
32+
...#......
33+
..........
34+
....a.....
35+
..........
36+
.....a....
37+
..........
38+
......#...
39+
..........
40+
..........
41+
```
42+
43+
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:
44+
45+
```
46+
..........
47+
...#......
48+
#.........
49+
....a.....
50+
........a.
51+
.....a....
52+
..#.......
53+
......#...
54+
..........
55+
..........
56+
```
57+
58+
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:
59+
60+
```
61+
..........
62+
...#......
63+
#.........
64+
....a.....
65+
........a.
66+
.....a....
67+
..#.......
68+
......A...
69+
..........
70+
..........
71+
```
72+
73+
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:
74+
75+
```
76+
......#....#
77+
...#....0...
78+
....#0....#.
79+
..#....0....
80+
....0....#..
81+
.#....A.....
82+
...#........
83+
#......#....
84+
........A...
85+
.........A..
86+
..........#.
87+
..........#.
88+
```
89+
90+
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.
91+
92+
Calculate the impact of the signal. How many unique locations within the bounds of the map contain an antinode?
93+
94+
## Part 2

day-8/main.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package main
2+
3+
import (
4+
_ "embed"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"strings"
9+
10+
"github.com/shaunburdick/advent-of-code-2024/lib/file"
11+
"github.com/shaunburdick/advent-of-code-2024/lib/grid"
12+
)
13+
14+
var input string
15+
16+
func init() {
17+
// do this in init (not main) so test file has same input
18+
inputFile, err := file.LoadRelativeFile("input.txt")
19+
if err != nil {
20+
log.Println(err)
21+
}
22+
23+
input = strings.TrimRight(inputFile, "\n")
24+
}
25+
26+
func main() {
27+
var part int
28+
flag.IntVar(&part, "part", 1, "part 1 or 2")
29+
flag.Parse()
30+
fmt.Println("Running part", part)
31+
32+
if part == 1 {
33+
ans := part1(input)
34+
fmt.Println("Output:", ans)
35+
} else {
36+
ans := part2(input)
37+
fmt.Println("Output:", ans)
38+
}
39+
}
40+
41+
func part1(input string) int {
42+
parsed := parseInput(input)
43+
antinodes := make(map[string]struct{})
44+
antennaMap := grid.Grid{Data: parsed}
45+
nodes := UniqueNodes(antennaMap)
46+
47+
for _, coords := range nodes {
48+
// if there are more than one instance of the node
49+
if len(coords) > 1 {
50+
for i, coordA := range coords {
51+
// apply to every other coord
52+
for _, coordB := range coords[i+1:] {
53+
antiNodeA := grid.Coords{X: 2*coordA.X - coordB.X, Y: 2*coordA.Y - coordB.Y}
54+
antiNodeB := grid.Coords{X: 2*coordB.X - coordA.X, Y: 2*coordB.Y - coordA.Y}
55+
56+
if antennaMap.InBounds(antiNodeA) {
57+
antinodes[antiNodeA.String()] = struct{}{}
58+
}
59+
60+
if antennaMap.InBounds(antiNodeB) {
61+
antinodes[antiNodeB.String()] = struct{}{}
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
return len(antinodes)
69+
}
70+
71+
func UniqueNodes(g grid.Grid) map[rune][]grid.Coords {
72+
nodes := make(map[rune][]grid.Coords)
73+
74+
for y, row := range g.Data {
75+
for x, char := range row {
76+
if char != '.' {
77+
if _, found := nodes[char]; !found {
78+
nodes[char] = []grid.Coords{}
79+
}
80+
81+
nodes[char] = append(nodes[char], grid.Coords{X: x, Y: y})
82+
}
83+
}
84+
}
85+
86+
return nodes
87+
}
88+
89+
func part2(input string) int {
90+
parsed := parseInput(input)
91+
_ = parsed
92+
93+
return 0
94+
}
95+
96+
func parseInput(input string) (ans []string) {
97+
return strings.Split(input, "\n")
98+
}

day-8/main_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
file "github.com/shaunburdick/advent-of-code-2024/lib/file"
7+
)
8+
9+
type TestDeclaration struct {
10+
name string
11+
input string
12+
want int
13+
run bool
14+
}
15+
16+
var example1 = `............
17+
........0...
18+
.....0......
19+
.......0....
20+
....0.......
21+
......A.....
22+
............
23+
............
24+
........A...
25+
.........A..
26+
............
27+
............`
28+
29+
func Test_day8_part1(t *testing.T) {
30+
tests := []TestDeclaration{
31+
{
32+
name: "example",
33+
input: example1,
34+
want: 14,
35+
run: true,
36+
},
37+
{
38+
name: "actual",
39+
input: input,
40+
want: 0,
41+
run: file.ExistsRelativeFile("input.txt"),
42+
},
43+
}
44+
for _, tt := range tests {
45+
if tt.run {
46+
t.Run(tt.name, func(t *testing.T) {
47+
if got := part1(tt.input); got != tt.want {
48+
t.Errorf("part1() = %v, want %v", got, tt.want)
49+
}
50+
})
51+
}
52+
}
53+
}
54+
55+
func Benchmark_day8_part1(b *testing.B) {
56+
for i := 0; i < b.N; i++ {
57+
part1(example1)
58+
}
59+
}
60+
61+
var example2 = ``
62+
63+
func Test_day8_part2(t *testing.T) {
64+
tests := []TestDeclaration{
65+
{
66+
name: "example",
67+
input: example2,
68+
want: 0,
69+
run: true,
70+
},
71+
{
72+
name: "actual",
73+
input: input,
74+
want: 0,
75+
run: file.ExistsRelativeFile("input.txt"),
76+
},
77+
}
78+
for _, tt := range tests {
79+
if tt.run {
80+
t.Run(tt.name, func(t *testing.T) {
81+
if got := part2(tt.input); got != tt.want {
82+
t.Errorf("part2() = %v, want %v", got, tt.want)
83+
}
84+
})
85+
}
86+
}
87+
}
88+
89+
func Benchmark_day8_part2(b *testing.B) {
90+
for i := 0; i < b.N; i++ {
91+
part2(example2)
92+
}
93+
}

0 commit comments

Comments
 (0)