-
Notifications
You must be signed in to change notification settings - Fork 9
/
day14.rs
107 lines (90 loc) · 3.29 KB
/
day14.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! # Restroom Redoubt
//!
//! For part one we jump straight to the final position by multiplying the velocity by 100.
//! The image appears in part two when the positions of all robots are unique.
//!
//! The x coordinates repeat every 101 seconds and the y coordinates repeat every 103 seconds.
//! First we check for times when the robot x coordinates could form the left and right columns
//! of the tree's bounding box. This gives a time `t` mod 101.
//!
//! Then we check the y coordinates looking for the top and bottom rows of the bounding box,
//! giving a time `u` mod 103.
//!
//! Using the [Chinese Remainder Theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem)
//! we combine the two times into a single time mod 10403 that is the answer.
use crate::util::iter::*;
use crate::util::parse::*;
use std::cmp::Ordering::*;
type Robot = [usize; 4];
pub fn parse(input: &str) -> Vec<Robot> {
input
.iter_signed::<i32>()
.chunk::<4>()
.map(|[x, y, dx, dy]| {
[x as usize, y as usize, dx.rem_euclid(101) as usize, dy.rem_euclid(103) as usize]
})
.collect()
}
pub fn part1(input: &[Robot]) -> i32 {
let mut quadrants = [0; 4];
for [x, y, dx, dy] in input {
let x = (x + 100 * dx) % 101;
let y = (y + 100 * dy) % 103;
match (x.cmp(&50), y.cmp(&51)) {
(Less, Less) => quadrants[0] += 1,
(Less, Greater) => quadrants[1] += 1,
(Greater, Less) => quadrants[2] += 1,
(Greater, Greater) => quadrants[3] += 1,
_ => (),
}
}
quadrants.iter().product()
}
pub fn part2(robots: &[Robot]) -> usize {
// Search for times mod 101 when the tree could possibly exist using x coordinates only.
// and times mod 103 when the tree could possibly exist using y coordinates only.
let mut rows = Vec::new();
let mut columns = Vec::new();
for time in 0..103 {
let mut xs = [0; 101];
let mut ys = [0; 103];
for [x, y, dx, dy] in robots {
let x = (x + time * dx) % 101;
xs[x] += 1;
let y = (y + time * dy) % 103;
ys[y] += 1;
}
// Tree bounding box is 31x33.
if time < 101 && xs.iter().filter(|&&c| c >= 33).count() >= 2 {
columns.push(time);
}
if ys.iter().filter(|&&c| c >= 31).count() >= 2 {
rows.push(time);
}
}
// If there's only one combination then return answer.
if rows.len() == 1 && columns.len() == 1 {
let t = columns[0];
let u = rows[0];
// Combine indices using the Chinese Remainder Theorem to get index mod 10403.
return (5253 * t + 5151 * u) % 10403;
}
// Backup check looking for time when all robot positions are unique.
let mut floor = vec![0; 10403];
for &t in &columns {
'outer: for &u in &rows {
let time = (5253 * t + 5151 * u) % 10403;
for &[x, y, dx, dy] in robots {
let x = (x + time * dx) % 101;
let y = (y + time * dy) % 103;
let index = 101 * y + x;
if floor[index] == time {
continue 'outer;
}
floor[index] = time;
}
return time;
}
}
unreachable!()
}