@@ -6,31 +6,35 @@ import grid.{type Pos}
6
6
import parse
7
7
8
8
pub fn part1 ( input : String ) -> Int {
9
- let # ( antennas , width , height ) = parse_input ( input )
9
+ let # ( map , in_bounds ) = parse_input ( input )
10
10
11
- antennas
12
- |> dict . keys
13
- |> list . flat_map ( fn ( label ) { antinodes_for ( antennas , label , width , height ) } )
11
+ map
12
+ |> dict . values
13
+ |> list . flat_map ( fn ( antennas ) { antinodes_for ( antennas , in_bounds ) } )
14
14
|> list . unique
15
15
|> list . length
16
16
}
17
17
18
- fn antinodes_for (
19
- antennas : Dict ( String , List ( Pos ) ) ,
20
- label : String ,
21
- width : Int ,
22
- height : Int ,
23
- ) -> List ( Pos ) {
18
+ pub fn part2 ( input : String ) -> Int {
19
+ let # ( map , in_bounds ) = parse_input ( input )
20
+
21
+ map
22
+ |> dict . values
23
+ |> list . flat_map ( fn ( antennas ) { harmonic_antinodes_for ( antennas , in_bounds ) } )
24
+ |> list . unique
25
+ |> list . length
26
+ }
27
+
28
+ type BoundFn =
29
+ fn ( Pos ) -> Bool
30
+
31
+ fn antinodes_for ( antennas : List ( Pos ) , in_bounds : BoundFn ) -> List ( Pos ) {
24
32
antennas
25
- |> dict . get ( label )
26
- |> result . unwrap ( [ ] )
27
33
|> list . combination_pairs
28
34
|> list . flat_map ( fn ( pair ) {
29
35
[ individual_antinode ( pair . 0 , pair . 1 ) , individual_antinode ( pair . 1 , pair . 0 ) ]
30
36
} )
31
- |> list . filter ( fn ( pos ) {
32
- pos . 0 >= 0 && pos . 0 < width && pos . 1 >= 0 && pos . 1 < height
33
- } )
37
+ |> list . filter ( in_bounds )
34
38
}
35
39
36
40
fn individual_antinode ( a : Pos , b : Pos ) -> Pos {
@@ -39,7 +43,40 @@ fn individual_antinode(a: Pos, b: Pos) -> Pos {
39
43
# ( a . 0 + dx , a . 1 + dy )
40
44
}
41
45
42
- fn parse_input ( input : String ) -> # ( Dict ( String , List ( Pos ) ) , Int , Int ) {
46
+ fn harmonic_antinodes_for ( antennas : List ( Pos ) , in_bounds : BoundFn ) -> List ( Pos ) {
47
+ antennas
48
+ |> list . combination_pairs
49
+ |> list . flat_map ( fn ( pair ) {
50
+ [
51
+ find_harmonic_antinodes ( pair . 0 , pair . 1 , in_bounds ) ,
52
+ find_harmonic_antinodes ( pair . 1 , pair . 0 , in_bounds ) ,
53
+ ]
54
+ } )
55
+ |> list . flatten
56
+ }
57
+
58
+ fn find_harmonic_antinodes ( a : Pos , b : Pos , in_bounds : BoundFn ) -> List ( Pos ) {
59
+ let dx = a . 0 - b . 0
60
+ let dy = a . 1 - b . 1
61
+
62
+ next_harmonic_antinode ( a , dx , dy , in_bounds , [ a ] )
63
+ }
64
+
65
+ fn next_harmonic_antinode (
66
+ a : Pos ,
67
+ dx : Int ,
68
+ dy : Int ,
69
+ in_bounds : BoundFn ,
70
+ nodes : List ( Pos ) ,
71
+ ) -> List ( Pos ) {
72
+ let node = # ( a . 0 + dx , a . 1 + dy )
73
+ case in_bounds ( node ) {
74
+ True -> next_harmonic_antinode ( node , dx , dy , in_bounds , [ node , .. nodes ] )
75
+ False -> nodes
76
+ }
77
+ }
78
+
79
+ fn parse_input ( input : String ) -> # ( Dict ( String , List ( Pos ) ) , BoundFn ) {
43
80
let lines = parse . lines ( input )
44
81
45
82
let pos_to_char =
@@ -56,6 +93,10 @@ fn parse_input(input: String) -> #(Dict(String, List(Pos)), Int, Int) {
56
93
let width = lines |> list . first |> result . unwrap ( "" ) |> string . length
57
94
let height = lines |> list . length
58
95
96
+ let in_bounds = fn ( p : Pos ) {
97
+ p . 0 >= 0 && p . 0 < width && p . 1 >= 0 && p . 1 < height
98
+ }
99
+
59
100
# (
60
101
pos_to_char
61
102
|> dict . values
@@ -74,7 +115,6 @@ fn parse_input(input: String) -> #(Dict(String, List(Pos)), Int, Int) {
74
115
)
75
116
} )
76
117
|> dict . from_list ,
77
- width ,
78
- height ,
118
+ in_bounds ,
79
119
)
80
120
}
0 commit comments