From 12fde697d3dda85a9c78af51bc8a7e377e5ea5f2 Mon Sep 17 00:00:00 2001 From: sepia Date: Mon, 23 Dec 2024 18:09:59 -0600 Subject: [PATCH] Day 23 --- src/day23.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 4 ++- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/day23.rs diff --git a/src/day23.rs b/src/day23.rs new file mode 100644 index 0000000..38dfb20 --- /dev/null +++ b/src/day23.rs @@ -0,0 +1,93 @@ +use itertools::Itertools; +use std::{ + collections::{HashMap, HashSet}, + fmt::{Display, Write}, +}; + +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] +struct Computer(char, char); + +pub fn day23() { + let input_connections: Vec<(Computer, Computer)> = parse_input(&crate::input(23)); + let connections = { + let mut connections: HashMap> = HashMap::new(); + for &(a, b) in input_connections.iter() { + connections.entry(a).or_insert(vec![]).push(b); + connections.entry(b).or_insert(vec![]).push(a); + } + connections + }; + + fn collect_cliques( + connections: &HashMap>, + clique: &Vec, + visited: &mut HashSet>, + ) -> Vec> { + let mut bigger_cliques: Vec> = vec![]; + bigger_cliques.push(clique.clone()); + for (computer, friends) in connections.iter() { + if clique.contains(computer) { + continue; + } + if clique.iter().all(|groupie| friends.contains(groupie)) { + let mut new_clique = clique.clone(); + new_clique.push(*computer); + new_clique.sort(); + if visited.contains(&new_clique) { + continue; + } else { + visited.insert(new_clique.clone()); + } + let mut new_bigger_cliques = collect_cliques(connections, &new_clique, visited); + bigger_cliques.append(&mut new_bigger_cliques); + } + } + bigger_cliques + } + let mut visited = HashSet::new(); + let mut all_cliques: Vec> = connections + .keys() + .map(|&c| vec![c]) + .flat_map(|seed| collect_cliques(&connections, &seed, &mut visited)) + .collect(); + all_cliques.sort_by_key(|group| group.len()); + let mut maximum_clique = all_cliques.last().unwrap().clone(); + println!("The biggest clique's size is {}.", maximum_clique.len()); + maximum_clique.sort(); + println!( + "The biggest clique's password is {}", + maximum_clique.iter().map(|c| format!("{c}")).join(",") + ); + + let t_trios = all_cliques + .iter() + .filter(|clique| clique.len() == 3) + .filter(|trio| trio.iter().any(|c| c.0 == 't')) + .count(); + println!("{t_trios} trios contain a friend who starts with t."); +} + +impl Computer { + fn from_string(s: &str) -> Self { + Self(s.chars().nth(0).unwrap(), s.chars().nth(1).unwrap()) + } +} + +impl Display for Computer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_char(self.0)?; + f.write_char(self.1) + } +} + +fn parse_input(input: &str) -> Vec<(Computer, Computer)> { + input + .lines() + .map(|line| { + line.split("-") + .map(Computer::from_string) + .collect_tuple() + .unwrap() + }) + .collect() +} diff --git a/src/main.rs b/src/main.rs index 604b8e5..4a784e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,7 +28,9 @@ mod day2; mod day20; #[allow(dead_code)] mod day21; +#[allow(dead_code)] mod day22; +mod day23; #[allow(dead_code)] mod day3; #[allow(dead_code)] @@ -45,7 +47,7 @@ mod day8; mod day9; fn main() { - day22::day22(); + day23::day23(); } pub fn input(day: u8) -> String {