Skip to content

Commit 7e8943d

Browse files
committed
solve: day8
1 parent c03d137 commit 7e8943d

File tree

3 files changed

+169
-1
lines changed

3 files changed

+169
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
resolver = "2"
33
members = [
44
"aoc_lib/aoc_derive",
5-
"aoc_lib/utils", "day1", "day2", "day3", "day4", "day5", "day6", "day7",
5+
"aoc_lib/utils", "day1", "day2", "day3", "day4", "day5", "day6", "day7", "day8",
66
]
77

88
[workspace.dependencies]

day8/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "day8"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
aoc_derive.path = '../aoc_lib/aoc_derive'
8+
utils.path = '../aoc_lib/utils'
9+
derive_more.workspace = true
10+
itertools.workspace = true
11+
lazy-regex.workspace = true
12+
parse-display.workspace = true
13+
rayon.workspace = true
14+
regex.workspace = true
15+
num.workspace = true
16+
17+
[dev-dependencies]
18+
pretty_assertions.workspace = true

day8/src/main.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
use std::collections::{BTreeSet, HashMap, HashSet};
2+
3+
use aoc_derive::aoc_main;
4+
use itertools::{Itertools, iproduct};
5+
use lazy_regex::regex;
6+
use utils::ParseInput;
7+
use utils::*;
8+
9+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
10+
struct Pos {
11+
x: i64,
12+
y: i64,
13+
z: i64,
14+
}
15+
16+
impl Pos {
17+
fn dist(&self, other: &Pos) -> i64 {
18+
(((self.x - other.x).pow(2) + (self.y - other.y).pow(2) + (self.z - other.z).pow(2)) as f64)
19+
.sqrt()
20+
.floor() as i64
21+
}
22+
}
23+
24+
#[derive(Debug, Clone)]
25+
struct JunctionBox {
26+
pos: Pos,
27+
connections: HashSet<Pos>,
28+
}
29+
30+
impl JunctionBox {
31+
fn get_circuit(&self, boxes: &HashMap<Pos, JunctionBox>) -> BTreeSet<Pos> {
32+
let mut circuit = BTreeSet::from([self.pos]);
33+
let mut next = self.connections.clone();
34+
while !next.is_empty() {
35+
circuit.extend(next.iter().copied());
36+
next = next
37+
.iter()
38+
.flat_map(|b| boxes[b].connections.iter().copied())
39+
.filter(|b| !circuit.contains(b))
40+
.collect();
41+
}
42+
circuit
43+
}
44+
}
45+
46+
fn connect_next(
47+
distances: &[(Pos, Pos)],
48+
boxes: &mut HashMap<Pos, JunctionBox>,
49+
) -> Option<(Pos, Pos)> {
50+
let pair = distances.iter().find(|(b1, b2)| !boxes[b1].connections.contains(b2));
51+
if let Some((shortest1, shortest2)) = pair {
52+
boxes.get_mut(shortest1).unwrap().connections.insert(*shortest2);
53+
boxes.get_mut(shortest2).unwrap().connections.insert(*shortest1);
54+
}
55+
56+
pair.copied()
57+
}
58+
59+
fn part1(
60+
distances: &[(Pos, Pos)],
61+
mut boxes: HashMap<Pos, JunctionBox>,
62+
iterations: usize,
63+
) -> usize {
64+
for _ in 0..iterations {
65+
connect_next(distances, &mut boxes);
66+
}
67+
68+
boxes
69+
.values()
70+
.map(|b| b.get_circuit(&boxes))
71+
.unique()
72+
.map(|c| c.len())
73+
.sorted()
74+
.rev()
75+
.take(3)
76+
.product::<usize>()
77+
}
78+
79+
fn part2(distances: &[(Pos, Pos)], mut boxes: HashMap<Pos, JunctionBox>) -> i64 {
80+
loop {
81+
let (b1, b2) = connect_next(distances, &mut boxes)
82+
.expect("Should find solution before running out of connections");
83+
if boxes.get(&b1).unwrap().get_circuit(&boxes).len() == boxes.len() {
84+
return b1.x * b2.x;
85+
}
86+
}
87+
}
88+
89+
#[aoc_main(1000)]
90+
fn solve(input: Input, iterations: usize) -> impl Into<Solution> {
91+
let boxes: HashMap<_, JunctionBox> = input
92+
.lines()
93+
.map(|line| {
94+
let (x, y, z) = extract_numbers(line).collect_tuple().unwrap();
95+
let pos = Pos { x, y, z };
96+
(pos, JunctionBox { pos, connections: HashSet::new() })
97+
})
98+
.collect();
99+
100+
let distances = boxes
101+
.values()
102+
.enumerate()
103+
.flat_map(|(i, b1)| {
104+
boxes
105+
.values()
106+
.enumerate()
107+
.filter_map(move |(j, b2)| (j < i).then_some((b1.pos, b2.pos)))
108+
})
109+
.sorted_by_key(|(b1, b2)| b1.dist(b2))
110+
.collect_vec();
111+
112+
(part1(&distances, boxes.clone(), iterations), part2(&distances, boxes))
113+
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::*;
118+
#[test]
119+
fn test_examples() {
120+
pretty_assertions::assert_eq!(
121+
solve(
122+
Input::from(
123+
r#"162,817,812
124+
57,618,57
125+
906,360,560
126+
592,479,940
127+
352,342,300
128+
466,668,158
129+
542,29,236
130+
431,825,988
131+
739,650,466
132+
52,470,668
133+
216,146,977
134+
819,987,18
135+
117,168,530
136+
805,96,715
137+
346,949,466
138+
970,615,88
139+
941,993,340
140+
862,61,35
141+
984,92,344
142+
425,690,689"#
143+
),
144+
10
145+
)
146+
.into(),
147+
Solution::from((40.to_string(), 25272.to_string()))
148+
);
149+
}
150+
}

0 commit comments

Comments
 (0)