12
12
//!
13
13
//! Computing the result is simply multiplying the number of each element by its length. There are
14
14
//! 92 elements total so we can use a fixed size array to store the decay chain information.
15
+ //!
16
+ //! It would be possible (but less fun) to precompute all possible 92 answers into a
17
+ //! look up table.
15
18
use crate :: util:: hash:: * ;
16
19
17
20
const ELEMENTS : & str = "\
@@ -113,34 +116,34 @@ type Result = (usize, usize);
113
116
pub fn parse ( input : & str ) -> Result {
114
117
let elements: Vec < Vec < _ > > =
115
118
ELEMENTS . lines ( ) . map ( |line| line. split_ascii_whitespace ( ) . collect ( ) ) . collect ( ) ;
116
- let mut indices = FastMap :: with_capacity ( 92 ) ;
119
+ let mut indices = FastMap :: with_capacity ( 92 * 2 ) ;
117
120
121
+ // Map both sequence and element name to indices.
118
122
for ( i, tokens) in elements. iter ( ) . enumerate ( ) {
123
+ indices. insert ( tokens[ 0 ] , i) ;
119
124
indices. insert ( tokens[ 2 ] , i) ;
120
125
}
121
126
122
- let mut sequence = [ "" ; 92 ] ;
123
- let mut decays = [ [ None ; 6 ] ; 92 ] ;
127
+ // Build list of decay chains.
128
+ let sizes: Vec < _ > = elements. iter ( ) . map ( |e| e[ 0 ] . len ( ) ) . collect ( ) ;
129
+ let decays: Vec < Vec < _ > > =
130
+ elements. iter ( ) . map ( |e| e[ 4 ..] . iter ( ) . map ( |t| indices[ t] ) . collect ( ) ) . collect ( ) ;
124
131
125
- for ( i, tokens) in elements. iter ( ) . enumerate ( ) {
126
- sequence[ i] = tokens[ 0 ] ;
127
- for ( j, & token) in tokens. iter ( ) . skip ( 4 ) . enumerate ( ) {
128
- decays[ i] [ j] = Some ( indices[ token] ) ;
129
- }
130
- }
132
+ // Each input is a single element.
133
+ let mut current = [ 0 ; 92 ] ;
134
+ current[ indices[ input. trim ( ) ] ] = 1 ;
131
135
132
- let mut current = initial_state ( input, & sequence) ;
133
136
for _ in 0 ..40 {
134
137
current = step ( & current, & decays) ;
135
138
}
139
+ let part1 = length ( & current, & sizes) ;
136
140
137
- let result1 = length ( & current, & sequence) ;
138
141
for _ in 0 ..10 {
139
142
current = step ( & current, & decays) ;
140
143
}
144
+ let part2 = length ( & current, & sizes) ;
141
145
142
- let result2 = length ( & current, & sequence) ;
143
- ( result1, result2)
146
+ ( part1, part2)
144
147
}
145
148
146
149
pub fn part1 ( input : & Result ) -> usize {
@@ -151,31 +154,20 @@ pub fn part2(input: &Result) -> usize {
151
154
input. 1
152
155
}
153
156
154
- fn initial_state ( input : & str , sequence : & [ & str ] ) -> [ usize ; 92 ] {
155
- let input = input. trim ( ) ;
156
- let start = sequence. iter ( ) . position ( |& s| s == input) . unwrap ( ) ;
157
-
158
- let mut current = [ 0 ; 92 ] ;
159
- current[ start] += 1 ;
160
- current
161
- }
162
-
163
- fn step ( current : & [ usize ; 92 ] , decays : & [ [ Option < usize > ; 6 ] ; 92 ] ) -> [ usize ; 92 ] {
157
+ fn step ( current : & [ usize ] , decays : & [ Vec < usize > ] ) -> [ usize ; 92 ] {
164
158
let mut next = [ 0 ; 92 ] ;
165
159
166
- for i in 0 ..92 {
167
- let c = current[ i] ;
168
- if c > 0 {
169
- let mut iter = decays[ i] . iter ( ) ;
170
- while let Some ( Some ( index) ) = iter. next ( ) {
171
- next[ * index] += c;
160
+ for ( i, & count) in current. iter ( ) . enumerate ( ) {
161
+ if count > 0 {
162
+ for & element in & decays[ i] {
163
+ next[ element] += count;
172
164
}
173
165
}
174
166
}
175
167
176
168
next
177
169
}
178
170
179
- fn length ( current : & [ usize ; 92 ] , sequence : & [ & str ; 92 ] ) -> usize {
180
- current. iter ( ) . zip ( sequence . iter ( ) ) . map ( |( c, s) | c * s. len ( ) ) . sum ( )
171
+ fn length ( current : & [ usize ] , sizes : & [ usize ] ) -> usize {
172
+ current. iter ( ) . zip ( sizes . iter ( ) ) . map ( |( c, s) | c * s) . sum ( )
181
173
}
0 commit comments