use beetle_nonzero::NonZeroUnchecked;
use no_panic::no_panic;
use crate::Collatz;
#[no_panic]
pub fn odd_rule<T: Collatz>(n: NonZeroUnchecked<T>) -> Option<NonZeroUnchecked<T>> {
let one = T::one();
let three = one + one + one;
let three_times_n = n.value.checked_mul(&three)?; let three_times_n_plus_one = three_times_n.checked_add(&one)?; Some(NonZeroUnchecked::new(three_times_n_plus_one))
}
#[no_panic]
pub fn even_rule<T: Collatz>(n: NonZeroUnchecked<T>) -> NonZeroUnchecked<T> {
let two = T::one() + T::one();
NonZeroUnchecked::new(n.value / two)
}
#[no_panic]
pub fn basic<T: Collatz>(n: NonZeroUnchecked<T>) -> Option<NonZeroUnchecked<T>> {
if n.value.is_odd() {
odd_rule(n)
} else {
Some(even_rule(n))
}
}
#[no_panic]
pub fn halve_odds<T: Collatz>(n: NonZeroUnchecked<T>) -> NonZeroUnchecked<T> {
let two = T::one() + T::one();
let n = n.value;
if n.is_odd() {
NonZeroUnchecked::new((n + n + n + T::one()) / two)
} else {
NonZeroUnchecked::new(n / two)
}
}
#[no_panic]
pub fn trailing_zeros<T: Collatz>(n: NonZeroUnchecked<T>) -> Option<NonZeroUnchecked<T>> {
let applied_rules: NonZeroUnchecked<T> = basic(n)?;
let ans = crate::divide_while_even(applied_rules)?;
Some(ans)
}
#[no_panic]
pub fn trailing_zeros_num_is_odd<T: Collatz>(
n: NonZeroUnchecked<T>,
) -> Option<NonZeroUnchecked<T>> {
let n = n.value * T::from_u8(3)? + T::one();
let n = NonZeroUnchecked::new(n);
crate::divide_while_even(n)
}
#[no_panic]
pub fn trailing_zeros_num_is_even<T: Collatz>(
n: NonZeroUnchecked<T>,
) -> Option<NonZeroUnchecked<T>> {
crate::divide_while_even(n)
}