]> aoc.elinar.fr Git - aoc_2024/commitdiff
Day23 - part 1
authoralex <>
Mon, 23 Dec 2024 09:29:26 +0000 (10:29 +0100)
committeralex <>
Mon, 23 Dec 2024 09:29:26 +0000 (10:29 +0100)
src/day23.rs [new file with mode: 0644]
src/main.rs

diff --git a/src/day23.rs b/src/day23.rs
new file mode 100644 (file)
index 0000000..9b0859c
--- /dev/null
@@ -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<Link>,
+    graph: HashMap<[u8; 2], HashSet<[u8; 2]>>,
+}
+
+impl Puzzle {
+    pub fn new(input: &str) -> Self {
+        let mut links: Vec<Link> = 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<HashSet<[u8; 2]>> {
+        let mut cycles: Vec<HashSet<[u8; 2]>> = 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<u64, Box<dyn Error>> {
+    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<u32, Box<dyn Error>> {
+    println!("Running {} - part 2", get_day());
+
+    Ok(0)
+}
+
+pub fn run(input: &str) -> Result<(), Box<dyn Error>> {
+    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());
+    }
+}
index 65c8fd2022975ac16c73c2f34bdb6a06737e7a5c..5bdf7bb6d5bc581016e6822a56a6d887a3472789 100644 (file)
@@ -25,6 +25,7 @@ pub mod day18;
 pub mod day19;
 pub mod day20;
 pub mod day22;
+pub mod day23;
 
 fn main() {
     let args: Vec<String> = env::args().collect();
@@ -68,6 +69,7 @@ fn run(day: &str, input_file: &str) -> Result<(), Box<dyn Error>> {
         "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(())