diff --git a/src/bin/08.rs b/src/bin/08.rs new file mode 100644 index 0000000..37191c0 --- /dev/null +++ b/src/bin/08.rs @@ -0,0 +1,106 @@ +use aoc::*; +use itertools::Itertools; +use std::cmp::Reverse; +use std::collections::HashSet; + +const INPUT: &str = include_str!("../../input/08"); + +fn main() { + println!("Part 1: {}", part1(INPUT, 1000)); + println!("Part 2: {}", part2(INPUT)); +} + +#[test] +fn example() { + assert_eq!(part1(include_str!("../../input/08-test"), 10), 40); + assert_example!(part2, "08-test", 25272); +} + +fn part1(input: &str, n: usize) -> usize { + let boxes = parse_input(input); + pairs(&boxes) + .take(n) + .fold(Vec::new(), connect) + .into_iter() + .map(|circuit| circuit.len()) + .sorted_by_key(|&l| Reverse(l)) + .take(3) + .product() +} + +fn part2(input: &str) -> usize { + let boxes = parse_input(input); + let pairs = pairs(&boxes); + + let mut circuits: Vec = Vec::new(); + + for pair in pairs { + circuits = connect(circuits, pair); + let done = circuits.iter().any(|c| c.len() >= boxes.len()); + if done { + return pair.0 .0[0] * pair.1 .0[0]; + } + } + + unreachable!() +} + +fn connect(mut circuits: Vec, (a, b): (JBox, JBox)) -> Vec { + let with_a = circuits.iter_mut().position(|c| c.contains(&a)); + let with_b = circuits.iter_mut().position(|c| c.contains(&b)); + match (with_a, with_b) { + (Some(with_a), Some(with_b)) => { + // Merge into with_a. with_b will be empty, but whatever. + let with_b_circuit = circuits[with_b].drain().collect_vec(); + circuits[with_a].extend(with_b_circuit); + } + (Some(with_a), None) => { + circuits[with_a].insert(b); + } + (None, Some(with_b)) => { + circuits[with_b].insert(a); + } + (None, None) => { + circuits.push(Circuit::from([a, b])); + } + } + circuits +} + +fn pairs(boxes: &[JBox]) -> impl Iterator + use<'_> { + boxes + .iter() + .copied() + .combinations(2) + .map(|v| (v[0], v[1])) + .sorted_by_key(|&(a, b)| distance(a, b)) +} + +fn parse_input(input: &str) -> Vec { + input.lines().map(JBox::parse).collect() +} + +fn distance(a: JBox, b: JBox) -> usize { + let sum_squares: usize = + a.0.iter() + .zip(&b.0) + .map(|(&a, &b)| a.abs_diff(b).pow(2)) + .sum(); + sum_squares.isqrt() +} + +type Circuit = HashSet; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +struct JBox([usize; 3]); + +impl JBox { + fn parse(line: &str) -> Self { + let mut nums = line.split(',').map(|n| n.parse().unwrap()); + Self([ + nums.next().unwrap(), + nums.next().unwrap(), + nums.next().unwrap(), + ]) + } +}