use num_primes::{BigUint, Verification};
use num_traits::Pow;
use std::{
collections::VecDeque,
iter::from_generator,
ops::{Div, Mul, Rem},
};
pub fn insert_digit(n: &BigUint, position: usize, contains_zero: bool) -> impl Iterator<Item = BigUint> + '_ {
debug_assert!(position <= n.to_string().len(), "position {} of {} is out of range", position, n);
let start_index: u8 = if contains_zero { 0 } else { 1 };
let pow = BigUint::from(10usize).pow(position);
let lhs = n.div(&pow).mul(&pow).mul(10usize);
let rhs = n.rem(&pow);
from_generator(move || {
for i in start_index..=9 {
let digit = BigUint::from(i).mul(&pow);
let new = digit + &lhs + &rhs;
if Verification::is_prime(&new) {
yield new;
}
}
})
}
pub fn super_prime(start: &BigUint, iteration: usize) -> Vec<BigUint> {
let seq = vec![start.clone()];
let mut stack = VecDeque::new();
stack.push_back(seq);
'outer: while let Some(old_seq) = stack.pop_back() {
let last = unsafe { old_seq.last().unwrap_unchecked() };
let old_len = last.to_string().len();
for i in 0..old_len {
for number in insert_digit(last, i, i != old_len) {
let mut new_seq = old_seq.clone();
new_seq.push(number.clone());
stack.push_back(new_seq);
if old_len == iteration {
break 'outer;
}
}
}
}
stack.pop_back().unwrap_or_default()
}