22//! https://adventofcode.com/2024/day/8
33
44use std:: { fs, io} ;
5+ use std:: collections:: { BTreeMap , BTreeSet } ;
6+ use std:: ops:: Range ;
57use std:: path:: Path ;
68
9+ use lib:: vector:: Vector ;
10+
11+ type Vec2 = Vector < i32 , 2 > ;
12+
713fn main ( ) {
814 let input = Input :: from_file ( format ! ( "{}/input.txt" , env!( "CARGO_MANIFEST_DIR" ) ) ) . expect ( "failed to read input" ) ;
915 //let input = Input::from_file(format!("{}/example1.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
10- println ! ( "{input:?}" ) ;
16+ // println!("{input:?}");
1117
1218 // Part 1
1319 println ! ( "Part 1: {}" , part1( & input) ) ;
@@ -17,24 +23,119 @@ fn main() {
1723}
1824
1925fn part1 ( input : & Input ) -> usize {
20- 0
26+ let mut freqs: BTreeMap < _ , Vec < _ > > = BTreeMap :: new ( ) ;
27+ for ( pos, c) in input. antennas . iter ( ) {
28+ freqs. entry ( * c) . or_default ( ) . push ( * pos) ;
29+ }
30+
31+ let mut antinodes = BTreeSet :: new ( ) ;
32+ for ( _, positions) in freqs. into_iter ( ) {
33+ for i in 0 ..positions. len ( ) {
34+ for j in 0 ..positions. len ( ) {
35+ if i == j {
36+ continue ;
37+ }
38+
39+ let p1 = positions[ i] ;
40+ let p2 = positions[ j] ;
41+
42+ let d = p2 - p1;
43+
44+ let a1 = p2 + d;
45+ if in_bounds ( & input. bounds , a1) {
46+ antinodes. insert ( a1) ;
47+ }
48+
49+ let a2 = p1 - d;
50+ if in_bounds ( & input. bounds , a2) {
51+ antinodes. insert ( a2) ;
52+ }
53+ }
54+ }
55+
56+ }
57+
58+ antinodes. len ( )
2159}
2260
2361fn part2 ( input : & Input ) -> usize {
24- 0
62+ let mut freqs: BTreeMap < _ , Vec < _ > > = BTreeMap :: new ( ) ;
63+ for ( pos, c) in input. antennas . iter ( ) {
64+ freqs. entry ( * c) . or_default ( ) . push ( * pos) ;
65+ }
66+
67+ let mut antinodes = BTreeSet :: new ( ) ;
68+ for ( _, positions) in freqs. into_iter ( ) {
69+ for i in 0 ..positions. len ( ) {
70+ for j in 0 ..positions. len ( ) {
71+ if i == j {
72+ continue ;
73+ }
74+
75+ let p1 = positions[ i] ;
76+ let p2 = positions[ j] ;
77+
78+ let d = p2 - p1;
79+
80+ let mut p = p2;
81+ loop {
82+ if !in_bounds ( & input. bounds , p) {
83+ break ;
84+ }
85+
86+ antinodes. insert ( p) ;
87+ p += d;
88+ }
89+
90+ let mut p = p1;
91+ loop {
92+ if !in_bounds ( & input. bounds , p) {
93+ break ;
94+ }
95+
96+ antinodes. insert ( p) ;
97+ p -= d;
98+ }
99+ }
100+ }
101+ }
102+
103+ antinodes. len ( )
104+ }
105+
106+ fn in_bounds ( bounds : & ( Range < i32 > , Range < i32 > ) , pos : Vec2 ) -> bool {
107+ bounds. 0 . contains ( & pos[ 0 ] ) && bounds. 1 . contains ( & pos[ 1 ] )
25108}
26109
27110#[ derive( Debug , Clone ) ]
28111struct Input {
29- values : Vec < String > ,
112+ bounds : ( Range < i32 > , Range < i32 > ) ,
113+ antennas : BTreeMap < Vec2 , char > ,
30114}
31115
32116impl Input {
33117 fn from_file ( path : impl AsRef < Path > ) -> io:: Result < Self > {
34118 let input = fs:: read_to_string ( path) ?;
35- let values = input. lines ( ) . map ( str:: to_string) . collect ( ) ;
36119
37- Ok ( Self { values } )
120+ let mut width = 0 ;
121+ let mut height = 0 ;
122+ let mut antennas = BTreeMap :: new ( ) ;
123+ for ( y, line) in input. lines ( ) . enumerate ( ) {
124+ for ( x, c) in line. trim ( ) . chars ( ) . enumerate ( ) {
125+ let pos = Vector :: new ( [ x as i32 , y as i32 ] ) ;
126+
127+ if c != '.' {
128+ antennas. insert ( pos, c) ;
129+ }
130+
131+ width = x as i32 + 1 ;
132+ height = y as i32 + 1 ;
133+ }
134+ }
135+
136+ let bounds = ( 0 ..width, 0 ..height) ;
137+
138+ Ok ( Self { bounds, antennas } )
38139 }
39140}
40141
@@ -46,27 +147,27 @@ mod test {
46147 fn test_part1 ( ) {
47148 let input = Input :: from_file ( "example1.txt" ) . unwrap ( ) ;
48149
49- assert_eq ! ( part1( & input) , 0 ) ;
150+ assert_eq ! ( part1( & input) , 14 ) ;
50151 }
51152
52153 #[ test]
53154 fn test_part1_solution ( ) {
54155 let input = Input :: from_file ( "input.txt" ) . unwrap ( ) ;
55156
56- assert_eq ! ( part1( & input) , 0 ) ;
157+ assert_eq ! ( part1( & input) , 423 ) ;
57158 }
58159
59160 #[ test]
60161 fn test_part2 ( ) {
61162 let input = Input :: from_file ( "example1.txt" ) . unwrap ( ) ;
62163
63- assert_eq ! ( part2( & input) , 0 ) ;
164+ assert_eq ! ( part2( & input) , 34 ) ;
64165 }
65166
66167 #[ test]
67168 fn test_part2_solution ( ) {
68169 let input = Input :: from_file ( "input.txt" ) . unwrap ( ) ;
69170
70- assert_eq ! ( part2( & input) , 0 ) ;
171+ assert_eq ! ( part2( & input) , 1287 ) ;
71172 }
72173}
0 commit comments