diff --git a/Cargo.lock b/Cargo.lock index 951ed46..385ed04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,9 +224,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "lock_api" diff --git a/README.md b/README.md index 01ff3b1..20e9e96 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,11 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | [Day 6](./src/bin/06.rs) | `50.5µs` | `2.5ms` | | [Day 7](./src/bin/07.rs) | `65.4µs` | `55.4µs` | | [Day 8](./src/bin/08.rs) | `26.4ms` | `27.6ms` | +| [Day 9](./src/bin/09.rs) | `128.8µs` | `-` | +| [Day 10](./src/bin/10.rs) | `51.2ms` | `-` | +| [Day 11](./src/bin/11.rs) | `153.6µs` | `667.6µs` | -**Total: 226.62ms** +**Total: 278.77ms** --- diff --git a/data/examples/11-2.txt b/data/examples/11-2.txt new file mode 100644 index 0000000..d787665 --- /dev/null +++ b/data/examples/11-2.txt @@ -0,0 +1,13 @@ +svr: aaa bbb +aaa: fft +fft: ccc +bbb: tty +tty: ccc +ccc: ddd eee +ddd: hub +hub: fff +eee: dac +dac: fff +fff: ggg hhh +ggg: out +hhh: out diff --git a/data/examples/11.txt b/data/examples/11.txt new file mode 100644 index 0000000..01e5b43 --- /dev/null +++ b/data/examples/11.txt @@ -0,0 +1,10 @@ +aaa: you hhh +you: bbb ccc +bbb: ddd eee +ccc: ddd eee fff +ddd: ggg +eee: out +fff: out +ggg: out +hhh: ccc fff iii +iii: out diff --git a/src/bin/09.rs b/src/bin/09.rs index 39be398..7c2b10d 100644 --- a/src/bin/09.rs +++ b/src/bin/09.rs @@ -78,7 +78,8 @@ pub fn part_two(input: &str) -> Option { } } - Some(best_size) + // Some(best_size) + None } #[cfg(test)] diff --git a/src/bin/11.rs b/src/bin/11.rs new file mode 100644 index 0000000..08f0435 --- /dev/null +++ b/src/bin/11.rs @@ -0,0 +1,115 @@ +advent_of_code::solution!(11); +use std::collections::HashMap; +use itertools::Itertools; + +fn traverse_path(nodes: &HashMap<&str, Vec<&str>>, start: &str) -> Option { + if start == "out" { return Some(1) } + else { + let outputs = nodes.get(start).unwrap(); + return outputs.iter().map(|o: &&str| traverse_path(nodes, o)).sum(); + } +} + +fn traverse_path_part_two(nodes: &HashMap<&str, Vec<&str>>, start: &str, end: &str, exclude_node: Option<&str>, cache: &mut HashMap) -> usize { + // if we made it to our desired end node, increase the count + if start == end { + return 1 + } + // if we either make it to the end node (and "end" wasn't our desired node) or we hit our excluded node, return a 0 + else if start == "out" || (!Option::is_none(&exclude_node) && start == exclude_node.unwrap()) { return 0 } + else { + // print!("traversing {start} => "); + let outputs = nodes.get(start).unwrap(); + // println!("{outputs:?}"); + let mut sum = 0; + for o in outputs.iter() { + let key = o.to_string(); + if cache.contains_key(&key) { + sum += cache.get(&key).unwrap(); + } else { + let result = traverse_path_part_two(nodes, o, end, exclude_node, cache); + cache.insert(key, result); + sum += result; + } + } + sum + } +} + +pub fn part_one(input: &str) -> Option { + let mut nodes = HashMap::new(); + let lines = input.lines().filter(|l| !l.is_empty()).collect_vec(); + for line in lines { + let parts = line.split(':').collect_vec(); + let source = parts[0]; + let outputs = parts[1].trim().split(' ').collect_vec(); + nodes.insert(source, outputs); + } + // println!("{nodes:?}"); + let paths = traverse_path(&nodes, "you").unwrap(); + // println!("calculated paths {paths}"); + + Some(paths as u64) +} + +pub fn part_two(input: &str) -> Option { + let mut nodes = HashMap::new(); + let lines = input.lines().filter(|l| !l.is_empty()).collect_vec(); + for line in lines { + let parts = line.split(':').collect_vec(); + let source = parts[0]; + let outputs = parts[1].trim().split(' ').collect_vec(); + nodes.insert(source, outputs); + } + + let mut cache = HashMap::new(); + cache.clear(); + let paths_from_svr_to_dac = traverse_path_part_two(&nodes, "svr", "dac", Some("fft"), &mut cache); + // println!("paths from svr to dac {paths_from_svr_to_dac}"); + + cache.clear(); + let paths_from_dac_to_fft = traverse_path_part_two(&nodes, "dac", "fft", None, &mut cache); + // println!("paths from dac to fft {paths_from_dac_to_fft}"); + + cache.clear(); + let paths_from_fft_to_out = traverse_path_part_two(&nodes, "fft", "out", None, &mut cache); + // println!("paths from dac to fft {paths_from_fft_to_out}"); + + cache.clear(); + let paths_from_svr_to_fft = traverse_path_part_two(&nodes, "svr", "fft", Some("dac"), &mut cache); + // println!("paths from svr to fft {paths_from_svr_to_fft}"); + + cache.clear(); + let paths_from_fft_to_dac = traverse_path_part_two(&nodes, "fft", "dac", None, &mut cache); + // println!("paths from fft to dac {paths_from_fft_to_dac}"); + + cache.clear(); + let paths_from_dac_to_out = traverse_path_part_two(&nodes, "dac", "out", None, &mut cache); + // println!("paths from fft to dac {paths_from_dac_to_out}"); + + // Calculate ALL paths as follows: + // Paths from "svr" (START) => "dac" * "dac" => "fft" * "fft" => "out" (END) + // + Paths from "svr" (START) => "fft" * "fft" => "dac" * "dac" => "out" (END) + let total_paths_svr_dac_fft_out = paths_from_svr_to_dac * paths_from_dac_to_fft * paths_from_fft_to_out; + let total_paths_svr_fft_dac_out = paths_from_svr_to_fft * paths_from_fft_to_dac * paths_from_dac_to_out; + let total = total_paths_svr_dac_fft_out + total_paths_svr_fft_dac_out; + + Some(total as u64) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some(5)); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file_part("examples", DAY, 2)); + assert_eq!(result, Some(2)); + } +}