1
1
use crate :: data:: load;
2
2
use ndarray:: prelude:: * ;
3
- use thiserror:: Error ;
4
-
5
- #[ derive( Error , Debug , PartialEq , Eq ) ]
6
- pub enum PuzzleErr {
7
- #[ error( "Unknown pipe character: {}." , . 0 ) ]
8
- UnknownPipeChar ( String ) ,
9
- }
3
+ use std:: iter:: zip;
10
4
11
5
#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
12
6
struct Coord {
13
7
r : usize ,
14
8
c : usize ,
15
9
}
16
10
11
+ impl Coord {
12
+ fn t ( & self ) -> Self {
13
+ Self {
14
+ r : self . c ,
15
+ c : self . r ,
16
+ }
17
+ }
18
+
19
+ fn dist ( & self , other : & Self ) -> usize {
20
+ self . r . abs_diff ( other. r ) + self . c . abs_diff ( other. c )
21
+ }
22
+ }
23
+
17
24
#[ derive( Debug , Clone ) ]
18
25
struct CosmicMap {
19
26
arr : Array2 < u8 > ,
20
27
galaxies : Vec < Coord > ,
21
28
}
22
29
23
- fn parse_map ( input : & str ) -> Result < CosmicMap , PuzzleErr > {
30
+ impl CosmicMap {
31
+ fn t ( & self ) -> Self {
32
+ Self {
33
+ arr : self . arr . t ( ) . to_owned ( ) ,
34
+ galaxies : self . galaxies . iter ( ) . map ( |c| c. t ( ) ) . collect ( ) ,
35
+ }
36
+ }
37
+ }
38
+
39
+ fn parse_map ( input : & str ) -> CosmicMap {
24
40
let lines = input. trim ( ) . lines ( ) . map ( |l| l. trim ( ) ) . collect :: < Vec < _ > > ( ) ;
25
41
let width = lines. first ( ) . unwrap ( ) . len ( ) ;
26
42
let height = lines. len ( ) ;
@@ -34,63 +50,57 @@ fn parse_map(input: &str) -> Result<CosmicMap, PuzzleErr> {
34
50
}
35
51
}
36
52
}
37
- Ok ( CosmicMap { arr, galaxies } )
53
+ CosmicMap { arr, galaxies }
38
54
}
39
55
40
- fn _expand_arr_rows ( arr : Array2 < u8 > ) -> Array2 < u8 > {
41
- let mut vecs = Vec :: new ( ) ;
42
-
43
- let mut nrows = 0 ;
44
- for r in arr. rows ( ) {
45
- nrows += 1 ;
46
- vecs. extend_from_slice ( r. to_vec ( ) . as_slice ( ) ) ;
47
- if r. sum ( ) == 0 {
48
- nrows += 1 ;
49
- vecs. extend_from_slice ( r. to_vec ( ) . as_slice ( ) ) ;
56
+ fn calculate_dists ( coords : & [ Coord ] ) -> Vec < usize > {
57
+ let mut dists = Vec :: new ( ) ;
58
+ for ( i, a) in coords. iter ( ) . enumerate ( ) {
59
+ for b in coords[ ( i + 1 ) ..] . iter ( ) {
60
+ dists. push ( a. dist ( b) )
50
61
}
51
62
}
52
- Array2 :: from_shape_vec ( ( nrows , arr . ncols ( ) ) , vecs ) . unwrap ( )
63
+ dists
53
64
}
54
65
55
- fn _locate_galaxies ( arr : & Array2 < u8 > ) -> Vec < Coord > {
56
- let mut galaxies = Vec :: new ( ) ;
57
- for i in 0 ..arr. nrows ( ) {
58
- for j in 0 ..arr. ncols ( ) {
59
- if arr. get ( ( i, j) ) . unwrap ( ) == & 1 {
60
- galaxies. push ( Coord { r : i, c : j } )
61
- }
66
+ fn expand_galaxies ( map : & CosmicMap , ex_rate : usize ) -> Vec < Coord > {
67
+ let x = match ex_rate {
68
+ 0 ..=1 => ex_rate,
69
+ _ => ex_rate - 1 ,
70
+ } ;
71
+ let coords = map. galaxies . clone ( ) ;
72
+ let mut add_rs = ( 0 ..coords. len ( ) ) . map ( |_| 0 ) . collect :: < Vec < _ > > ( ) ;
73
+
74
+ for i in 0 ..map. arr . nrows ( ) {
75
+ if map. arr . row ( i) . sum ( ) == 0 {
76
+ add_rs = zip ( & coords, add_rs)
77
+ . map ( |( coord, add_r) | if coord. r > i { add_r + x } else { add_r } )
78
+ . collect ( ) ;
62
79
}
63
80
}
64
- galaxies
65
- }
66
81
67
- fn expand_map ( map : CosmicMap ) -> CosmicMap {
68
- let arr = _expand_arr_rows ( map. arr ) ;
69
- let arr = _expand_arr_rows ( arr. t ( ) . to_owned ( ) ) . t ( ) . to_owned ( ) ;
70
- let galaxies = _locate_galaxies ( & arr) ;
71
- CosmicMap { arr, galaxies }
82
+ zip ( coords, add_rs)
83
+ . map ( |( coord, add_r) | Coord {
84
+ r : coord. r + add_r,
85
+ c : coord. c ,
86
+ } )
87
+ . collect ( )
72
88
}
73
89
74
- fn calculate_dists ( map : & CosmicMap ) -> Vec < usize > {
75
- let mut dists = Vec :: new ( ) ;
76
- for ( i, a) in map. galaxies . iter ( ) . enumerate ( ) {
77
- for b in map. galaxies [ ( i + 1 ) ..] . iter ( ) {
78
- dists. push ( a. r . abs_diff ( b. r ) + a. c . abs_diff ( b. c ) )
79
- }
80
- }
81
- dists
90
+ fn _solve ( input : & str , expansion_size : usize ) -> usize {
91
+ let mut map = parse_map ( input) ;
92
+ map. galaxies = expand_galaxies ( & map, expansion_size) ;
93
+ map = map. t ( ) ;
94
+ map. galaxies = expand_galaxies ( & map, expansion_size) ;
95
+ calculate_dists ( & map. galaxies ) . iter ( ) . sum ( )
82
96
}
83
97
84
- pub fn puzzle_1 ( input : & str ) -> Result < usize , PuzzleErr > {
85
- let map = parse_map ( input) ?;
86
- log:: info!( "STARTING MAP:\n {:?}" , map. arr) ;
87
- log:: info!( "Galaxy locations: {:?}" , map. galaxies) ;
88
-
89
- let map = expand_map ( map) ;
90
- log:: info!( "EXPANDED MAP:\n {:?}" , map. arr) ;
91
- log:: info!( "Galaxy locations: {:?}" , map. galaxies) ;
98
+ pub fn puzzle_1 ( input : & str ) -> usize {
99
+ _solve ( input, 1 )
100
+ }
92
101
93
- Ok ( calculate_dists ( & map) . iter ( ) . sum ( ) )
102
+ pub fn puzzle_2 ( input : & str , expansion_size : usize ) -> usize {
103
+ _solve ( input, expansion_size)
94
104
}
95
105
96
106
pub fn main ( data_dir : & str ) {
@@ -99,17 +109,11 @@ pub fn main(data_dir: &str) {
99
109
100
110
// Puzzle 1.
101
111
let answer_1 = puzzle_1 ( & data) ;
102
- match answer_1 {
103
- Ok ( x) => println ! ( " Puzzle 1: {}" , x) ,
104
- Err ( e) => panic ! ( "No solution to puzzle 1: {}." , e) ,
105
- }
106
- assert_eq ! ( answer_1, Ok ( 9724940 ) ) ;
112
+ println ! ( " Puzzle 1: {}" , answer_1) ;
113
+ assert_eq ! ( answer_1, 9724940 ) ;
107
114
108
115
// Puzzle 2.
109
- // let answer_2 = puzzle_2(&data);
110
- // match answer_2 {
111
- // Ok(x) => println!(" Puzzle 2: {}", x),
112
- // Err(e) => panic!("No solution to puzzle 2: {}", e),
113
- // }
114
- // assert_eq!(answer_2, Ok(933))
116
+ let answer_2 = puzzle_2 ( & data, 1000000 ) ;
117
+ println ! ( " Puzzle 1: {}" , answer_2) ;
118
+ assert_eq ! ( answer_2, 569052586852 ) ;
115
119
}
0 commit comments