1use utils::number::chinese_remainder;
2use utils::point::Point2D;
3use utils::prelude::*;
4
5#[derive(Clone, Debug)]
7pub struct Day14 {
8 robots: Vec<Robot>,
9}
10
11#[derive(Copy, Clone, Debug)]
12struct Robot {
13 position: Point2D<i32>,
14 velocity: Point2D<i32>,
15}
16
17const WIDTH: i32 = 101;
18const HEIGHT: i32 = 103;
19
20impl Day14 {
21 pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
22 Ok(Self {
23 robots: parser::number_range(0..=WIDTH - 1)
24 .with_prefix("p=")
25 .then(parser::number_range(0..=HEIGHT - 1).with_prefix(","))
26 .then(parser::i32().with_prefix(" v="))
27 .then(parser::i32().with_prefix(","))
28 .map(|(px, py, vx, vy)| Robot {
29 position: Point2D::new(px, py),
30 velocity: Point2D::new(vx, vy),
31 })
32 .parse_lines(input)?,
33 })
34 }
35
36 #[must_use]
37 pub fn part1(&self) -> u64 {
38 let mut counts = [0; 4];
39 for &(mut r) in self.robots.iter() {
40 r.position += r.velocity * 100;
41 r.position.x = r.position.x.rem_euclid(WIDTH);
42 r.position.y = r.position.y.rem_euclid(HEIGHT);
43
44 if r.position.x == WIDTH / 2 || r.position.y == HEIGHT / 2 {
45 continue;
46 }
47
48 let mut quadrant = 0;
49 if r.position.x > WIDTH / 2 {
50 quadrant += 2;
51 }
52 if r.position.y > HEIGHT / 2 {
53 quadrant += 1;
54 }
55 counts[quadrant] += 1;
56 }
57 counts.iter().product()
58 }
59
60 #[must_use]
61 pub fn part2(&self) -> u32 {
62 let a = (0..WIDTH)
72 .find(|&t| {
73 let mut columns = [0u8; WIDTH as usize];
74 for r in &self.robots {
75 let col = (r.position.x + r.velocity.x * t).rem_euclid(WIDTH);
76 columns[col as usize] += 1;
77 }
78 columns.iter().any(|&b| b >= 30)
79 })
80 .expect("expected a time to have more than 30 robots in a column");
81
82 let b = (0..HEIGHT)
83 .find(|&t| {
84 let mut rows = [0u8; HEIGHT as usize];
85 for r in &self.robots {
86 let row = (r.position.y + r.velocity.y * t).rem_euclid(HEIGHT);
87 rows[row as usize] += 1;
88 }
89 rows.iter().any(|&b| b >= 30)
90 })
91 .expect("expected a time to have more than 30 robots in a row");
92
93 chinese_remainder([a, b], [WIDTH, HEIGHT]).unwrap() as u32
94 }
95}
96
97examples!(Day14 -> (u32, u32) []);