use core::panic; use std::{ collections::{HashMap, HashSet}, error::Error, }; pub fn process_part1(input: &str) -> u32 { let mut distances = HashMap::new(); let mut locations = HashSet::new(); input.lines().for_each(|line| { let (direction, distance) = line.split_once(" = ").unwrap(); let (from, to) = direction.split_once(" to ").unwrap(); let distance = distance.parse::().unwrap(); distances.insert((from.to_string(), to.to_string()), distance); locations.insert(from.to_string()); locations.insert(to.to_string()); }); let locations = locations .iter() .map(|place| place.to_string()) .collect::>(); let num_permutations = factorial(locations.len()); let mut shortest = u32::MAX; for idx in 1..=num_permutations { let perm = permutation(locations.clone(), idx).unwrap(); let route_length = get_route_length(perm, &distances); if route_length < shortest { shortest = route_length; } } shortest } fn get_route_length(route: Vec, distances: &HashMap<(String, String), u32>) -> u32 { route .windows(2) .map(|pair| { let distance = distances.get(&(pair[0].clone(), pair[1].clone())); if let Some(distance) = distance { return distance; } let distance = distances.get(&(pair[1].clone(), pair[0].clone())); if let Some(distance) = distance { return distance; } panic!("Should not happen"); }) .sum() } fn permutation(mut locations: Vec, nth: usize) -> Result, Box> { locations.sort(); if nth == 1 { return Ok(locations); } if nth > factorial(locations.len()) || nth == 0 { return Err(Box::from("Out of bounds")); } let mut perm = Vec::new(); let num_unique_locations = locations.len(); let mut remainder = nth - 1; for idx in 1..=locations.len() { let permutations = remainder / factorial(num_unique_locations - idx); remainder %= factorial(num_unique_locations - idx); perm.push(locations[permutations].clone()); locations.remove(permutations); } Ok(perm) } fn factorial(num: usize) -> usize { let mut fact = 1; for n in 1..=num { fact *= n; } fact } pub fn process_part2(input: &str) -> u32 { let mut distances = HashMap::new(); let mut locations = HashSet::new(); input.lines().for_each(|line| { let (direction, distance) = line.split_once(" = ").unwrap(); let (from, to) = direction.split_once(" to ").unwrap(); let distance = distance.parse::().unwrap(); distances.insert((from.to_string(), to.to_string()), distance); locations.insert(from.to_string()); locations.insert(to.to_string()); }); let locations = locations .iter() .map(|place| place.to_string()) .collect::>(); let num_permutations = factorial(locations.len()); let mut longest = 0; for idx in 1..=num_permutations { let perm = permutation(locations.clone(), idx).unwrap(); let route_length = get_route_length(perm, &distances); if route_length > longest { longest = route_length; } } longest } #[cfg(test)] mod tests { use super::*; const INPUT: &str = "London to Dublin = 464 London to Belfast = 518 Dublin to Belfast = 141"; #[test] fn part1() { let result = process_part1(INPUT); assert_eq!(result, 605); } #[test] fn part2() { let result = process_part2(INPUT); assert_eq!(result, 982); } }