---cargo [profile.dev] opt-level = 3 --- use std::collections::{HashMap, hash_map::Entry}; static CONTENT: &'static str = include_str!("./inputs/10_1.txt"); #[derive(Debug)] struct Machine { desired_lights: u64, buttons: Vec, } fn main() { let machines: Vec = CONTENT.lines() .map(|l| l.trim()) .map(|l| { let (lights, rest) = l.split_once(' ').unwrap(); let buttons: Vec<_> = rest.split(' ').take_while(|p| p.contains('(')).collect(); let joltage = rest.split(' ').skip_while(|p| p.contains('(')).next().unwrap(); (lights, buttons, joltage) }) .map(|(raw_lights, raw_buttons, raw_joltage)| { let raw_lights = raw_lights.strip_prefix('[').unwrap().strip_suffix(']').unwrap(); let lights = raw_lights.chars().enumerate().map(|(idx, c)| { let v = match c { '.' => 0, '#' => 1, c => unreachable!("{:?}", c), }; (idx, v) }).fold(0u64, |acc, (idx, v)| { acc + (v << idx) }); (lights, raw_buttons, raw_joltage) }) .map(|(lights, raw_buttons, raw_joltage)| { let buttons: Vec<_> = raw_buttons.iter().map(|button| { let button = button.strip_prefix('(').unwrap().strip_suffix(')').unwrap(); let switch: u64 = button.split(',').map(|c| { let v: u64 = c.parse().unwrap(); 1 << v }).fold(0u64, |acc, v| { acc + v }); switch }).collect(); (lights, buttons, raw_joltage) }) .map(|(lights, buttons, _)| { Machine { desired_lights: lights, buttons, } }) .collect(); println!("{:#?}", machines); let machine_states: Vec<_> = machines.iter().map(|machine| { let mut states: HashMap> = HashMap::new(); let mut queue = vec![0u64]; while let Some(state) = queue.pop() { let new_states: Vec<_> = machine.buttons.iter() .map(|button| { state ^ button }).collect(); match states.entry(state) { Entry::Occupied(_) => {} Entry::Vacant(ventry) => { let new_states = ventry.insert(new_states); queue.extend(new_states.iter().map(|v| *v)); } }; } states }).collect(); let distances: Vec<_> = machine_states.iter().map(|states| { let mut distances: HashMap, usize)> = states.keys().map(|node| { (*node, (None, usize::MAX)) }).collect(); let mut q: Vec = states.keys().copied().collect(); distances.insert(0, (None, 0)); while !q.is_empty() { q.sort_by_key(|n| core::cmp::Reverse(distances.get(n).map(|(_, d)| d).unwrap())); let u = q.pop().unwrap(); let (_, u_distance) = distances.get(&u).copied().unwrap(); for neighbour in states.get(&u).unwrap() { if !q.contains(neighbour) { continue; } let new_distance = u_distance.saturating_add(1); let (neighbour_prev, neighbour_distance) = distances.get_mut(&neighbour).unwrap(); if new_distance < *neighbour_distance { *neighbour_prev = Some(u); *neighbour_distance = new_distance; } } } distances }).collect(); let mut total_steps = 0; for ((machine, states), distances) in machines.iter().zip(machine_states.iter()).zip(distances.iter()) { println!("{:#?}", machine); //println!("States:\n{:#?}", states); //println!("Distances: {:#?}", distances); let (_, steps) = distances.get(&machine.desired_lights).unwrap(); println!("Required Steps: {}", steps); total_steps += steps; } println!("Required Total Steps: {}", total_steps); }