From 5f7d4ea1852c2abaadfc1dc9f03c3432abcfd0bc Mon Sep 17 00:00:00 2001 From: Fabian Schmidt Date: Tue, 29 Oct 2024 13:13:50 +0100 Subject: [PATCH] y2015d9 thank you project euler --- y2015/resources/9_input.txt | 28 ++++++++ y2015/src/bin/d9.rs | 20 ++++++ y2015/src/days/d9.rs | 125 ++++++++++++++++++++++++++++++++++++ y2015/src/days/mod.rs | 1 + 4 files changed, 174 insertions(+) create mode 100644 y2015/resources/9_input.txt create mode 100644 y2015/src/bin/d9.rs create mode 100644 y2015/src/days/d9.rs diff --git a/y2015/resources/9_input.txt b/y2015/resources/9_input.txt new file mode 100644 index 0000000..997758f --- /dev/null +++ b/y2015/resources/9_input.txt @@ -0,0 +1,28 @@ +Tristram to AlphaCentauri = 34 +Tristram to Snowdin = 100 +Tristram to Tambi = 63 +Tristram to Faerun = 108 +Tristram to Norrath = 111 +Tristram to Straylight = 89 +Tristram to Arbre = 132 +AlphaCentauri to Snowdin = 4 +AlphaCentauri to Tambi = 79 +AlphaCentauri to Faerun = 44 +AlphaCentauri to Norrath = 147 +AlphaCentauri to Straylight = 133 +AlphaCentauri to Arbre = 74 +Snowdin to Tambi = 105 +Snowdin to Faerun = 95 +Snowdin to Norrath = 48 +Snowdin to Straylight = 88 +Snowdin to Arbre = 7 +Tambi to Faerun = 68 +Tambi to Norrath = 134 +Tambi to Straylight = 107 +Tambi to Arbre = 40 +Faerun to Norrath = 11 +Faerun to Straylight = 66 +Faerun to Arbre = 144 +Norrath to Straylight = 115 +Norrath to Arbre = 135 +Straylight to Arbre = 127 diff --git a/y2015/src/bin/d9.rs b/y2015/src/bin/d9.rs new file mode 100644 index 0000000..33b2269 --- /dev/null +++ b/y2015/src/bin/d9.rs @@ -0,0 +1,20 @@ +use std::fs; + +use y2015::days::d9; + +fn main() { + part1(); + part2(); +} + +fn part1() { + let root = env!("CARGO_MANIFEST_DIR"); + let content = fs::read_to_string(format!("{root}/resources/9_input.txt")).unwrap(); + println!("{}", d9::process_part1(&content)); +} + +fn part2() { + let root = env!("CARGO_MANIFEST_DIR"); + let content = fs::read_to_string(format!("{root}/resources/9_input.txt")).unwrap(); + println!("{}", d9::process_part2(&content)); +} diff --git a/y2015/src/days/d9.rs b/y2015/src/days/d9.rs new file mode 100644 index 0000000..98e7663 --- /dev/null +++ b/y2015/src/days/d9.rs @@ -0,0 +1,125 @@ +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_9 { + use super::*; + + const INPUT: &str = "London to Dublin = 464 +London to Belfast = 518 +Dublin to Belfast = 141"; + + #[test] + fn it_works() { + let result = process_part1(INPUT); + assert_eq!(result, 605); + } + + #[test] + fn part2() { + let result = process_part2(INPUT); + assert_eq!(result, 982); + } +} diff --git a/y2015/src/days/mod.rs b/y2015/src/days/mod.rs index a268712..68906bd 100644 --- a/y2015/src/days/mod.rs +++ b/y2015/src/days/mod.rs @@ -6,3 +6,4 @@ pub mod d5; pub mod d6; pub mod d7; pub mod d8; +pub mod d9;