diff --git a/day8/rust/.gitignore b/day8/rust/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/day8/rust/.gitignore @@ -0,0 +1 @@ +target diff --git a/day8/rust/Cargo.lock b/day8/rust/Cargo.lock new file mode 100644 index 0000000..b21cc6a --- /dev/null +++ b/day8/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/day8/rust/Cargo.toml b/day8/rust/Cargo.toml new file mode 100644 index 0000000..1ec6963 --- /dev/null +++ b/day8/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/day8/rust/src/main.rs b/day8/rust/src/main.rs new file mode 100644 index 0000000..944be16 --- /dev/null +++ b/day8/rust/src/main.rs @@ -0,0 +1,182 @@ +enum Direction { + Left, + Right, +} + +#[derive(Debug, Clone)] +struct Node { + name: String, + left_name: String, + right_name: String, + left: Option, + right: Option, +} + +struct History { + node: usize, + idx: usize, +} + +#[derive(Debug)] +struct Period { + offset: usize, + period: usize, + z: Vec, +} + +fn main() { + let stdin = std::io::stdin(); + let mut first = true; + let mut instructions = Vec::new(); + let mut nodes = Vec::new(); + + for line in stdin.lines() { + let line = line.unwrap(); + + if line.len() == 0 && first { + first = false; + } else if first { + instructions = line + .chars() + .map(|e| { + return match e { + 'L' => Direction::Left, + 'R' => Direction::Right, + _ => unreachable!(), + }; + }) + .collect(); + } else { + let (name, paths) = line.split_once("=").unwrap(); + + let (left, right) = paths.split_once(",").unwrap(); + + let left: String = left.chars().filter(|e| *e != '(').collect(); + let right: String = right.chars().filter(|e| *e != ')').collect(); + + nodes.push(Node { + name: name.trim().into(), + left_name: left.trim().into(), + right_name: right.trim().into(), + left: None, + right: None, + }); + } + } + + let tmp = nodes.clone(); + + for node in &mut nodes { + for (i, candidate) in tmp.iter().enumerate() { + if candidate.name == node.left_name { + node.left = Some(i); + } + } + for (i, candidate) in tmp.iter().enumerate() { + if candidate.name == node.right_name { + node.right = Some(i); + } + } + } + + // Find starter + let mut curr = 0; + for (i, node) in nodes.iter().enumerate() { + if node.name == "AAA" { + curr = i; + break; + } + } + + let mut part1 = 0; + while nodes[curr].name != "ZZZ" { + if let Direction::Left = instructions[part1 % instructions.len()] { + curr = nodes[curr].left.unwrap(); + } else { + curr = nodes[curr].right.unwrap(); + } + + part1 += 1; + } + + println!("{}", part1); + + let mut currents = Vec::new(); + for (i, node) in nodes.iter().enumerate() { + if node.name.ends_with("A") { + currents.push(i); + } + } + + let mut periods = Vec::new(); + + for i in 0..currents.len() { + let mut step = 0; + let mut found = false; + let mut history = Vec::new(); + + while !found { + history.push(History { + node: currents[i], + idx: step % instructions.len(), + }); + + if let Direction::Left = instructions[step % instructions.len()] { + currents[i] = nodes[currents[i]].left.unwrap(); + } else { + currents[i] = nodes[currents[i]].right.unwrap(); + } + + step += 1; + + for (j, h) in history.iter().enumerate() { + if h.node == currents[i] && step % instructions.len() == h.idx { + found = true; + + let mut z = Vec::new(); + for k in j..history.len() { + if nodes[history[k].node].name.ends_with("Z") { + z.push(k - j); + } + } + + periods.push(Period { + offset: j, + period: history.len() - j, + z + }); + } + } + } + } + + let mut part2 = 0; + let mut found = false; + + let mut step = periods[0].offset; + while !found { + for z0 in &periods[0].z { + found = true; + part2 = step + *z0; + + for period in &periods { + let mut found2 = false; + for z in &period.z { + if (part2 - period.offset) % period.period == *z { + found2 = true; + break; + } + } + + if !found2 { + found = false; + break; + } + } + } + + step += periods[0].period; + } + + println!("{}", part2); +}