AdventOfCode/y2015/src/days/d9.rs
2024-11-18 11:52:30 +01:00

97 lines
3.0 KiB
Rust

use core::panic;
use std::collections::{HashMap, HashSet};
use utils::{math::factorial, permutation::nth_lex};
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::<u32>().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::<Vec<String>>();
let num_permutations = factorial(locations.len().try_into().unwrap());
let mut shortest = u32::MAX;
for idx in 1..=num_permutations {
let perm = nth_lex(locations.clone(), idx.try_into().unwrap()).unwrap();
let route_length = get_route_length(perm, &distances);
if route_length < shortest {
shortest = route_length;
}
}
shortest
}
fn get_route_length(route: Vec<String>, 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()
}
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::<u32>().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::<Vec<String>>();
let num_permutations = factorial(locations.len().try_into().unwrap());
let mut longest = 0;
for idx in 1..=num_permutations {
let perm = nth_lex(locations.clone(), idx.try_into().unwrap()).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);
}
}