1use crate::util::integer::*;
20use crate::util::parse::*;
21use crate::util::point::*;
22use std::collections::BTreeMap;
23
24type Input = (i32, i32);
25
26struct Line {
27 start: Point,
28 end: Point,
29 distance: i32,
30}
31
32pub fn parse(input: &str) -> Input {
33 let lines: Vec<_> = input.lines().collect();
35 let steps = |i: usize| {
36 let first = lines[i].bytes().filter(u8::is_ascii_alphabetic);
37 let second = lines[i].iter_signed::<i32>();
38 first.zip(second)
39 };
40
41 let mut start = ORIGIN;
43 let mut distance = 0;
44 let mut vertical = BTreeMap::new();
45 let mut horizontal = BTreeMap::new();
46
47 for (direction, amount) in steps(0) {
48 let delta = Point::from(direction);
49 let end = start + delta * amount;
50 let line = Line { start, end, distance };
51
52 if start.x == end.x {
53 vertical.insert(start.x, line);
54 } else {
55 horizontal.insert(start.y, line);
56 }
57
58 start = end;
59 distance += amount;
60 }
61
62 let mut start = ORIGIN;
64 let mut distance = 0;
65 let mut manhattan = i32::MAX;
66 let mut delay = i32::MAX;
67
68 for (direction, amount) in steps(1) {
69 let delta = Point::from(direction);
70 let end = start + delta * amount;
71
72 let mut update = |line: &Line, candidate: Point| {
74 if candidate.manhattan(line.start) < line.end.manhattan(line.start)
75 && candidate.signum(line.start) == line.end.signum(line.start)
76 && candidate.manhattan(ORIGIN) > 0
77 {
78 manhattan = manhattan.min(candidate.manhattan(ORIGIN));
79 delay = delay.min(
80 distance
81 + candidate.manhattan(start)
82 + line.distance
83 + candidate.manhattan(line.start),
84 );
85 }
86 };
87
88 if start.x == end.x {
90 let (lo, hi) = start.y.minmax(end.y);
91 for (&y, line) in horizontal.range(lo..=hi) {
92 update(line, Point::new(start.x, y));
93 }
94 } else {
95 let (lo, hi) = start.x.minmax(end.x);
96 for (&x, line) in vertical.range(lo..=hi) {
97 update(line, Point::new(x, start.y));
98 }
99 }
100
101 start = end;
102 distance += amount;
103 }
104
105 (manhattan, delay)
106}
107
108pub fn part1(input: &Input) -> i32 {
109 input.0
110}
111
112pub fn part2(input: &Input) -> i32 {
113 input.1
114}