Compare commits
2 Commits
73765e857a
...
f51dc9c145
| Author | SHA1 | Date | |
|---|---|---|---|
|
f51dc9c145
|
|||
|
09cd17d3ff
|
53
src/day2.rs
53
src/day2.rs
@@ -1,6 +1,7 @@
|
|||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use misc::POW10;
|
use misc::POW10;
|
||||||
|
use std::cmp::{max, min};
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
#[aoc_generator(day2)]
|
#[aoc_generator(day2)]
|
||||||
@@ -88,15 +89,15 @@ fn part2_arithmetic_brute(input: &[RangeInclusive<u64>]) -> u64 {
|
|||||||
let n_digits = (product.ilog10() + 1) as usize;
|
let n_digits = (product.ilog10() + 1) as usize;
|
||||||
|
|
||||||
for n in 1..=n_digits / 2 {
|
for n in 1..=n_digits / 2 {
|
||||||
let repetitions = n_digits / n;
|
|
||||||
if !n_digits.is_multiple_of(n) {
|
if !n_digits.is_multiple_of(n) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let decade = POW10[n_digits - n];
|
let repetitions = n_digits / n;
|
||||||
|
let decade = POW10[n_digits - n]; // get the power of 10 to split the leftmost n digits
|
||||||
let lhs = product / decade;
|
let lhs = product / decade;
|
||||||
let remainder = product % decade;
|
let remainder = product % decade;
|
||||||
|
|
||||||
// for each repetition we multiply by 10^(rep * n)
|
// for each repetition we multiply by 10^(rep * n) to add the appropriate zeros
|
||||||
let expected_remainder = (0..repetitions - 1).map(|rep| lhs * POW10[rep * n]).sum();
|
let expected_remainder = (0..repetitions - 1).map(|rep| lhs * POW10[rep * n]).sum();
|
||||||
|
|
||||||
if remainder == expected_remainder {
|
if remainder == expected_remainder {
|
||||||
@@ -139,6 +140,48 @@ fn part1_clever(input: &[RangeInclusive<u64>]) -> u64 {
|
|||||||
invalid_sum
|
invalid_sum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn n_digits(n: &u64) -> usize {
|
||||||
|
(n.ilog10() + 1) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_repeaters(r: &RangeInclusive<u64>, n: usize) -> Vec<u64> {
|
||||||
|
let mut invalids = Vec::new();
|
||||||
|
for r in split_by_decade(r) {
|
||||||
|
let n_digits = n_digits(r.start());
|
||||||
|
if !n_digits.is_multiple_of(n) || n_digits < 2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let repetitions = n_digits / n;
|
||||||
|
let decade = POW10[n_digits - n];
|
||||||
|
for lhs in (r.start() / decade)..=(r.end() / decade) {
|
||||||
|
let repeater = (0..repetitions)
|
||||||
|
.map(|rep| lhs * POW10[rep * n])
|
||||||
|
.sum::<u64>();
|
||||||
|
if r.contains(&repeater) {
|
||||||
|
invalids.push(repeater)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
invalids
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split_by_decade(r: &RangeInclusive<u64>) -> impl Iterator<Item = RangeInclusive<u64>> {
|
||||||
|
let (start, end) = (*r.start(), *r.end());
|
||||||
|
(n_digits(r.start())..n_digits(r.end()) + 1)
|
||||||
|
.map(move |nd| RangeInclusive::new(max(start, POW10[nd - 1]), min(end, POW10[nd] - 1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day2, part2, Clever)]
|
||||||
|
fn part2_clever(input: &[RangeInclusive<u64>]) -> u64 {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.flat_map(|r| (1..=n_digits(r.end()) / 2).map(|nd| generate_repeaters(r, nd)))
|
||||||
|
.flatten()
|
||||||
|
.unique()
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -167,4 +210,8 @@ mod tests {
|
|||||||
fn part1_clever_example() {
|
fn part1_clever_example() {
|
||||||
assert_eq!(part1_clever(&parse(EXAMPLE)), 1227775554);
|
assert_eq!(part1_clever(&parse(EXAMPLE)), 1227775554);
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn part2_clever_example() {
|
||||||
|
assert_eq!(part2_clever(&parse(EXAMPLE)), 4174379265);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the 8 neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
/// Return an iterator over the 8 neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
||||||
pub fn adjacent_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
pub fn adjacent_iter<'a, C: AsCoord2d + Copy>(&'a self, c: &'a C) -> OffsetsIter<'a, T> {
|
||||||
OffsetsIter {
|
OffsetsIter {
|
||||||
grid: self,
|
grid: self,
|
||||||
origin: c.to_coord(),
|
origin: c.to_coord(),
|
||||||
@@ -462,7 +462,7 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the 4 cardinal neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
/// Return an iterator over the 4 cardinal neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
||||||
pub fn cardinal_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
pub fn cardinal_iter<'a, C: AsCoord2d + Copy>(&'a self, c: &'a C) -> OffsetsIter<'a, T> {
|
||||||
OffsetsIter {
|
OffsetsIter {
|
||||||
grid: self,
|
grid: self,
|
||||||
origin: c.to_coord(),
|
origin: c.to_coord(),
|
||||||
|
|||||||
Reference in New Issue
Block a user