Skip to content

Commit

Permalink
[2024] Day 23 initial solution
Browse files Browse the repository at this point in the history
  • Loading branch information
connorslade committed Dec 23, 2024
1 parent a82d093 commit b998389
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Thank you to [Eric Wastl](http://was.tl) for running this incredible yearly even
- [Day 20: Race Condition](aoc_2024/src/day_20.rs)
- [Day 21: Keypad Conundrum](aoc_2024/src/day_21.rs)
- [Day 22: Monkey Market](aoc_2024/src/day_22.rs)
- [Day 23: LAN Party](aoc_2024/src/day_23.rs)
<!-- MARKER -->

## [2023](https://adventofcode.com/2023) [![aoc_2023](https://github.com/connorslade/advent-of-code/actions/workflows/aoc_2023.yml/badge.svg)](https://github.com/connorslade/advent-of-code/actions/workflows/aoc_2023.yml)
Expand Down
145 changes: 145 additions & 0 deletions aoc_2024/src/day_23.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use std::collections::{HashMap, HashSet};

use common::{solution, Answer};
use itertools::Itertools;

solution!("LAN Party", 23);

fn part_a(input: &str) -> Answer {
let graph = parse(input);

let mut triplets = HashSet::new();
for key in graph.keys() {
let neighbors = &graph[key];

for x in neighbors {
for y in neighbors.iter().skip(1) {
if graph[x].contains(y) {
let mut sorted = vec![key, x, y];
sorted.sort();
triplets.insert((sorted[0], sorted[1], sorted[2]));
}
}
}
}

triplets
.iter()
.filter(|(a, b, c)| a.starts_with('t') || b.starts_with('t') || c.starts_with('t'))
.count()
.into()
}

fn part_b(input: &str) -> Answer {
let graph = parse(input);

let mut cliques = Vec::new();
bron_kerbosch(
&graph,
&mut HashSet::new(),
&mut graph.keys().cloned().collect(),
&mut HashSet::new(),
&mut cliques,
);

let max = cliques.iter().max_by_key(|x| x.len()).unwrap();
max.iter().sorted().join(",").into()
}

fn parse(input: &str) -> HashMap<&str, HashSet<&str>> {
let mut out: HashMap<&str, HashSet<&str>> = HashMap::new();

for line in input.lines() {
let (a, b) = line.split_once('-').unwrap();
out.entry(a).or_default().insert(b);
out.entry(b).or_default().insert(a);
}

out
}

fn bron_kerbosch<'a>(
graph: &HashMap<&'a str, HashSet<&'a str>>,
r: &mut HashSet<&'a str>,
p: &mut HashSet<&'a str>,
x: &mut HashSet<&'a str>,
cliques: &mut Vec<HashSet<&'a str>>,
) {
if p.is_empty() && x.is_empty() {
cliques.push(r.clone());
return;
}

let pivot = p.iter().chain(x.iter()).next().cloned();

for &v in p.clone().difference(&pivot.map_or_else(HashSet::new, |p| {
graph.get(&p).unwrap_or(&HashSet::new()).clone()
})) {
let mut r = r.clone();
r.insert(v);

let mut p = p
.intersection(graph.get(&v).unwrap_or(&HashSet::new()))
.cloned()
.collect();
let mut x = x
.intersection(graph.get(&v).unwrap_or(&HashSet::new()))
.cloned()
.collect();

bron_kerbosch(graph, &mut r, &mut p, &mut x, cliques);

p.remove(&v);
x.insert(v);
}
}

#[cfg(test)]
mod test {
use indoc::indoc;

const CASE: &str = indoc! {"
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 part_a() {
assert_eq!(super::part_a(CASE), 7.into());
}

#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), "co,de,ka,ta".into());
}
}
2 changes: 2 additions & 0 deletions aoc_2024/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod day_19;
mod day_20;
mod day_21;
mod day_22;
mod day_23;
// [import_marker]

pub const SOLUTIONS: &[Solution] = &[
Expand All @@ -47,5 +48,6 @@ pub const SOLUTIONS: &[Solution] = &[
day_20::SOLUTION,
day_21::SOLUTION,
day_22::SOLUTION,
day_23::SOLUTION,
// [list_marker]
];

0 comments on commit b998389

Please sign in to comment.