solution_printer!(4, print_solution, input_generator, INPUT, solve_part_1, solve_part_2);
pub const INPUT: &str = include_str!("../input/2019/day4.txt");
pub fn solve_part_1 (input_range: &DigitsNeverDecreasingRange) -> usize
{
input_range.filter(|digits| any_digits_repeat(digits)).count()
}
#[derive(Copy, Clone)]
pub struct DigitsNeverDecreasingRange
{
exhausted: bool,
next_value: [u8; 6],
end_value_inclusive: [u8; 6],
}
fn satisfy_digits_not_decreasing<F1, F2> (digits: &mut [u8; 6], f1: F1, f2: F2)
where F1: Fn(&mut [u8; 6], usize) -> (),
F2: Fn(&mut u8, u8) -> (),
{
let mut prev_digit = digits[0];
for (i, &mut digit) in digits.iter_mut().enumerate().skip(1)
{
if digit < prev_digit
{
f1(digits, i);
for digit in digits[i..].iter_mut()
{ f2(digit, prev_digit); }
break;
}
prev_digit = digit;
}
}
impl DigitsNeverDecreasingRange
{
fn new (lower_bound_inclusive: u32, upper_bound_inclusive: u32) -> Self
{
let mut initial_value = [0_u8; 6];
initial_value.clone_from_slice(&get_digits_of_n(lower_bound_inclusive));
satisfy_digits_not_decreasing(&mut initial_value, |_, _| (), |digit, prev_digit| *digit = prev_digit);
let mut end_value_inclusive = [0_u8; 6];
end_value_inclusive.clone_from_slice(&get_digits_of_n(upper_bound_inclusive));
satisfy_digits_not_decreasing(&mut end_value_inclusive, |digits, i| digits[i - 1] -= 1, |digit, _| *digit = 9);
let exhausted = initial_value > end_value_inclusive;
Self
{
exhausted,
next_value: initial_value,
end_value_inclusive,
}
}
}
fn get_digits_of_n<'a> (n: u32) -> Vec<u8>
{
(0..6).rev().map(|i| ((n / 10_u32.pow(i)) % 10) as u8).collect()
}
impl Iterator for DigitsNeverDecreasingRange
{
type Item = [u8; 6];
fn next (&mut self) -> Option<Self::Item>
{
if !self.exhausted
{
if self.next_value == self.end_value_inclusive
{
self.exhausted = true;
return Some(self.next_value);
}
let ret = self.next_value;
increment_to_next_non_decreasing_digits_value(&mut self.next_value);
return Some(ret);
}
None
}
}
fn increment_to_next_non_decreasing_digits_value (digits: &mut [u8]) -> u8
{
let index_last_digit = digits.len() - 1;
if digits[index_last_digit] < 9
{
digits[index_last_digit] += 1;
return digits[index_last_digit];
}
else if index_last_digit > 0
{
let ret = increment_to_next_non_decreasing_digits_value(&mut digits[..index_last_digit]);
digits[index_last_digit] = ret;
return ret;
}
digits[index_last_digit] = 9;
9
}
fn any_digits_repeat (digits: &[u8; 6]) -> bool
{
let mut prev_digit = digits[0];
for digit in digits.iter().skip(1)
{
if *digit == prev_digit
{ return true; }
prev_digit = *digit;
}
false
}
pub fn input_generator (input_range_inclusive_str: &str) -> DigitsNeverDecreasingRange
{
let ends: Vec<_> = input_range_inclusive_str.trim_end_matches('\n').split('-').map(|n_str| n_str.parse::<u32>().unwrap()).collect();
let (lower_bound_inclusive, upper_bound_inclusive) = (ends[0], ends[1]);
DigitsNeverDecreasingRange::new(lower_bound_inclusive, upper_bound_inclusive)
}
pub fn solve_part_2 (input_range: &DigitsNeverDecreasingRange) -> usize
{
input_range.filter(|digits| any_digits_repeat_exactly_twice(digits)).count()
}
fn any_digits_repeat_exactly_twice (digits: &[u8; 6]) -> bool
{
let mut prev_digit = digits[0];
let mut curr_repeat_count = 1;
let mut did_any_digits_repeat_only_twice_in_group = false;
for digit in digits.iter().skip(1)
{
if *digit == prev_digit
{ curr_repeat_count += 1; }
else
{
if curr_repeat_count == 2
{ did_any_digits_repeat_only_twice_in_group = true; }
curr_repeat_count = 1;
}
prev_digit = *digit;
}
if curr_repeat_count == 2
{ did_any_digits_repeat_only_twice_in_group = true; }
did_any_digits_repeat_only_twice_in_group
}