Solve 23
This commit is contained in:
parent
6c3b0cabf1
commit
9e8d3fb4bb
1 changed files with 129 additions and 0 deletions
129
src/bin/23.rs
Normal file
129
src/bin/23.rs
Normal file
|
@ -0,0 +1,129 @@
|
|||
use aoc::*;
|
||||
use itertools::Itertools;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::fmt;
|
||||
|
||||
const INPUT: &str = include_str!("../../input/23");
|
||||
|
||||
fn main() {
|
||||
assert_example!(part1, "23-test", 7);
|
||||
println!("Part 1: {}", part1(INPUT));
|
||||
assert_example!(part2, "23-test", "co,de,ka,ta");
|
||||
println!("Part 2: {}", part2(INPUT));
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> usize {
|
||||
let graph = parse(input);
|
||||
|
||||
let mut result = HashSet::new();
|
||||
|
||||
let starts = graph.keys().filter(|c| c.0 == 't');
|
||||
|
||||
for start in starts {
|
||||
for n1 in graph.get(start).unwrap() {
|
||||
for n2 in graph.get(n1).unwrap() {
|
||||
if n1 == n2 {
|
||||
continue;
|
||||
}
|
||||
if graph.get(n2).unwrap().contains(start) {
|
||||
let mut group = vec![*n1, *n2, *start];
|
||||
group.sort();
|
||||
result.insert(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.len()
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> String {
|
||||
let graph = parse(input);
|
||||
graph
|
||||
.keys()
|
||||
.map(|&start| clique(&graph, start))
|
||||
.max_by_key(|group| group.len())
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.sorted()
|
||||
.join(",")
|
||||
}
|
||||
|
||||
fn clique(graph: &Graph, start: Computer) -> HashSet<Computer> {
|
||||
let mut clique = HashSet::new();
|
||||
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(start);
|
||||
|
||||
while let Some(current) = queue.pop_front() {
|
||||
let mut all_connected = true;
|
||||
for c in &clique {
|
||||
if !graph.get(c).unwrap().contains(¤t) {
|
||||
all_connected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !all_connected {
|
||||
continue;
|
||||
}
|
||||
clique.insert(current);
|
||||
let next = graph.get(¤t).unwrap();
|
||||
queue.extend(next);
|
||||
}
|
||||
|
||||
clique
|
||||
}
|
||||
|
||||
type Graph = HashMap<Computer, Vec<Computer>>;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct Computer(char, char);
|
||||
|
||||
impl Computer {
|
||||
fn parse(s: &str) -> Self {
|
||||
if s.len() != 2 {
|
||||
panic!("computer needs 2 chars, got '{s}'");
|
||||
}
|
||||
|
||||
let mut chars = s.chars();
|
||||
Self(chars.next().unwrap(), chars.next().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Computer {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.cmp(&other.0).then(self.1.cmp(&other.1))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Computer {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Computer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{}", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: &str) -> Graph {
|
||||
let mut graph: Graph = HashMap::new();
|
||||
|
||||
for line in input.lines() {
|
||||
let (left, right) = parse_line(line);
|
||||
graph.entry(left).or_default().push(right);
|
||||
graph.entry(right).or_default().push(left);
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
fn parse_line(line: &str) -> (Computer, Computer) {
|
||||
let (left, right) = line.split_once('-').unwrap();
|
||||
let left = Computer::parse(left);
|
||||
let right = Computer::parse(right);
|
||||
(left, right)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue