1use crate::util::grid::*;
3use crate::util::iter::*;
4use crate::util::parse::*;
5use crate::util::point::*;
6
7type Input = (String, i32);
8
9pub fn parse(input: &str) -> Input {
10 let (mut points, velocity): (Vec<_>, Vec<_>) = input
11 .iter_signed::<i32>()
12 .chunk::<4>()
13 .map(|[x, y, dx, dy]| (Point::new(x, y), Point::new(dx, dy)))
14 .unzip();
15
16 let up = velocity.iter().position(|v| v.y < 0).unwrap();
18 let down = velocity.iter().position(|v| v.y > 0).unwrap();
19
20 let p = (points[up].y - points[down].y).abs();
22 let v = (velocity[up].y - velocity[down].y).abs();
23 let mut time = (p - 10) / v;
24
25 tick(&mut points, &velocity, time);
27
28 while size(&points) > 620 {
31 tick(&mut points, &velocity, 1);
32 time += 1;
33 }
34
35 adjust(&mut points);
37
38 let mut grid = Grid::new(63, 10, '.');
40
41 (0..10).for_each(|y| grid[Point::new(0, y)] = '\n');
42 points.iter().for_each(|&p| grid[p + RIGHT] = '#');
43
44 let message = grid.bytes.iter().collect();
45
46 (message, time)
48}
49
50pub fn part1(input: &Input) -> &str {
51 &input.0
52}
53
54pub fn part2(input: &Input) -> i32 {
55 input.1
56}
57
58fn bounding_box(points: &[Point]) -> (i32, i32, i32, i32) {
59 points.iter().fold(
60 (i32::MAX, i32::MIN, i32::MAX, i32::MIN),
61 |(min_x, max_x, min_y, max_y), &p| {
62 (min_x.min(p.x), max_x.max(p.x), min_y.min(p.y), max_y.max(p.y))
63 },
64 )
65}
66
67fn size(points: &[Point]) -> i32 {
68 let (min_x, max_x, min_y, max_y) = bounding_box(points);
69 (max_x - min_x + 1) * (max_y - min_y + 1)
70}
71
72fn adjust(points: &mut [Point]) {
73 let (min_x, _, min_y, _) = bounding_box(points);
74 let top_left = Point::new(min_x, min_y);
75 points.iter_mut().for_each(|p| *p -= top_left);
76}
77
78fn tick(points: &mut [Point], velocity: &[Point], time: i32) {
79 for (p, &v) in points.iter_mut().zip(velocity) {
80 *p += v * time;
81 }
82}