use std::error::Error;
use std::collections::BTreeSet;
pub fn is_prime(n: u64) -> bool {
if n == 2 {
return true;
}
if n < 2 || (n % 2) == 0 {
return false;
}
let mut k = 3;
while (k * k) <= n {
if (n % k) == 0 {
return false;
}
k += 1;
}
true
}
pub fn triangular_number(n: u64) -> Result<u64, Box<dyn Error>> {
let n_plus_1 = n.checked_add(1).ok_or_else(|| "overflow")?;
let t_n = n_plus_1.checked_mul(n).ok_or_else(|| "overflow")? / 2;
Ok(t_n)
}
pub fn factors_of(n: u64) -> BTreeSet<u64> {
if n < 2 {
return BTreeSet::from([n]);
}
let mut factors = BTreeSet::new();
let sqrt = n.isqrt();
for k in 1..=sqrt {
let (q, r) = (n / k, n % k);
if r == 0 {
factors.insert(k);
if q != sqrt {
factors.insert(q);
}
}
}
factors
}
pub fn is_palindrome(s: &str) -> bool {
let chars: Vec<char>= s.to_lowercase().chars().collect();
let mut left_idx = 0;
let mut right_idx = chars.len() - 1;
while left_idx < right_idx {
let left_char = &chars[left_idx];
if !left_char.is_alphanumeric() {
left_idx += 1;
continue;
}
let right_char = &chars[right_idx];
if !right_char.is_alphanumeric() {
right_idx -= 1;
continue;
}
if left_char != right_char {
return false;
}
left_idx += 1;
right_idx -= 1;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn below_2_are_not_prime() {
assert!(!is_prime(0));
assert!(!is_prime(1));
}
#[test]
fn primes_below_20() {
assert!(is_prime(2));
assert!(is_prime(3));
assert!(is_prime(5));
assert!(is_prime(7));
assert!(is_prime(11));
assert!(is_prime(13));
assert!(is_prime(17));
assert!(is_prime(19));
}
#[test]
fn palindrome_one_casing() {
assert!(is_palindrome("tacocat"));
}
#[test]
fn palindrome_case_insensitive() {
assert!(is_palindrome("TacoCat"));
}
#[test]
fn palindrome_with_spaces() {
assert!(is_palindrome("taco cat"));
}
#[test]
fn palindrome_numbers() {
assert!(is_palindrome("1234321"));
}
#[test]
fn triangular_small() {
assert_eq!(0, triangular_number(0).unwrap());
assert_eq!(1, triangular_number(1).unwrap());
assert_eq!(3, triangular_number(2).unwrap());
assert_eq!(6, triangular_number(3).unwrap());
assert_eq!(10, triangular_number(4).unwrap());
assert_eq!(15, triangular_number(5).unwrap());
}
#[test]
fn triangular_overflow() -> Result<(), String> {
let result = triangular_number(u64::MAX);
if result.is_err() {
Ok(())
} else {
Err(String::from("large triangular numbers should overflow"))
}
}
#[test]
fn factors_of_zero_and_one() {
assert_eq!(BTreeSet::from([0]), factors_of(0));
assert_eq!(BTreeSet::from([1]), factors_of(1));
}
#[test]
fn factors_non_square() {
let result = factors_of(28);
assert_eq!(BTreeSet::from([1, 2, 4, 7, 14, 28]), result);
}
#[test]
fn factors_of_a_square() {
let result = factors_of(64);
assert_eq!(BTreeSet::from([1, 2, 4, 8, 16, 32, 64]), result);
}
}