1use crate::util::parse::*;
7use crate::util::point::*;
8
9type Pair = (Point, i32);
10type Input = ([i32; 4], Vec<Pair>);
11
12pub fn parse(input: &str) -> Input {
16 let first = input.bytes().filter(u8::is_ascii_alphabetic).map(Point::from);
17 let second = input.iter_signed::<i32>();
18 let pairs = first.zip(second).collect();
19
20 let mut x1 = i32::MAX;
22 let mut y1 = i32::MAX;
23 let mut x2 = i32::MIN;
24 let mut y2 = i32::MIN;
25 let mut point = ORIGIN;
26
27 for &(step, amount) in &pairs {
28 point += step * amount;
29 x1 = x1.min(point.x);
30 y1 = y1.min(point.y);
31 x2 = x2.max(point.x);
32 y2 = y2.max(point.y);
33 }
34
35 ([x1, y1, x2, y2], pairs)
36}
37
38pub fn part1(input: &Input) -> u32 {
40 simulate::<2>(input)
41}
42
43pub fn part2(input: &Input) -> u32 {
45 simulate::<10>(input)
46}
47
48fn simulate<const N: usize>(input: &Input) -> u32 {
57 let ([x1, y1, x2, y2], pairs) = input;
58 let width = x2 - x1 + 1;
59 let height = y2 - y1 + 1;
60 let start = Point::new(-x1, -y1);
61
62 let mut distinct = 0;
63 let mut rope = [start; N];
64 let mut grid = vec![false; (width * height) as usize];
65
66 for &(step, amount) in pairs {
67 for _ in 0..amount {
68 rope[0] += step;
69 for i in 1..N {
70 if !apart(rope[i - 1], rope[i]) {
71 break;
72 }
73 rope[i] += rope[i - 1].signum(rope[i]);
74 }
75
76 let tail = rope[N - 1];
77 let index = (width * tail.y + tail.x) as usize;
78
79 if !grid[index] {
80 grid[index] = true;
81 distinct += 1;
82 }
83 }
84 }
85
86 distinct
87}
88
89#[inline]
92fn apart(a: Point, b: Point) -> bool {
93 (a.x - b.x).abs() > 1 || (a.y - b.y).abs() > 1
94}