Skip to content

Commit ab3d2e9

Browse files
committed
2017 day 13
1 parent 3786069 commit ab3d2e9

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

crates/utils/src/number.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,23 @@ pub fn egcd<T: SignedInteger>(mut a: T, mut b: T) -> (T, T, T) {
255255
(a, x0, y0)
256256
}
257257

258+
/// Computes the lowest common multiple (LCM).
259+
///
260+
/// # Examples
261+
/// ```
262+
/// # use utils::number::lcm;
263+
/// assert_eq!(lcm(6, 4), 12);
264+
/// assert_eq!(lcm(21, 6), 42);
265+
/// ```
266+
pub fn lcm<T: SignedInteger>(a: T, b: T) -> T {
267+
if a == T::ZERO || b == T::ZERO {
268+
return T::ZERO;
269+
}
270+
271+
let (gcd, ..) = egcd(a, b);
272+
(a / gcd).abs() * b.abs()
273+
}
274+
258275
/// Computes the modular inverse of `a` modulo `b` if it exists.
259276
///
260277
/// # Examples

crates/year2017/src/day13.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use std::collections::BTreeMap;
2+
use utils::number;
3+
use utils::prelude::*;
4+
5+
/// Finding the gap in the firewall.
6+
///
7+
/// Similar to [2016 day 15](../year2016/struct.Day15.html), but instead of a system of linear
8+
/// simultaneous congruences, it is a system of simultaneous modular inequalities.
9+
#[derive(Clone, Debug)]
10+
pub struct Day13 {
11+
layers: Vec<(u32, u32)>,
12+
}
13+
14+
impl Day13 {
15+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
16+
Ok(Self {
17+
layers: parser::u32()
18+
.with_suffix(": ")
19+
.then(parser::u32())
20+
.parse_lines(input)?,
21+
})
22+
}
23+
24+
#[must_use]
25+
pub fn part1(&self) -> u32 {
26+
self.layers
27+
.iter()
28+
.map(|&(depth, range)| {
29+
let period = (range - 1) * 2;
30+
if depth % period == 0 {
31+
depth * range
32+
} else {
33+
0
34+
}
35+
})
36+
.sum()
37+
}
38+
39+
#[must_use]
40+
pub fn part2(&self) -> u32 {
41+
// Each key represents a modulus and maps to a list of values where
42+
// delay % modulus can't equal the value
43+
let mut constraints = BTreeMap::new();
44+
for &(depth, range) in &self.layers {
45+
let modulus = (range as i32 - 1) * 2;
46+
let disallowed_value = (-(depth as i32)).rem_euclid(modulus);
47+
48+
constraints
49+
.entry(modulus)
50+
.or_insert_with(Vec::new)
51+
.push(disallowed_value);
52+
}
53+
54+
// Find all the possible delays % lcm which meet the above constraints
55+
let mut lcm = 1;
56+
let mut possible_delays = vec![0];
57+
for (modulus, disallowed_values) in constraints {
58+
let new_lcm = number::lcm(modulus, lcm);
59+
possible_delays = possible_delays
60+
.into_iter()
61+
.flat_map(|delay| {
62+
(delay..new_lcm)
63+
.step_by(lcm as usize)
64+
.filter(|&i| !disallowed_values.contains(&(i % modulus)))
65+
})
66+
.collect();
67+
lcm = new_lcm;
68+
}
69+
70+
*possible_delays.iter().min().unwrap() as u32
71+
}
72+
}
73+
74+
examples!(Day13 -> (u32, u32) [
75+
{input: "0: 3\n1: 2\n4: 4\n6: 4", part1: 24, part2: 10},
76+
]);

crates/year2017/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ utils::year!(2017 => year2017, ${
1414
10 => day10::Day10<'_>,
1515
11 => day11::Day11,
1616
12 => day12::Day12,
17+
13 => day13::Day13,
1718
});

0 commit comments

Comments
 (0)