summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-12-10 04:02:44 -0500
committerJesse Luehrs <doy@tozt.net>2023-12-10 04:02:44 -0500
commit9c29b9932d131136b37eb0e3b4a53b4c25a2903a (patch)
tree0cc87dd5eb8b5c4a9a2997f74bbb6f50dc48f8c4
parent5a045b5e92479bea54e20eeca27499809dcae1ef (diff)
downloadadvent-of-code-9c29b9932d131136b37eb0e3b4a53b4c25a2903a.tar.gz
advent-of-code-9c29b9932d131136b37eb0e3b4a53b4c25a2903a.zip
day 8 part 2
-rw-r--r--src/bin/2023/day8.rs67
1 files changed, 66 insertions, 1 deletions
diff --git a/src/bin/2023/day8.rs b/src/bin/2023/day8.rs
index 5b43ee5..a71c4ed 100644
--- a/src/bin/2023/day8.rs
+++ b/src/bin/2023/day8.rs
@@ -14,6 +14,17 @@ pub struct Network {
graph: HashMap<String, (String, String)>,
}
+fn gcd(mut a: usize, mut b: usize) -> usize {
+ loop {
+ let r = a % b;
+ if r == 0 {
+ return b;
+ }
+ a = b;
+ b = r;
+ }
+}
+
pub fn parse(fh: File) -> Result<Network> {
let mut lines = parse::raw_lines(fh);
let directions = lines.next().unwrap();
@@ -57,7 +68,61 @@ pub fn part1(network: Network) -> Result<i64> {
}
pub fn part2(network: Network) -> Result<i64> {
- todo!()
+ let vertices: Vec<String> = network
+ .graph
+ .keys()
+ .filter(|v| v.ends_with('A'))
+ .cloned()
+ .collect();
+
+ let mut cycles: HashMap<_, HashMap<(String, usize), Vec<usize>>> =
+ HashMap::new();
+ for start_vertex in vertices {
+ let mut seen = HashMap::new();
+ let mut vertex = start_vertex.clone();
+ let mut distance = 0;
+
+ loop {
+ if vertex.ends_with('Z') {
+ let entry: &mut Vec<_> = seen
+ .entry((
+ vertex.clone(),
+ distance % network.directions.len(),
+ ))
+ .or_default();
+ if entry.len() >= 2 {
+ break;
+ }
+ entry.push(distance);
+ }
+ let next = network.graph[&vertex].clone();
+ vertex = match network.directions
+ [distance % network.directions.len()]
+ {
+ Direction::Left => next.0,
+ Direction::Right => next.1,
+ };
+ distance += 1;
+ }
+ cycles.insert(
+ start_vertex,
+ seen.into_iter()
+ .filter(|(_, distances)| distances.len() == 2)
+ .collect(),
+ );
+ }
+
+ // this is pretty dumb but it looks like we're supposed to notice that
+ // the input data is very specifically shaped to make this easy
+ let cycles: Vec<_> = cycles
+ .values()
+ .map(|cycle| cycle.values().next().unwrap()[0])
+ .collect();
+ let gcd = cycles.iter().copied().reduce(gcd).unwrap();
+ Ok(i64::try_from(
+ gcd * cycles.iter().copied().map(|n| n / gcd).product::<usize>(),
+ )
+ .unwrap())
}
#[test]