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
//! # Secure Container
//!
//! We speed things up by only checking numbers that have digits in non-decreasing order for pairs.
//! These numbers become rapidly less dense as the password value increases and there
//! are only 3003 total of these numbers with 6 digits.
use crate::util::parse::*;
use crate::util::slice::*;
pub fn parse(input: &str) -> Vec<u32> {
input.iter_unsigned().collect()
}
/// Password must contain at least one pair.
pub fn part1(input: &[u32]) -> u32 {
let predicate = |first: bool, second: bool, third: bool, fourth: bool, fifth: bool| {
first || second || third || fourth || fifth
};
passwords(input, predicate)
}
/// Password must contain at least one pair that's not part of a larger group.
pub fn part2(input: &[u32]) -> u32 {
let predicate = |first: bool, second: bool, third: bool, fourth: bool, fifth: bool| {
(first && !second)
|| (!first && second && !third)
|| (!second && third && !fourth)
|| (!third && fourth && !fifth)
|| (!fourth && fifth)
};
passwords(input, predicate)
}
fn passwords(input: &[u32], predicate: impl Fn(bool, bool, bool, bool, bool) -> bool) -> u32 {
let start = input[0];
let end = input[1];
// Split into six digits.
let mut digits = [
start / 100000,
(start / 10000) % 10,
(start / 1000) % 10,
(start / 100) % 10,
(start / 10) % 10,
start % 10,
];
// Increase the starting number to the next number that has all digits in non-decreasing order
// to ensure that the incrementing logic in the search loop works correctly.
// For example 223450 => 223455, 120568 => 122222 and 439999 => 444444.
for i in 1..6 {
if digits[i] < digits[i - 1] {
for j in i..6 {
digits[j] = digits[i - 1];
}
break;
}
}
let mut n = 0;
let mut count = 0;
while n <= end {
// Check current number
let first = digits[0] == digits[1];
let second = digits[1] == digits[2];
let third = digits[2] == digits[3];
let fourth = digits[3] == digits[4];
let fifth = digits[4] == digits[5];
if predicate(first, second, third, fourth, fifth) {
count += 1;
}
// Find the next number with all digits in non-decreasing order.
let mut i = 5;
while digits[i] == 9 {
i -= 1;
}
let next = digits[i] + 1;
while i <= 5 {
digits[i] = next;
i += 1;
}
// Convert number to `u32`.
n = digits.fold_decimal();
}
count
}