generated from fspoettel/advent-of-code-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path08.rs
117 lines (93 loc) · 2.57 KB
/
08.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
advent_of_code::solution!(8);
use std::collections::HashMap;
type MyLocation = [char; 3];
struct State {
instructions: Vec<char>,
graph: HashMap<MyLocation, (MyLocation, MyLocation)>,
}
fn parse_data(input: &str) -> State {
let (instructions_str, graph_str) = input.split_once("\n\n").unwrap();
let instructions = instructions_str.chars().collect();
let mut graph = HashMap::new();
for line in graph_str.lines() {
let key = line[..3].chars().collect::<Vec<_>>().try_into().unwrap();
let left = line[7..10].chars().collect::<Vec<_>>().try_into().unwrap();
let right = line[12..15].chars().collect::<Vec<_>>().try_into().unwrap();
graph.insert(key, (left, right));
}
State {
instructions,
graph,
}
}
fn part_x<F>(state: &State, current_location: &MyLocation, end_predicate: F) -> u64
where
F: Fn(&MyLocation) -> bool,
{
let mut steps = 0;
let mut location = *current_location;
for instruction in state.instructions.iter().cycle() {
location = match instruction {
'L' => state.graph[&location].0,
'R' => state.graph[&location].1,
_ => unreachable!(),
};
steps += 1;
if end_predicate(&location) {
return steps;
}
}
unreachable!()
}
pub fn part_one(input: &str) -> Option<u64> {
let state = parse_data(input);
let location = state
.graph
.keys()
.find(|loc| loc == &&['A', 'A', 'A'])
.unwrap();
let result = part_x(&state, location, |loc| loc == &['Z', 'Z', 'Z']);
Some(result)
}
fn gcd(a: u64, b: u64) -> u64 {
let mut a = a;
let mut b = b;
while b != 0 {
(a, b) = (b, a % b);
}
a
}
fn lcm(a: u64, b: u64) -> u64 {
(a * b) / gcd(a, b)
}
pub fn part_two(input: &str) -> Option<u64> {
let state = parse_data(input);
let locations = state
.graph
.keys()
.filter(|loc| loc[2] == 'A')
.collect::<Vec<_>>();
let result = locations
.into_iter()
.map(|loc| part_x(&state, loc, |loc| loc[2] == 'Z'))
.fold(1, lcm);
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_two(&advent_of_code::template::read_file_part(
"examples", DAY, 1,
));
assert_eq!(result, Some(6));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file_part(
"examples", DAY, 2,
));
assert_eq!(result, Some(6));
}
}