Skip to content

Commit

Permalink
2017 day 13
Browse files Browse the repository at this point in the history
  • Loading branch information
ictrobot committed Nov 1, 2024
1 parent 3786069 commit ab3d2e9
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
17 changes: 17 additions & 0 deletions crates/utils/src/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,23 @@ pub fn egcd<T: SignedInteger>(mut a: T, mut b: T) -> (T, T, T) {
(a, x0, y0)
}

/// Computes the lowest common multiple (LCM).
///
/// # Examples
/// ```
/// # use utils::number::lcm;
/// assert_eq!(lcm(6, 4), 12);
/// assert_eq!(lcm(21, 6), 42);
/// ```
pub fn lcm<T: SignedInteger>(a: T, b: T) -> T {
if a == T::ZERO || b == T::ZERO {
return T::ZERO;
}

let (gcd, ..) = egcd(a, b);
(a / gcd).abs() * b.abs()
}

/// Computes the modular inverse of `a` modulo `b` if it exists.
///
/// # Examples
Expand Down
76 changes: 76 additions & 0 deletions crates/year2017/src/day13.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::collections::BTreeMap;
use utils::number;
use utils::prelude::*;

/// Finding the gap in the firewall.
///
/// Similar to [2016 day 15](../year2016/struct.Day15.html), but instead of a system of linear
/// simultaneous congruences, it is a system of simultaneous modular inequalities.
#[derive(Clone, Debug)]
pub struct Day13 {
layers: Vec<(u32, u32)>,
}

impl Day13 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
Ok(Self {
layers: parser::u32()
.with_suffix(": ")
.then(parser::u32())
.parse_lines(input)?,
})
}

#[must_use]
pub fn part1(&self) -> u32 {
self.layers
.iter()
.map(|&(depth, range)| {
let period = (range - 1) * 2;
if depth % period == 0 {
depth * range
} else {
0
}
})
.sum()
}

#[must_use]
pub fn part2(&self) -> u32 {
// Each key represents a modulus and maps to a list of values where
// delay % modulus can't equal the value
let mut constraints = BTreeMap::new();
for &(depth, range) in &self.layers {
let modulus = (range as i32 - 1) * 2;
let disallowed_value = (-(depth as i32)).rem_euclid(modulus);

constraints
.entry(modulus)
.or_insert_with(Vec::new)
.push(disallowed_value);
}

// Find all the possible delays % lcm which meet the above constraints
let mut lcm = 1;
let mut possible_delays = vec![0];
for (modulus, disallowed_values) in constraints {
let new_lcm = number::lcm(modulus, lcm);
possible_delays = possible_delays
.into_iter()
.flat_map(|delay| {
(delay..new_lcm)
.step_by(lcm as usize)
.filter(|&i| !disallowed_values.contains(&(i % modulus)))
})
.collect();
lcm = new_lcm;
}

*possible_delays.iter().min().unwrap() as u32
}
}

examples!(Day13 -> (u32, u32) [
{input: "0: 3\n1: 2\n4: 4\n6: 4", part1: 24, part2: 10},
]);
1 change: 1 addition & 0 deletions crates/year2017/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ utils::year!(2017 => year2017, ${
10 => day10::Day10<'_>,
11 => day11::Day11,
12 => day12::Day12,
13 => day13::Day13,
});

0 comments on commit ab3d2e9

Please sign in to comment.