diff --git a/years/2024/src/day_23.rs b/years/2024/src/day_23.rs index c9ef1be..ea1d39a 100644 --- a/years/2024/src/day_23.rs +++ b/years/2024/src/day_23.rs @@ -1,17 +1,127 @@ +use std::collections::{HashMap, HashSet}; -use advent_core::{Day, day_stuff, ex_for_day}; +use advent_core::{day_stuff, ex_for_day, Day}; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; pub struct Day23; +type Edges = HashMap>; + +fn find_self_in_3<'a>(node: &'a String, edges: &'a Edges) -> Vec<[&'a String; 3]> { + edges + .get(node) + .unwrap() + .iter() + .flat_map(|adj| { + edges.get(adj).unwrap().iter().filter_map(|sadj| { + if edges.get(sadj).unwrap().contains(node) { + let mut v = [node, adj, sadj]; + v.sort(); + Some(v) + } else { + None + } + }) + }) + .collect() +} + +fn represent<'a>( + node: &'a String, + friends: HashSet<&'a String>, + edges: &'a Edges, + size: usize, + seen: &mut HashSet<&'a String>, +) -> Option> { + if friends.len() == size { + return Some(friends); + } else if friends.iter().all(|f| seen.contains(f)) { + return None; + } + + seen.insert(node); + + edges.get(node).unwrap().iter().find_map(|dep| { + if edges + .get(dep) + .is_some_and(|e| friends.iter().all(|f| e.contains(*f))) + { + let mut new_friends = friends.clone(); + new_friends.insert(dep); + represent(dep, new_friends, edges, size, seen) + } else { + None + } + }) +} + impl Day for Day23 { + day_stuff!(23, "", "", Edges); + + fn part_1(input: Self::Input) -> Option { + let groups = input + .keys() + .flat_map(|k| find_self_in_3(k, &input)) + .collect::>(); + + let ans = groups + .into_iter() + .filter(|g| g.iter().any(|c| c.starts_with('t'))) + .count(); + + Some(ans.to_string()) + } + + fn part_2(input: Self::Input) -> Option { + let verts = input.keys().cloned().collect::>(); + let max_group_size = verts + .iter() + .map(|v| input.get(v).unwrap().len()) + .max() + .unwrap() + + 1; - day_stuff!(23, "", ""); + let mut group = (0..max_group_size) + .rev() + .find_map(|s| { + verts.par_iter().find_map_any(|node| { + represent( + node, + HashSet::from_iter([node]), + &input, + s, + &mut HashSet::with_capacity(s), + ) + }) + }) + .unwrap() + .into_iter() + .collect::>(); - fn part_1(_input: Self::Input) -> Option { - None + group.sort(); + let len = group.len(); + let s = ",".to_string(); + Some(group.into_iter().intersperse(&s).fold( + String::with_capacity(len * 2 + (len - 1)), + |mut acc, computer| { + acc.push_str(computer.as_str()); + acc + }, + )) } - fn part_2(_input: Self::Input) -> Option { - None + fn parse_input(input: &str) -> Self::Input { + input + .lines() + .fold(HashMap::with_capacity(50), |mut acc, l| { + let (l, r) = l.split_once('-').unwrap(); + acc.entry(l.to_string()) + .or_insert(HashSet::new()) + .insert(r.to_string()); + acc.entry(r.to_string()) + .or_insert(HashSet::new()) + .insert(l.to_string()); + acc + }) } } diff --git a/years/2024/src/lib.rs b/years/2024/src/lib.rs index 12c0ef9..ea65503 100644 --- a/years/2024/src/lib.rs +++ b/years/2024/src/lib.rs @@ -1,4 +1,5 @@ #![feature(let_chains)] +#![feature(iter_intersperse)] use macros::year;