1use std::collections::HashMap;
2use utils::graph::explore_hamiltonian_paths;
3use utils::prelude::*;
4
5#[derive(Clone, Debug)]
11pub struct Day09 {
12 part1: u32,
13 part2: u32,
14}
15
16type Visited = u32;
17
18impl Day09 {
19 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
20 let location = parser::take_while1(u8::is_ascii_alphabetic).error_msg("expected location");
21 let parsed = location
22 .then(location.with_prefix(" to ").with_suffix(" = "))
23 .then(parser::u32())
24 .parse_lines(input)?;
25
26 let mut indexes = HashMap::new();
27 parsed.iter().for_each(|&(start, end, _)| {
28 let len = indexes.len();
29 indexes.entry(start).or_insert(len);
30 let len = indexes.len();
31 indexes.entry(end).or_insert(len);
32 });
33
34 let locations = indexes.len();
35 if locations > Visited::BITS as usize {
36 return Err(InputError::new(input, 0, "too many locations"));
37 }
38
39 let mut matrix = vec![0; indexes.len() * indexes.len()];
40 parsed.iter().for_each(|&(start, end, dist)| {
41 let start = indexes[start];
42 let end = indexes[end];
43 matrix[indexes.len() * start + end] = dist;
44 matrix[indexes.len() * end + start] = dist;
45 });
46
47 let (mut part1, mut part2) = (u32::MAX, 0);
48 explore_hamiltonian_paths(
49 indexes.len() as u32,
50 0,
51 (0, u32::MAX, 0),
52 |a, b| matrix[a as usize * locations + b as usize],
53 |(total, min_edge, max_edge), edge| {
54 (total + edge, min_edge.min(edge), max_edge.max(edge))
55 },
56 |(total, min_edge, max_edge), loop_edge| {
57 part1 = part1.min(total + loop_edge - max_edge.max(loop_edge));
58 part2 = part2.max(total + loop_edge - min_edge.min(loop_edge))
59 },
60 );
61
62 Ok(Self { part1, part2 })
63 }
64
65 #[must_use]
66 pub fn part1(&self) -> u32 {
67 self.part1
68 }
69
70 #[must_use]
71 pub fn part2(&self) -> u32 {
72 self.part2
73 }
74}
75
76examples!(Day09 -> (u32, u32) [
77 {
78 input: "London to Dublin = 464\n\
79 London to Belfast = 518\n\
80 Dublin to Belfast = 141",
81 part1: 605,
82 part2: 982,
83 },
84]);