1use crate::util::iter::*;
16use crate::util::parse::*;
17use std::cmp::Ordering::*;
18
19type Robot = [usize; 4];
20
21pub fn parse(input: &str) -> Vec<Robot> {
22 input
23 .iter_signed::<i32>()
24 .chunk::<4>()
25 .map(|[x, y, dx, dy]| {
26 [x as usize, y as usize, dx.rem_euclid(101) as usize, dy.rem_euclid(103) as usize]
27 })
28 .collect()
29}
30
31pub fn part1(input: &[Robot]) -> i32 {
32 let mut quadrants = [0; 4];
33
34 for [x, y, dx, dy] in input {
35 let x = (x + 100 * dx) % 101;
36 let y = (y + 100 * dy) % 103;
37
38 match (x.cmp(&50), y.cmp(&51)) {
39 (Less, Less) => quadrants[0] += 1,
40 (Less, Greater) => quadrants[1] += 1,
41 (Greater, Less) => quadrants[2] += 1,
42 (Greater, Greater) => quadrants[3] += 1,
43 _ => (),
44 }
45 }
46
47 quadrants.iter().product()
48}
49
50pub fn part2(robots: &[Robot]) -> usize {
51 let mut rows = Vec::new();
54 let mut columns = Vec::new();
55
56 for time in 0..103 {
57 let mut xs = [0; 101];
58 let mut ys = [0; 103];
59
60 for [x, y, dx, dy] in robots {
61 let x = (x + time * dx) % 101;
62 xs[x] += 1;
63 let y = (y + time * dy) % 103;
64 ys[y] += 1;
65 }
66
67 if time < 101 && xs.iter().filter(|&&c| c >= 33).count() >= 2 {
69 columns.push(time);
70 }
71 if ys.iter().filter(|&&c| c >= 31).count() >= 2 {
72 rows.push(time);
73 }
74 }
75
76 if rows.len() == 1 && columns.len() == 1 {
78 let t = columns[0];
79 let u = rows[0];
80 return (5253 * t + 5151 * u) % 10403;
82 }
83
84 let mut floor = vec![0; 10403];
86
87 for &t in &columns {
88 'outer: for &u in &rows {
89 let time = (5253 * t + 5151 * u) % 10403;
90
91 for &[x, y, dx, dy] in robots {
92 let x = (x + time * dx) % 101;
93 let y = (y + time * dy) % 103;
94
95 let index = 101 * y + x;
96 if floor[index] == time {
97 continue 'outer;
98 }
99 floor[index] = time;
100 }
101
102 return time;
103 }
104 }
105
106 unreachable!()
107}