Browse Source

Completed day 12 part 1

Tyler Hallada 4 years ago
parent
commit
e5f615cf48
4 changed files with 324 additions and 6 deletions
  1. 34 0
      inputs/12.txt
  2. 16 0
      inputs/12_test.txt
  3. 265 0
      src/day12.rs
  4. 9 6
      src/main.rs

+ 34 - 0
inputs/12.txt

@@ -0,0 +1,34 @@
1
+initial state: ##.##.##..#..#.#.#.#...#...#####.###...#####.##..#####.#..#.##..#..#.#...#...##.##...#.##......####.
2
+
3
+##.#. => #
4
+#.#.. => #
5
+##... => .
6
+...## => #
7
+###.# => #
8
+#.##. => #
9
+#.### => #
10
+####. => #
11
+.#..# => #
12
+...#. => .
13
+#..#. => .
14
+#.#.# => .
15
+.##.# => .
16
+..#.. => .
17
+.#.## => #
18
+..##. => .
19
+.#.#. => #
20
+#..## => #
21
+..#.# => #
22
+#.... => .
23
+..### => .
24
+#...# => .
25
+##### => #
26
+###.. => #
27
+....# => .
28
+##.## => #
29
+.#### => .
30
+..... => .
31
+##..# => #
32
+.##.. => .
33
+.###. => .
34
+.#... => #

+ 16 - 0
inputs/12_test.txt

@@ -0,0 +1,16 @@
1
+initial state: #..#.#..##......###...###
2
+
3
+...## => #
4
+..#.. => #
5
+.#... => #
6
+.#.#. => #
7
+.#.## => #
8
+.##.. => #
9
+.#### => #
10
+#.#.# => #
11
+#.### => #
12
+##.#. => #
13
+##.## => #
14
+###.. => #
15
+###.# => #
16
+####. => #

+ 265 - 0
src/day12.rs

@@ -0,0 +1,265 @@
1
+extern crate regex;
2
+
3
+use std::collections::{HashMap, VecDeque};
4
+use std::error::Error;
5
+use std::fmt;
6
+use std::fs;
7
+use std::result;
8
+use std::str::FromStr;
9
+
10
+use regex::Regex;
11
+
12
+type Result<T> = result::Result<T, Box<Error>>;
13
+
14
+const INPUT: &str = "inputs/12.txt";
15
+
16
+#[derive(Debug, PartialEq)]
17
+struct Pots(VecDeque<bool>);
18
+
19
+#[derive(Debug, PartialEq)]
20
+struct SpreadRules(HashMap<[bool; 5], bool>);
21
+
22
+#[derive(Debug, PartialEq)]
23
+struct GrowthSimulation {
24
+    pots: Pots,
25
+    spread_rules: SpreadRules,
26
+    generations: usize,
27
+}
28
+
29
+impl fmt::Display for Pots {
30
+    #[allow(clippy::write_with_newline)]
31
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32
+        for pot in self.0.iter() {
33
+            if *pot {
34
+                write!(f, "#")?;
35
+            } else {
36
+                write!(f, ".")?;
37
+            }
38
+        }
39
+        write!(f, "\n")?;
40
+        Ok(())
41
+    }
42
+}
43
+
44
+impl fmt::Display for SpreadRules {
45
+    #[allow(clippy::write_with_newline)]
46
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47
+        for (pattern, result) in self.0.iter() {
48
+            for pot in pattern {
49
+                if *pot {
50
+                    write!(f, "#")?;
51
+                } else {
52
+                    write!(f, ".")?;
53
+                }
54
+            }
55
+            write!(f, " => ")?;
56
+            if *result {
57
+                write!(f, "#")?;
58
+            } else {
59
+                write!(f, ".")?;
60
+            }
61
+            write!(f, "\n")?;
62
+        }
63
+        write!(f, "\n")?;
64
+        Ok(())
65
+    }
66
+}
67
+
68
+impl fmt::Display for GrowthSimulation {
69
+    #[allow(clippy::write_with_newline)]
70
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71
+        write!(f, "{}", self.pots)?;
72
+        write!(f, "\n")?;
73
+        write!(f, "{}", self.spread_rules)?;
74
+        Ok(())
75
+    }
76
+}
77
+
78
+impl FromStr for GrowthSimulation {
79
+    type Err = Box<Error>;
80
+
81
+    fn from_str(s: &str) -> Result<GrowthSimulation> {
82
+        let sections: Vec<&str> = s.split("\n\n").collect();
83
+        let (initial_state_str, spread_rules_str) = (sections[0], sections[1]);
84
+        let mut pots = Pots(VecDeque::new());
85
+        let mut spread_rules = SpreadRules(HashMap::new());
86
+
87
+        lazy_static! {
88
+            static ref initial_state_regex: Regex =
89
+                Regex::new(r"initial state: (?P<initial_state>[#.]+)").unwrap();
90
+            static ref spread_rules_regex: Regex =
91
+                Regex::new(r"(?P<pattern>[#.]{5}) => (?P<result>[#.])").unwrap();
92
+        }
93
+
94
+        let initial_state_captures = match initial_state_regex.captures(initial_state_str) {
95
+            None => {
96
+                return Err(From::from(
97
+                    "Malformed initial state, no fields could be found",
98
+                ));
99
+            }
100
+            Some(captures) => captures,
101
+        };
102
+
103
+        for pot in initial_state_captures["initial_state"].chars() {
104
+            pots.0.push_back(pot == '#');
105
+        }
106
+
107
+        for rule in spread_rules_str.lines() {
108
+            let spread_rules_captures = match spread_rules_regex.captures(rule) {
109
+                None => {
110
+                    return Err(From::from(
111
+                        "Malformed spread rules, no fields could be found",
112
+                    ));
113
+                }
114
+                Some(captures) => captures,
115
+            };
116
+
117
+            let mut pattern = [false; 5];
118
+            let pattern_vec: Vec<bool> = spread_rules_captures["pattern"]
119
+                .chars()
120
+                .map(|c| c == '#')
121
+                .collect();
122
+            pattern.copy_from_slice(&pattern_vec);
123
+            let result = &spread_rules_captures["result"] == "#";
124
+            spread_rules.0.insert(pattern, result);
125
+        }
126
+
127
+        Ok(GrowthSimulation { pots, spread_rules, generations: 0 })
128
+    }
129
+}
130
+
131
+impl GrowthSimulation {
132
+    fn advance_generation(&mut self) {
133
+        let mut next_generation = VecDeque::new();
134
+        let padding = &[false; 4];
135
+        let pots_slice = self.pots.0.as_slices();
136
+        let pots_slice = [padding, pots_slice.0, pots_slice.1, padding].concat();
137
+        for (index, pot_window) in pots_slice.windows(5).enumerate() {
138
+            match self.spread_rules.0.get(pot_window) {
139
+                Some(result) => {
140
+                    next_generation.push_back(*result);
141
+                },
142
+                None => {
143
+                    next_generation.push_back(pots_slice[2]);
144
+                },
145
+            }
146
+        }
147
+        self.pots = Pots(next_generation);
148
+        self.generations += 1;
149
+    }
150
+
151
+    fn sum_plant_indices(&self) -> i32 {
152
+        let mut sum: i32 = 0;
153
+        for (index, pot) in self.pots.0.iter().enumerate() {
154
+            if *pot {
155
+                let shifted_index = index as i32 - self.generations as i32 * 2;
156
+                sum += shifted_index;
157
+            }
158
+        }
159
+        sum
160
+    }
161
+}
162
+
163
+fn read_initial_state_and_rules(filename: &str) -> Result<GrowthSimulation> {
164
+    let input = fs::read_to_string(filename)?;
165
+    Ok(input.parse()?)
166
+}
167
+
168
+pub fn solve_part1() -> Result<i32> {
169
+    let mut growth_sim = read_initial_state_and_rules(INPUT)?;
170
+    for _ in 0..20 {
171
+        growth_sim.advance_generation();
172
+    }
173
+    Ok(growth_sim.sum_plant_indices())
174
+}
175
+
176
+pub fn solve_part2() -> Result<i32> {
177
+    let mut growth_sim = read_initial_state_and_rules(INPUT)?;
178
+    for _ in 0..50_000_000_000_i64 {
179
+        growth_sim.advance_generation();
180
+    }
181
+    Ok(growth_sim.sum_plant_indices())
182
+}
183
+
184
+#[cfg(test)]
185
+mod tests {
186
+    use super::*;
187
+
188
+    const TEST_INPUT: &str = "inputs/12_test.txt";
189
+    fn test_growth_sim() -> GrowthSimulation {
190
+        GrowthSimulation {
191
+            pots: Pots(VecDeque::from(vec![
192
+                true, false, false, true, false, true, false, false, true, true, false, false,
193
+                false, false, false, false, true, true, true, false, false, false, true, true,
194
+                true,
195
+            ])),
196
+            spread_rules: SpreadRules([
197
+                ([true, true, true, true, false], true),
198
+                ([true, true, false, true, true], true),
199
+                ([false, false, true, false, false], true),
200
+                ([false, true, false, false, false], true),
201
+                ([true, true, false, true, false], true),
202
+                ([false, true, true, true, true], true),
203
+                ([true, false, true, true, true], true),
204
+                ([true, true, true, false, true], true),
205
+                ([false, true, false, true, true], true),
206
+                ([true, false, true, false, true], true),
207
+                ([false, true, false, true, false], true),
208
+                ([false, true, true, false, false], true),
209
+                ([true, true, true, false, false], true),
210
+                ([false, false, false, true, true], true),
211
+            ]
212
+            .iter()
213
+            .cloned()
214
+            .collect()),
215
+            generations: 0,
216
+        }
217
+    }
218
+
219
+    #[test]
220
+    fn reads_initial_state_and_rules_file() {
221
+        let growth_sim = read_initial_state_and_rules(TEST_INPUT).unwrap();
222
+        assert_eq!(growth_sim, test_growth_sim());
223
+    }
224
+
225
+    #[test]
226
+    fn displays_growth_simulation() {
227
+        assert_eq!(
228
+            format!("{}", test_growth_sim()).lines().collect::<Vec<&str>>().sort(),
229
+            vec![
230
+                "#..#.#..##......###...###",
231
+                "",
232
+                "####. => #",
233
+                "##.## => #",
234
+                "..#.. => #",
235
+                ".#... => #",
236
+                "##.#. => #",
237
+                ".#### => #",
238
+                "#.### => #",
239
+                "###.# => #",
240
+                ".#.## => #",
241
+                "#.#.# => #",
242
+                ".#.#. => #",
243
+                ".##.. => #",
244
+                "###.. => #",
245
+                "...## => #",
246
+            ].sort()
247
+        );
248
+    }
249
+
250
+    #[test]
251
+    fn advances_simulation_by_one_generation() {
252
+        let mut growth_sim = test_growth_sim();
253
+        growth_sim.advance_generation();
254
+        assert_eq!(format!("{}", growth_sim.pots), "..#...#....#.....#..#..#..#..\n");
255
+    }
256
+
257
+    #[test]
258
+    fn returns_correct_sum_after_20_generations() {
259
+        let mut growth_sim = test_growth_sim();
260
+        for _ in 0..20 {
261
+            growth_sim.advance_generation();
262
+        }
263
+        assert_eq!(growth_sim.sum_plant_indices(), 325);
264
+    }
265
+}

+ 9 - 6
src/main.rs

@@ -14,6 +14,7 @@ mod day8;
14 14
 mod day9;
15 15
 mod day10;
16 16
 mod day11;
17
+mod day12;
17 18
 
18 19
 fn main() {
19 20
     // println!("Day 1:");
@@ -47,10 +48,12 @@ fn main() {
47 48
     // let parts = day10::solve_parts().unwrap();
48 49
     // println!("{}", parts.0);
49 50
     // println!("{}", parts.1);
50
-    println!("Day 11:");
51
-    let part1 = day11::solve_part1().unwrap();
52
-    println!("{},{}", part1.coord.x, part1.coord.y);
53
-    let part2 = day11::solve_part2().unwrap();
54
-    println!("{},{},{}", part2.coord.x, part2.coord.y, part2.size);
55
-    // println!("{}", parts.1);
51
+    // println!("Day 11:");
52
+    // let part1 = day11::solve_part1().unwrap();
53
+    // println!("{},{}", part1.coord.x, part1.coord.y);
54
+    // let part2 = day11::solve_part2().unwrap();
55
+    // println!("{},{},{}", part2.coord.x, part2.coord.y, part2.size);
56
+    println!("Day 12:");
57
+    println!("{}", day12::solve_part1().unwrap());
58
+    println!("{}", day12::solve_part2().unwrap());
56 59
 }