Use PuzzleUtils
This commit is contained in:
		
							
								
								
									
										10
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1,7 +1,15 @@
 | 
			
		||||
# This file is automatically @generated by Cargo.
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
version = 3
 | 
			
		||||
version = 4
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "project_euler"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "utils",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "utils"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "git+https://git.plobos.xyz/projects/PuzzleUtils.git#d3a93a875f56c8f865411c0b7437986f413ca524"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,3 +6,4 @@ edition = "2021"
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
utils = { git = "https://git.plobos.xyz/projects/PuzzleUtils.git" }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ fn get_divisors(n: usize) -> Vec<usize> {
 | 
			
		||||
            divisors.push(potential_divisor);
 | 
			
		||||
            divisors.push(n / potential_divisor);
 | 
			
		||||
        }
 | 
			
		||||
        potential_divisor = potential_divisor + 1;
 | 
			
		||||
        potential_divisor += 1;
 | 
			
		||||
    }
 | 
			
		||||
    // This almost made me go mad
 | 
			
		||||
    if potential_divisor * potential_divisor == n {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let mut sum = Number::from(0);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let width = Number::from(20);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let power = get_power(1000);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let mut num_letters = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ fn fibonacci_even_sum(limit: i64) -> i64 {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return sum;
 | 
			
		||||
    sum
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let factorial = get_factorial(100);
 | 
			
		||||
 
 | 
			
		||||
@@ -9,10 +9,10 @@ fn main() {
 | 
			
		||||
    for i in 2..10000 {
 | 
			
		||||
        let divisors = get_divisors(i);
 | 
			
		||||
        let sum_divisors = divisors.iter().sum();
 | 
			
		||||
        if amicable_cache.get(&sum_divisors).is_some() {
 | 
			
		||||
        if amicable_cache.contains_key(&sum_divisors) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if despicable_cache.get(&sum_divisors).is_some() {
 | 
			
		||||
        if despicable_cache.contains_key(&sum_divisors) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        let other_divisors = get_divisors(sum_divisors);
 | 
			
		||||
@@ -37,7 +37,7 @@ fn get_divisors(n: isize) -> Vec<isize> {
 | 
			
		||||
            divisors.insert(potential_divisor);
 | 
			
		||||
            divisors.insert(n / potential_divisor);
 | 
			
		||||
        }
 | 
			
		||||
        potential_divisor = potential_divisor + 1;
 | 
			
		||||
        potential_divisor += 1;
 | 
			
		||||
    }
 | 
			
		||||
    divisors.iter().map(|&divisor| divisor).collect()
 | 
			
		||||
    divisors.iter().copied().collect()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,13 +14,10 @@ fn main() {
 | 
			
		||||
        }
 | 
			
		||||
        let mut contained = false;
 | 
			
		||||
        for abundant in &abundants {
 | 
			
		||||
            match abundants.binary_search(&(num - abundant)) {
 | 
			
		||||
                Ok(_) => {
 | 
			
		||||
            if abundants.binary_search(&(num - abundant)).is_ok() {
 | 
			
		||||
                contained = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
                Err(_) => {}
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if !contained {
 | 
			
		||||
            sum += num;
 | 
			
		||||
@@ -54,7 +51,7 @@ fn get_divisors(n: usize) -> Vec<usize> {
 | 
			
		||||
            divisors.push(potential_divisor);
 | 
			
		||||
            divisors.push(n / potential_divisor);
 | 
			
		||||
        }
 | 
			
		||||
        potential_divisor = potential_divisor + 1;
 | 
			
		||||
        potential_divisor += 1;
 | 
			
		||||
    }
 | 
			
		||||
    // This almost made me go mad, should have used the one from 21
 | 
			
		||||
    if potential_divisor * potential_divisor == n {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
use utils::permutation::nth_lex;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let n = 1_000_000;
 | 
			
		||||
    let digits = vec![1, 0, 2, 3, 4, 5, 6, 7, 8, 9];
 | 
			
		||||
    let perm = permutation(digits, n)
 | 
			
		||||
    let perm = nth_lex(digits, n)
 | 
			
		||||
        .expect("Should return ok")
 | 
			
		||||
        .iter()
 | 
			
		||||
        .map(|&digit| digit.to_string())
 | 
			
		||||
@@ -12,55 +12,14 @@ fn main() {
 | 
			
		||||
    println!("{perm}");
 | 
			
		||||
    let digits = vec!["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
 | 
			
		||||
    //for n in 1..=factorial(digits.len()) {
 | 
			
		||||
    let perm = permutation(digits.clone(), n)
 | 
			
		||||
    let perm = nth_lex(digits.clone(), n)
 | 
			
		||||
        .expect("Should return ok")
 | 
			
		||||
        .join("");
 | 
			
		||||
    println!("{perm}");
 | 
			
		||||
    //}
 | 
			
		||||
    let digits = vec!["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
 | 
			
		||||
    let perm = permutation(digits.clone(), n)
 | 
			
		||||
    let perm = nth_lex(digits.clone(), n)
 | 
			
		||||
        .expect("Should return ok")
 | 
			
		||||
        .join("");
 | 
			
		||||
    println!("{perm}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Explanation
 | 
			
		||||
///
 | 
			
		||||
/// there are 10! possible permutations
 | 
			
		||||
/// for each first number there are 9!, for each first 2 numbers 8!, etc.
 | 
			
		||||
/// we check how many times we have 9! permutations before we're over 1_000_000
 | 
			
		||||
/// aka. 1000000 / 9!
 | 
			
		||||
/// we take the remainder and check how many times we have 8! before we?re over it
 | 
			
		||||
/// (1000000 % 9!) 8!
 | 
			
		||||
/// etc.
 | 
			
		||||
/// every iteration we remove the digit by the idx from the original permutation
 | 
			
		||||
/// we only check for 999999 permutations because we already have the first one
 | 
			
		||||
///
 | 
			
		||||
fn permutation<T: Copy + Ord>(mut digits: Vec<T>, nth: usize) -> Result<Vec<T>, Box<dyn Error>> {
 | 
			
		||||
    digits.sort();
 | 
			
		||||
    if nth == 1 {
 | 
			
		||||
        return Ok(digits);
 | 
			
		||||
    }
 | 
			
		||||
    if nth > factorial(digits.len()) || nth == 0 {
 | 
			
		||||
        return Err(Box::from("Out of bounds"));
 | 
			
		||||
    }
 | 
			
		||||
    let mut perm = Vec::new();
 | 
			
		||||
    let num_unique_digits = digits.len();
 | 
			
		||||
    let mut remainder = nth - 1;
 | 
			
		||||
    for idx in 1..=digits.len() {
 | 
			
		||||
        let permutations = remainder / factorial(num_unique_digits - idx);
 | 
			
		||||
        remainder = remainder % factorial(num_unique_digits - idx);
 | 
			
		||||
        perm.push(digits[permutations]);
 | 
			
		||||
        digits.remove(permutations);
 | 
			
		||||
    }
 | 
			
		||||
    Ok(perm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// number of permutations is n! where n is the number of digits
 | 
			
		||||
fn factorial(num: usize) -> usize {
 | 
			
		||||
    let mut fact = 1;
 | 
			
		||||
    for n in 1..=num {
 | 
			
		||||
        fact = fact * n;
 | 
			
		||||
    }
 | 
			
		||||
    fact
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,67 +1,17 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let fib_idx = find_fib(1000);
 | 
			
		||||
    println!("{fib_idx}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Way too slow, from 20 onward we go from µs to ms and from 32 we measure in seconds
 | 
			
		||||
//fn fib_recursion(n: Number) -> usize {
 | 
			
		||||
//    let one = Number::from(1);
 | 
			
		||||
//    if n == one {
 | 
			
		||||
//        return 1;
 | 
			
		||||
//    }
 | 
			
		||||
//    let two = Number::from(2);
 | 
			
		||||
//    if n == two {
 | 
			
		||||
//        return 1;
 | 
			
		||||
//    }
 | 
			
		||||
//    fib_recursion(n.clone() - two) + fib_recursion(n - one)
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
// almost as fast as the no recursion solution but more complicated and more memory intensiv
 | 
			
		||||
// creating an inner function to not have to pass in the hashmap from outside makes it slightly slower
 | 
			
		||||
//fn fib_recursion_cached(n: Number) -> Number {
 | 
			
		||||
//    let mut cache: HashMap<Number, Number> = HashMap::new();
 | 
			
		||||
//    fn inner_fib_recursion_cached(n: Number, cache: &mut HashMap<Number, Number>) -> Number {
 | 
			
		||||
//        let one = Number::from(1);
 | 
			
		||||
//        if n == one {
 | 
			
		||||
//            return one;
 | 
			
		||||
//        }
 | 
			
		||||
//        let two = Number::from(2);
 | 
			
		||||
//        if n == two {
 | 
			
		||||
//            return one;
 | 
			
		||||
//        }
 | 
			
		||||
//        match cache.get(&n) {
 | 
			
		||||
//            Some(res) => return res.clone(),
 | 
			
		||||
//            None => {
 | 
			
		||||
//                let res = inner_fib_recursion_cached(n.clone() - two, cache) + inner_fib_recursion_cached(n.clone() - one, cache);
 | 
			
		||||
//                cache.insert(n.clone(), res.clone());
 | 
			
		||||
//                return res;
 | 
			
		||||
//            },
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
//    inner_fib_recursion_cached(n, &mut cache)
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
// faster than recursion
 | 
			
		||||
fn fib(n: usize) -> Number {
 | 
			
		||||
    let mut last_two = (Number::from(1), Number::from(1));
 | 
			
		||||
    let mut iteration = 1;
 | 
			
		||||
    while iteration < n {
 | 
			
		||||
        last_two = (last_two.1.clone(), last_two.0 + last_two.1);
 | 
			
		||||
        iteration += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    last_two.0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn find_fib(num_digits: usize) -> usize {
 | 
			
		||||
    let mut n = 1;
 | 
			
		||||
    loop {
 | 
			
		||||
        let fib = fib(n);
 | 
			
		||||
        let fib = Number::fib(n);
 | 
			
		||||
        let fib_len = fib.digits.len();
 | 
			
		||||
        if fib_len == num_digits {
 | 
			
		||||
            return n;
 | 
			
		||||
            return n as usize;
 | 
			
		||||
        }
 | 
			
		||||
        n += 1;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ fn main() {
 | 
			
		||||
        for corner in 0..4 {
 | 
			
		||||
            sum += last_square_end + (square * 2) * (corner + 1);
 | 
			
		||||
        }
 | 
			
		||||
        last_square_end = last_square_end + (square * 2) * 4;
 | 
			
		||||
        last_square_end += (square * 2) * 4;
 | 
			
		||||
    }
 | 
			
		||||
    println!("{sum}");
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use std::collections::HashSet;
 | 
			
		||||
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let mut terms: HashSet<Number> = HashSet::new();
 | 
			
		||||
    let max = 100;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,6 @@
 | 
			
		||||
use utils::math::prime_factors;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let result = prime_factors(600851475143).into_iter().max();
 | 
			
		||||
    println!("Result: {}", result.unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn prime_factors(number: i64) -> Vec<i64> {
 | 
			
		||||
    let mut factors = vec![2];
 | 
			
		||||
    let upper: i64 = (number as f64).sqrt().ceil() as i64;
 | 
			
		||||
    for i in 3..upper {
 | 
			
		||||
        let mut is_prime = true;
 | 
			
		||||
        for factor in &factors {
 | 
			
		||||
            if i % factor == 0 {
 | 
			
		||||
                is_prime = false;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if is_prime && number % i == 0 {
 | 
			
		||||
            factors.push(i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return factors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::prime_factors;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn it_works() {
 | 
			
		||||
        let result = prime_factors(13195).into_iter().max();
 | 
			
		||||
        assert_eq!(result.unwrap(), 29);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    println!("{}", nth_powers(5))
 | 
			
		||||
@@ -11,7 +11,7 @@ fn nth_powers(nth: u32) -> isize {
 | 
			
		||||
    loop {
 | 
			
		||||
        let attempt = max * idx;
 | 
			
		||||
        if Number::from(attempt).digits.len() < idx as usize {
 | 
			
		||||
            max = (idx - 1) * max;
 | 
			
		||||
            max *= idx - 1;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        idx += 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +1,18 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::{math::factorial, number::Number};
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let factorials_sum = digit_factorials();
 | 
			
		||||
    println!("{factorials_sum}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn factorial(num: isize) -> isize {
 | 
			
		||||
    let mut fact = 1;
 | 
			
		||||
    for n in 1..=num {
 | 
			
		||||
        fact = fact * n;
 | 
			
		||||
    }
 | 
			
		||||
    fact
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn digit_factorials() -> isize {
 | 
			
		||||
    let mut factorials = vec![];
 | 
			
		||||
    let mut max = factorial(9);
 | 
			
		||||
    let mut max = factorial(9) as isize;
 | 
			
		||||
    let mut idx = 1;
 | 
			
		||||
    loop {
 | 
			
		||||
        let attempt = max * idx;
 | 
			
		||||
        if Number::from(attempt).digits.len() < idx as usize {
 | 
			
		||||
            max = (idx - 1) * max;
 | 
			
		||||
            max *= idx - 1;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        idx += 1;
 | 
			
		||||
@@ -29,7 +21,7 @@ fn digit_factorials() -> isize {
 | 
			
		||||
        let digits_fact_sum = Number::from(n)
 | 
			
		||||
            .digits
 | 
			
		||||
            .iter()
 | 
			
		||||
            .map(|&digit| factorial(digit))
 | 
			
		||||
            .map(|&digit| factorial(digit as u64) as isize)
 | 
			
		||||
            .sum();
 | 
			
		||||
        if n == digits_fact_sum {
 | 
			
		||||
            factorials.push(n);
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ fn find_largest_palindrome(digits: u32) -> i64 {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return largest;
 | 
			
		||||
    largest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn check_palindrome(number: i64) -> bool {
 | 
			
		||||
@@ -27,7 +27,7 @@ fn check_palindrome(number: i64) -> bool {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
    true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
use project_euler::number::Number;
 | 
			
		||||
use utils::number::Number;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    println!("{}", power_series(1000));
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ fn solve() -> usize {
 | 
			
		||||
    let mut chain_length = primes.len() - 1;
 | 
			
		||||
    loop {
 | 
			
		||||
        for prime_window in primes.windows(chain_length) {
 | 
			
		||||
            let sum = prime_window.iter().map(|&prime| prime).sum::<usize>();
 | 
			
		||||
            let sum = prime_window.iter().copied().sum::<usize>();
 | 
			
		||||
            if primes.contains(&sum) {
 | 
			
		||||
                return sum;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,19 @@
 | 
			
		||||
use utils::math::factorial;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let result = smallest_multiple(20);
 | 
			
		||||
    println!("Result: {result}");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn smallest_multiple(number: i64) -> i64 {
 | 
			
		||||
    let factorial = factorial(number);
 | 
			
		||||
    let factorial = factorial(number.try_into().unwrap()) as i64;
 | 
			
		||||
    for i in number..=factorial {
 | 
			
		||||
        if is_multiple(i, number) {
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return factorial;
 | 
			
		||||
    factorial
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn is_multiple(number: i64, range: i64) -> bool {
 | 
			
		||||
@@ -23,14 +25,6 @@ fn is_multiple(number: i64, range: i64) -> bool {
 | 
			
		||||
    true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn factorial(n: i64) -> i64 {
 | 
			
		||||
    let mut result = 1;
 | 
			
		||||
    for i in 1..=n {
 | 
			
		||||
        result *= i;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::smallest_multiple;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,10 @@
 | 
			
		||||
use utils::math::nth_prime;
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let result = nth_prime(10001);
 | 
			
		||||
    println!("Result: {}", result.unwrap());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn nth_prime(nth: i64) -> Option<i64> {
 | 
			
		||||
    let mut primes: Vec<i64> = vec![2];
 | 
			
		||||
 | 
			
		||||
    let mut i = 3;
 | 
			
		||||
 | 
			
		||||
    while primes.len() < nth as usize {
 | 
			
		||||
        let mut is_prime = true;
 | 
			
		||||
        for prime in &primes {
 | 
			
		||||
            if i % prime == 0 {
 | 
			
		||||
                is_prime = false;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if is_prime {
 | 
			
		||||
            primes.push(i);
 | 
			
		||||
        }
 | 
			
		||||
        i += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return primes.pop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::nth_prime;
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ fn adjacent_product(number: &str, window: usize) -> i64 {
 | 
			
		||||
        .max()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
    result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 
 | 
			
		||||
@@ -14,5 +14,5 @@ fn main() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn is_triplet(a: usize, b: usize, c: usize) -> bool {
 | 
			
		||||
    return a * a + b * b == c * c;
 | 
			
		||||
    a * a + b * b == c * c
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										414
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										414
									
								
								src/lib.rs
									
									
									
									
									
								
							@@ -1,414 +0,0 @@
 | 
			
		||||
pub mod number {
 | 
			
		||||
    use std::cmp::{min, Ordering};
 | 
			
		||||
    use std::fmt::{Display, Formatter};
 | 
			
		||||
    use std::iter::zip;
 | 
			
		||||
    use std::ops::{Add, Div, Mul, Rem, Sub};
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 | 
			
		||||
    pub enum Sign {
 | 
			
		||||
        Positif,
 | 
			
		||||
        Negatif,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone, Debug, Eq, PartialEq, Hash)]
 | 
			
		||||
    pub struct Number {
 | 
			
		||||
        pub digits: Vec<isize>,
 | 
			
		||||
        pub sign: Sign,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Number {
 | 
			
		||||
        pub fn get_digit(n: isize, pos: usize) -> isize {
 | 
			
		||||
            let modulo = 10isize.pow(pos as u32 + 1);
 | 
			
		||||
            let divisor = modulo / 10;
 | 
			
		||||
            (n % modulo) / divisor
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub const fn byte_to_digit(b: u8) -> isize {
 | 
			
		||||
            // wrapping_sub('0' as u32) same as - 48 but less magical
 | 
			
		||||
            (b as isize).wrapping_sub('0' as isize)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn handle_overflows(&mut self) {
 | 
			
		||||
            let new_digits = &mut self.digits;
 | 
			
		||||
            let digits_len = new_digits.len();
 | 
			
		||||
            let mut digits_idx = digits_len - 1;
 | 
			
		||||
            loop {
 | 
			
		||||
                let digit_or_num = new_digits[digits_idx];
 | 
			
		||||
                let digit_len = if digit_or_num != 0 {
 | 
			
		||||
                    (digit_or_num.abs() as f64 + 1.0).log10().ceil() as usize
 | 
			
		||||
                } else {
 | 
			
		||||
                    1
 | 
			
		||||
                };
 | 
			
		||||
                for i in 0..digit_len {
 | 
			
		||||
                    let new_digit = Self::get_digit(digit_or_num, i);
 | 
			
		||||
                    let (digit_idx, is_overflow) = digits_idx.overflowing_sub(i);
 | 
			
		||||
                    if is_overflow {
 | 
			
		||||
                        new_digits.insert(0, new_digit);
 | 
			
		||||
                        digits_idx += 1;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let digit = new_digits.get_mut(digit_idx).unwrap();
 | 
			
		||||
                        if i == 0 {
 | 
			
		||||
                            *digit = new_digit;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            *digit += new_digit;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if digits_idx == 0 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                digits_idx -= 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn handle_underflows(&mut self) {
 | 
			
		||||
            let new_digits = &mut self.digits;
 | 
			
		||||
            let mut digits_len = new_digits.len();
 | 
			
		||||
            for digit in new_digits.clone() {
 | 
			
		||||
                match digit.cmp(&0) {
 | 
			
		||||
                    Ordering::Equal => {
 | 
			
		||||
                        if digits_len == 1 {
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        digits_len -= 1;
 | 
			
		||||
                        new_digits.remove(0);
 | 
			
		||||
                    }
 | 
			
		||||
                    Ordering::Less => {
 | 
			
		||||
                        self.sign = Sign::Negatif;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => break,
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            let mut digits_idx = digits_len - 1;
 | 
			
		||||
            loop {
 | 
			
		||||
                let digit = new_digits[digits_idx];
 | 
			
		||||
                if self.sign == Sign::Positif && digit < 0 && digits_idx > 0 {
 | 
			
		||||
                    let mut_digit = new_digits.get_mut(digits_idx).unwrap();
 | 
			
		||||
                    *mut_digit = 10 - digit.abs();
 | 
			
		||||
                    let mut_digit = new_digits.get_mut(digits_idx - 1).unwrap();
 | 
			
		||||
                    *mut_digit -= 1;
 | 
			
		||||
                } else {
 | 
			
		||||
                    let mut_digit = new_digits.get_mut(digits_idx).unwrap();
 | 
			
		||||
                    *mut_digit = digit.abs();
 | 
			
		||||
                }
 | 
			
		||||
                if digits_idx == 0 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                digits_idx -= 1;
 | 
			
		||||
            }
 | 
			
		||||
            for digit in new_digits.clone() {
 | 
			
		||||
                match digit.cmp(&0) {
 | 
			
		||||
                    Ordering::Equal => {
 | 
			
		||||
                        new_digits.remove(0);
 | 
			
		||||
                    }
 | 
			
		||||
                    _ => break,
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn pow(self, n: u32) -> Self {
 | 
			
		||||
            let mut result = self.clone();
 | 
			
		||||
            if ((self.digits.len() * 8) as u32) < isize::BITS {
 | 
			
		||||
                let number = isize::from(self);
 | 
			
		||||
                for _i in 1..n {
 | 
			
		||||
                    result = result * number;
 | 
			
		||||
                }
 | 
			
		||||
                result
 | 
			
		||||
            } else {
 | 
			
		||||
                let number = self.clone();
 | 
			
		||||
                for _i in 1..n {
 | 
			
		||||
                    result = result * number.clone();
 | 
			
		||||
                }
 | 
			
		||||
                result
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pub fn fact(self) -> Self {
 | 
			
		||||
            let mut fact = Number::from(1);
 | 
			
		||||
            if ((self.digits.len() * 8) as u32) < isize::BITS {
 | 
			
		||||
                let max = isize::from(self);
 | 
			
		||||
                for n in 1..=max {
 | 
			
		||||
                    fact = fact * n;
 | 
			
		||||
                }
 | 
			
		||||
                fact
 | 
			
		||||
            } else {
 | 
			
		||||
                panic!("starting number too big")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn div_with_rem(n1: Number, n2: Number) -> (Number, Number) {
 | 
			
		||||
            let n1_len = n1.digits.len();
 | 
			
		||||
            let n2_len = n2.digits.len();
 | 
			
		||||
            if n2_len > n1_len {
 | 
			
		||||
                return (Number::from(0), n2);
 | 
			
		||||
            }
 | 
			
		||||
            let dividend = n1.digits[..n2_len].to_vec();
 | 
			
		||||
            let mut quotient = vec![];
 | 
			
		||||
            let mut remainder = Number {
 | 
			
		||||
                digits: dividend.clone(),
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            let mut iteration = 1;
 | 
			
		||||
            loop {
 | 
			
		||||
                let mut factor = 0;
 | 
			
		||||
                loop {
 | 
			
		||||
                    let temp_remainder = remainder.clone() - n2.clone();
 | 
			
		||||
                    if temp_remainder.sign == Sign::Negatif {
 | 
			
		||||
                        quotient.push(factor);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    remainder = temp_remainder;
 | 
			
		||||
                    factor += 1;
 | 
			
		||||
                }
 | 
			
		||||
                if n1_len == n2_len + iteration - 1 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                remainder.digits.push(n1.digits[n2_len + iteration - 1]);
 | 
			
		||||
                iteration += 1;
 | 
			
		||||
            }
 | 
			
		||||
            let mut res = Number {
 | 
			
		||||
                digits: quotient,
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            res.handle_overflows();
 | 
			
		||||
            for digit in res.clone().digits {
 | 
			
		||||
                if digit != 0 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                res.digits.remove(0);
 | 
			
		||||
            }
 | 
			
		||||
            for digit in remainder.clone().digits {
 | 
			
		||||
                if digit != 0 || remainder.digits.len() == 1 {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                remainder.digits.remove(0);
 | 
			
		||||
            }
 | 
			
		||||
            (res, remainder)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<Number> for isize {
 | 
			
		||||
        fn from(value: Number) -> Self {
 | 
			
		||||
            let mut num = 0;
 | 
			
		||||
            for (pos, &digit) in value.digits.iter().rev().enumerate() {
 | 
			
		||||
                num += digit * 10isize.pow(pos as u32);
 | 
			
		||||
            }
 | 
			
		||||
            num
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<Number> for String {
 | 
			
		||||
        fn from(value: Number) -> Self {
 | 
			
		||||
            let string_vec: Vec<String> = value
 | 
			
		||||
                .digits
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|&digit| digit.to_string())
 | 
			
		||||
                .collect();
 | 
			
		||||
            string_vec.concat()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<&str> for Number {
 | 
			
		||||
        fn from(value: &str) -> Self {
 | 
			
		||||
            let bytes = value.as_bytes();
 | 
			
		||||
            let (sign, idx_start) = match bytes[0] {
 | 
			
		||||
                b'-' => (Sign::Negatif, 1),
 | 
			
		||||
                _ => (Sign::Positif, 0),
 | 
			
		||||
            };
 | 
			
		||||
            let mut digits = vec![];
 | 
			
		||||
            for &byte in &bytes[idx_start..] {
 | 
			
		||||
                let digit = Self::byte_to_digit(byte);
 | 
			
		||||
                digits.push(digit);
 | 
			
		||||
            }
 | 
			
		||||
            Self { digits, sign }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl From<isize> for Number {
 | 
			
		||||
        fn from(value: isize) -> Self {
 | 
			
		||||
            let mut sign = Sign::Positif;
 | 
			
		||||
            if value < 0 {
 | 
			
		||||
                sign = Sign::Negatif;
 | 
			
		||||
            }
 | 
			
		||||
            let num_len = if value > 0 {
 | 
			
		||||
                (value as f64 + 1.0).log10().ceil() as usize
 | 
			
		||||
            } else {
 | 
			
		||||
                1
 | 
			
		||||
            };
 | 
			
		||||
            let mut digits = vec![];
 | 
			
		||||
            for digit_idx in 0..num_len {
 | 
			
		||||
                let digit = Self::get_digit(value, digit_idx);
 | 
			
		||||
                digits.push(digit);
 | 
			
		||||
            }
 | 
			
		||||
            let digits = digits.iter().rev().copied().collect();
 | 
			
		||||
            Self { digits, sign }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Display for Number {
 | 
			
		||||
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
            let number_string = self
 | 
			
		||||
                .digits
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|&digit| digit.to_string())
 | 
			
		||||
                .collect::<Vec<String>>()
 | 
			
		||||
                .join("");
 | 
			
		||||
            match self.sign {
 | 
			
		||||
                Sign::Positif => write!(f, "{number_string}"),
 | 
			
		||||
                Sign::Negatif => write!(f, "-{number_string}"),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Add for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn add(self, rhs: Self) -> Self::Output {
 | 
			
		||||
            let self_len = self.digits.len();
 | 
			
		||||
            let rhs_len = rhs.digits.len();
 | 
			
		||||
            let mut self_digits = self.digits.clone();
 | 
			
		||||
            let mut rhs_digits = rhs.digits.clone();
 | 
			
		||||
            if self_len != rhs_len {
 | 
			
		||||
                let difference = (self_len).abs_diff(rhs_len);
 | 
			
		||||
                let pad = vec![0isize; difference];
 | 
			
		||||
                if min(self_len, rhs_len) == self_len {
 | 
			
		||||
                    self_digits = [pad, self.digits].concat();
 | 
			
		||||
                } else {
 | 
			
		||||
                    rhs_digits = [pad, rhs.digits].concat();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            let zipped = zip(self_digits.iter(), rhs_digits.iter());
 | 
			
		||||
            let added = zipped
 | 
			
		||||
                .map(|(self_digit, rhs_digit)| self_digit + rhs_digit)
 | 
			
		||||
                .collect();
 | 
			
		||||
            let mut overflown_number = Self {
 | 
			
		||||
                digits: added,
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            overflown_number.handle_overflows();
 | 
			
		||||
            overflown_number
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Sub for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn sub(self, rhs: Self) -> Self::Output {
 | 
			
		||||
            let self_len = self.digits.len();
 | 
			
		||||
            let rhs_len = rhs.digits.len();
 | 
			
		||||
            let mut self_digits = self.digits.clone();
 | 
			
		||||
            let mut rhs_digits = rhs.digits.clone();
 | 
			
		||||
            if self_len != rhs_len {
 | 
			
		||||
                let difference = (self_len).abs_diff(rhs_len);
 | 
			
		||||
                let pad = vec![0isize; difference];
 | 
			
		||||
                if min(self_len, rhs_len) == self_len {
 | 
			
		||||
                    self_digits = [pad, self.digits].concat();
 | 
			
		||||
                } else {
 | 
			
		||||
                    rhs_digits = [pad, rhs.digits].concat();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            let zipped = zip(self_digits.iter(), rhs_digits.iter());
 | 
			
		||||
            let added = zipped
 | 
			
		||||
                .map(|(self_digit, rhs_digit)| self_digit - rhs_digit)
 | 
			
		||||
                .collect();
 | 
			
		||||
            let mut underflown_number = Self {
 | 
			
		||||
                digits: added,
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            underflown_number.handle_underflows();
 | 
			
		||||
            underflown_number
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Mul for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn mul(self, rhs: Self) -> Self::Output {
 | 
			
		||||
            let multiplied = self.digits.iter().rev().enumerate().map(|(pos, &digit)| {
 | 
			
		||||
                let mut mult = digit * rhs.clone();
 | 
			
		||||
                mult.digits = [mult.digits, vec![0; pos]].concat();
 | 
			
		||||
                mult
 | 
			
		||||
            });
 | 
			
		||||
            let mut overflown_number = multiplied.reduce(|acc, num| acc + num).unwrap();
 | 
			
		||||
            overflown_number.handle_overflows();
 | 
			
		||||
            overflown_number
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Mul<Number> for isize {
 | 
			
		||||
        type Output = Number;
 | 
			
		||||
 | 
			
		||||
        fn mul(self, rhs: Number) -> Self::Output {
 | 
			
		||||
            let multiplied = rhs.digits.iter().map(|digit| digit * self).collect();
 | 
			
		||||
            let mut overflown_number = Number {
 | 
			
		||||
                digits: multiplied,
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            overflown_number.handle_overflows();
 | 
			
		||||
            overflown_number
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Mul<isize> for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn mul(self, rhs: isize) -> Self::Output {
 | 
			
		||||
            let multiplied = self.digits.iter().map(|digit| digit * rhs).collect();
 | 
			
		||||
            let mut overflown_number = Self {
 | 
			
		||||
                digits: multiplied,
 | 
			
		||||
                sign: Sign::Positif,
 | 
			
		||||
            };
 | 
			
		||||
            overflown_number.handle_overflows();
 | 
			
		||||
            overflown_number
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Div for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn div(self, rhs: Self) -> Self::Output {
 | 
			
		||||
            Self::div_with_rem(self, rhs).0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl Rem for Number {
 | 
			
		||||
        type Output = Self;
 | 
			
		||||
 | 
			
		||||
        fn rem(self, rhs: Self) -> Self::Output {
 | 
			
		||||
            Self::div_with_rem(self, rhs).1
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(test)]
 | 
			
		||||
    mod number_tests {
 | 
			
		||||
        use crate::number::{Number, Sign};
 | 
			
		||||
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_from_isize() {
 | 
			
		||||
            let number = Number::from(-1234);
 | 
			
		||||
            assert_eq!(
 | 
			
		||||
                number,
 | 
			
		||||
                Number {
 | 
			
		||||
                    digits: vec![1234],
 | 
			
		||||
                    sign: Sign::Negatif
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[test]
 | 
			
		||||
        fn test_get_digit() {
 | 
			
		||||
            let num = 12345;
 | 
			
		||||
            let digit_1 = Number::get_digit(num, 0);
 | 
			
		||||
            let digit_2 = Number::get_digit(num, 1);
 | 
			
		||||
            let digit_3 = Number::get_digit(num, 2);
 | 
			
		||||
            let digit_4 = Number::get_digit(num, 3);
 | 
			
		||||
            let digit_5 = Number::get_digit(num, 4);
 | 
			
		||||
            assert_eq!(digit_1, 5);
 | 
			
		||||
            assert_eq!(digit_2, 4);
 | 
			
		||||
            assert_eq!(digit_3, 3);
 | 
			
		||||
            assert_eq!(digit_4, 2);
 | 
			
		||||
            assert_eq!(digit_5, 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user