From: alex <> Date: Mon, 23 Dec 2024 09:29:26 +0000 (+0100) Subject: Day23 - part 1 X-Git-Url: https://aoc.elinar.fr/?a=commitdiff_plain;h=fe2ea7665d433eef1b708283119ef268cc8f618c;p=aoc_2024 Day23 - part 1 --- diff --git a/src/day23.rs b/src/day23.rs new file mode 100644 index 0000000..9b0859c --- /dev/null +++ b/src/day23.rs @@ -0,0 +1,160 @@ +use std::error::Error; +use std::path::Path; +use std::collections::{HashMap, HashSet}; + +#[derive(Copy, Clone, Debug)] +struct Link { + c1: [u8; 2], + c2: [u8; 2], +} + +impl Link { + pub fn new(link: &str) -> Self { + let (c1, c2) = link.split_once("-").unwrap(); + let c1 = c1.as_bytes()[0..2].try_into().unwrap(); + let c2 = c2.as_bytes()[0..2].try_into().unwrap(); + Self { c1, c2 } + } + + fn contains(&self, c: &[u8]) -> bool { + self.c1 == *c || self.c2 == *c + } +} + +struct Puzzle { + links: Vec, + graph: HashMap<[u8; 2], HashSet<[u8; 2]>>, +} + +impl Puzzle { + pub fn new(input: &str) -> Self { + let mut links: Vec = Vec::new(); + let mut graph: HashMap<[u8; 2], HashSet<[u8; 2]>> = HashMap::new(); + input.lines().for_each(|l| { + let link = Link::new(l); + links.push(link); + + match graph.get_mut(&link.c1) { + Some(c_set) => { c_set.insert(link.c2); }, + None => { + let mut c_set: HashSet<[u8; 2]> = HashSet::new(); + c_set.insert(link.c2); + graph.insert(link.c1, c_set); + } + } + + match graph.get_mut(&link.c2) { + Some(c_set) => { c_set.insert(link.c1); }, + None => { + let mut c_set: HashSet<[u8; 2]> = HashSet::new(); + c_set.insert(link.c1); + graph.insert(link.c2, c_set); + } + } + }); + + Self { links, graph } + } + + fn cycles_of_size_3(&self) -> Vec> { + let mut cycles: Vec> = Vec::new(); + self.graph.iter().for_each(|(c0, linked)| { + linked.iter().for_each(|c1| { + linked.iter() + .filter(|c2| *c2 != c1) + .for_each(|c2| { + if let Some(set1) = self.graph.get(c1) { + if set1.contains(c2) { + let cycle: HashSet<[u8; 2]> = HashSet::from([*c0, *c1, *c2]); + if !cycles.contains(&cycle) { + cycles.push(cycle); + } + } + } + }); + }); + }); + cycles + } +} + +fn run_part1(input: &str) -> Result> { + println!("Running {} - part 1", get_day()); + + let puzzle = Puzzle::new(input); + let cycles = puzzle.cycles_of_size_3(); + let res = cycles.iter() + .filter(|s| s.iter().any(|c| c[0] == b't')) + .count() as u64; + Ok(res) +} + +fn run_part2(input: &str) -> Result> { + println!("Running {} - part 2", get_day()); + + Ok(0) +} + +pub fn run(input: &str) -> Result<(), Box> { + let res = run_part1(input)?; + println!("{res}"); + + let res = run_part2(input)?; + println!("{res}"); + + Ok(()) +} + +fn get_day() -> String { + let filename = file!(); + Path::new(filename).file_stem().unwrap().to_str().unwrap().to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + + static TEXT_INPUT: &str = "\ +kh-tc +qp-kh +de-cg +ka-co +yn-aq +qp-ub +cg-tb +vc-aq +tb-ka +wh-tc +yn-cg +kh-ub +ta-co +de-co +tc-td +tb-wq +wh-td +ta-ka +td-qp +aq-cg +wq-ub +ub-vc +de-ta +wq-aq +wq-vc +wh-yn +ka-de +kh-ta +co-tc +wh-qp +tb-vc +td-yn"; + + #[test] + fn test_part1() { + assert_eq!(7, run_part1(TEXT_INPUT).unwrap()); + } + + #[test] + fn test_part2() { + assert_eq!(0, run_part2(TEXT_INPUT).unwrap()); + } +} diff --git a/src/main.rs b/src/main.rs index 65c8fd2..5bdf7bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ pub mod day18; pub mod day19; pub mod day20; pub mod day22; +pub mod day23; fn main() { let args: Vec = env::args().collect(); @@ -68,6 +69,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box> { "day19" => day19::run(&input)?, "day20" => day20::run(&input)?, "day22" => day22::run(&input)?, + "day23" => day23::run(&input)?, _ => return Err(format!("unknown or unimplemented day \"{day}\"").into()), } Ok(())