use crate::Solution;
use pmath::digits::digits;
use pmath::factorial_0_to_n;
problem!(Problem0074, 74, "Digit Factorial Chains");
impl Solution for Problem0074 {
fn solve(&self) -> String {
const MAX: usize = 1_000_000;
let mut chains = vec![0_u8; MAX];
let digit_factorials = factorial_0_to_n(9u64);
chains[169] = 3;
chains[363_601] = 3;
chains[1454] = 3;
chains[871] = 2;
chains[45361] = 2;
chains[872] = 2;
chains[45362] = 2;
let mut stack = Vec::new();
for i in 1..(MAX as u64) {
if chains[i as usize] == 0 {
stack.push((i, 0_u8));
while !stack.is_empty() {
if stack.last().unwrap().1 != 0 {
if stack.len() == 1 {
let only_item = stack.pop().unwrap();
chains[only_item.0 as usize] = only_item.1; } else {
let last_item = stack.pop().unwrap();
if last_item.0 < MAX as u64 {
chains[last_item.0 as usize] = last_item.1;
}
stack.last_mut().unwrap().1 = 1 + last_item.1;
}
} else {
let next_item = digits(stack.last().unwrap().0, 10)
.map(|d| digit_factorials[d as usize])
.sum::<u64>();
if next_item == stack.last().unwrap().0 {
stack.last_mut().unwrap().1 = 1;
} else if next_item < MAX as u64 && chains[next_item as usize] != 0 {
stack.last_mut().unwrap().1 = 1 + chains[next_item as usize];
} else {
stack.push((next_item, 0));
}
}
}
}
}
chains.into_iter().filter(|&c| c == 60).count().to_string()
}
}