use std::collections::HashMap; use std::fs; use std::path::Path; // Type alias to simplify the complex type type StepsRules = (Vec, HashMap); fn gcd(a: u64, b: u64) -> u64 { if b == 0 { a } else { gcd(b, a % b) } } fn lcm(a: u64, b: u64) -> u64 { a / gcd(a, b) * b } fn parse_file(file_path: &Path) -> Result { let data = fs::read_to_string(file_path).map_err(|e| e.to_string())?; let mut sections = data.trim().split("\n\n"); let steps = sections .next() .unwrap() .chars() .map(|c| if c == 'L' { 0 } else { 1 }) .collect(); let rules_section = sections.next().unwrap(); let mut rules = HashMap::new(); for line in rules_section.lines() { let mut parts = line.split('=').map(str::trim); let state = parts.next().unwrap().to_string(); let directions = parts .next() .unwrap() .split(',') .map(str::trim) .map(|s| s.trim_matches(|c: char| c == '(' || c == ')').to_string()) .collect::>(); rules.insert(state, (directions[0].clone(), directions[1].clone())); } Ok((steps, rules)) } fn navigate_network_simultaneously(steps: &[u8], rules: &HashMap) -> u64 { let start_nodes: Vec = rules.keys().filter(|k| k.ends_with('A')).cloned().collect(); let mut current_nodes = start_nodes.clone(); let mut step_count = 0; let mut time_to_z = HashMap::new(); while time_to_z.len() < start_nodes.len() { for (i, node) in current_nodes.iter_mut().enumerate() { let direction = if steps[step_count % steps.len()] == 0 { 'L' } else { 'R' }; let next_node = if direction == 'L' { &rules[node].0 } else { &rules[node].1 }; *node = next_node.clone(); if next_node.ends_with('Z') && !time_to_z.contains_key(&i) { time_to_z.insert(i, step_count + 1); } } if time_to_z.len() == start_nodes.len() { break; } step_count += 1; println!("Step {}: Current nodes - {:?}", step_count, current_nodes); } time_to_z.values().fold(1, |acc, &val| lcm(acc, val as u64)) } fn run_test(test_path: &Path) { println!("Running test..."); let (steps, rules) = parse_file(test_path).expect("Failed to parse test file"); let result = navigate_network_simultaneously(&steps, &rules); assert_eq!(result, 6, "Test failed: expected 6, got {}", result); println!("Test passed with {} steps.", result); } fn main() { let test_path = Path::new("../test.txt"); run_test(test_path); // Removed needless borrow let input_path = Path::new("../input.txt"); let (steps, rules) = parse_file(input_path).expect("Failed to parse input file"); // Removed needless borrow let result = navigate_network_simultaneously(&steps, &rules); // Calculate result for input file println!( "All paths reached 'Z' nodes simultaneously in {} steps.", result ); }