-
Notifications
You must be signed in to change notification settings - Fork 0
/
day8.rs
125 lines (113 loc) · 3.14 KB
/
day8.rs
1
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use num_integer::lcm;
use rayon::iter::{ParallelBridge, ParallelIterator};
use std::{collections::BTreeMap, iter};
struct Network<'a> {
instructions: Vec<bool>,
table: BTreeMap<&'a str, (&'a str, &'a str)>,
}
impl<'a> Network<'a> {
fn step(&self, start: &'a str) -> Option<&'a str> {
self.instructions
.iter()
.try_fold(start, |node, &instruction| {
let (left, right) = self.table.get(node)?;
Some(*if instruction { left } else { right })
})
}
}
fn parse(data: &str) -> Option<Network> {
let mut iter = data.lines();
let instructions = iter
.next()?
.chars()
.map(|c| match c {
'L' => Some(true),
'R' => Some(false),
_ => None,
})
.collect::<Option<_>>()?;
let table = iter
.filter(|s| !s.is_empty())
.map(|line| {
let (from, to) = line.split_once(" = ")?;
let (left, right) = to.split_once(", ")?;
Some((from, (left.strip_prefix('(')?, right.strip_suffix(')')?)))
})
.collect::<Option<_>>()?;
Some(Network {
instructions,
table,
})
}
pub fn part1(data: &str) -> Option<usize> {
let network = parse(data)?;
Some(
network.instructions.len()
* iter::successors(Some("AAA"), |&node| network.step(node))
.position(|node| node == "ZZZ")?,
)
}
pub fn part2(data: &str) -> Option<usize> {
let network = parse(data)?;
Some(
network.instructions.len()
* network
.table
.keys()
.filter(|node| node.ends_with('A'))
.par_bridge()
.map(|&start| {
let (i, end) = iter::successors(Some(start), |&node| network.step(node))
.enumerate()
.find(|(_, node)| node.ends_with('Z'))?;
if network.step(start) == network.step(end) {
Some(i)
} else {
None
}
})
.try_reduce(|| 1, |x, y| Some(lcm(x, y)))?,
)
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
use pretty_assertions::assert_eq;
static EXAMPLE_1: &str = indoc! {"
RL
AAA = (BBB, CCC)
BBB = (DDD, EEE)
CCC = (ZZZ, GGG)
DDD = (DDD, DDD)
EEE = (EEE, EEE)
GGG = (GGG, GGG)
ZZZ = (ZZZ, ZZZ)
"};
static EXAMPLE_2: &str = indoc! {"
LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)
"};
static EXAMPLE_3: &str = indoc! {"
LR
11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
"};
#[test]
fn part1_examples() {
assert_eq!(Some(2), part1(EXAMPLE_1));
assert_eq!(Some(6), part1(EXAMPLE_2));
}
#[test]
fn part2_examples() {
assert_eq!(Some(6), part2(EXAMPLE_3));
}
}