From 6e82b8e1a821c4943b3a5478ea799cc033d33dbb Mon Sep 17 00:00:00 2001 From: Olivia Appleton Date: Sun, 25 Aug 2024 15:06:43 -0500 Subject: [PATCH] Solve 36, 37, 45, 53 in rust --- rust/src/include/factors.rs | 8 ++-- rust/src/include/fibonacci.rs | 81 ++++++++++++++++++++++++++++++++++ rust/src/include/iter_cache.rs | 4 ++ rust/src/include/mod.rs | 1 + rust/src/include/primes.rs | 37 +++++----------- rust/src/include/problems.rs | 8 ++++ rust/src/include/utils.rs | 9 +++- rust/src/lib.rs | 4 ++ rust/src/main.rs | 30 +++++++++++-- rust/src/p0002.rs | 12 +---- rust/src/p0004.rs | 7 +-- rust/src/p0036.rs | 26 +++++++++++ rust/src/p0037.rs | 56 +++++++++++++++++++++++ rust/src/p0045.rs | 50 +++++++++++++++++++++ rust/src/p0053.rs | 26 +++++++++++ 15 files changed, 308 insertions(+), 51 deletions(-) create mode 100644 rust/src/include/fibonacci.rs create mode 100644 rust/src/p0036.rs create mode 100644 rust/src/p0037.rs create mode 100644 rust/src/p0045.rs create mode 100644 rust/src/p0053.rs diff --git a/rust/src/include/factors.rs b/rust/src/include/factors.rs index d5603166..b322d3ba 100644 --- a/rust/src/include/factors.rs +++ b/rust/src/include/factors.rs @@ -17,7 +17,7 @@ pub struct ProperDivisors next_size: usize, } -pub fn proper_divisors(num: I) -> ProperDivisors +pub fn proper_divisors(num: I) -> impl Iterator where I: Hash + Zero + One + Add + Ord + Copy + Div + Rem + 'static { return ProperDivisors::::new(num); @@ -48,9 +48,9 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div + Rem + return None; } if self.next_size == 0 { -self.next_size += 1; -return Some(one()); -} + self.next_size += 1; + return Some(one()); + } while self.curr_index < self.current_batch.len() { let result = self.current_batch[self.curr_index]; self.curr_index += 1; diff --git a/rust/src/include/fibonacci.rs b/rust/src/include/fibonacci.rs new file mode 100644 index 00000000..3ac40d13 --- /dev/null +++ b/rust/src/include/fibonacci.rs @@ -0,0 +1,81 @@ +use std::ops::{Add,Mul}; + +use num_traits::{one,zero,One,Zero}; + +use crate::include::iter_cache::cache_iterator; + +pub fn fib() -> impl Iterator { + return cache_iterator(Fibonacci::::new()); +} + +pub fn fib_by_3() -> impl Iterator { + return cache_iterator(FibonacciBy3::::new()); +} + +pub struct Fibonacci { + a: I, + b: I, +} + +impl Default for Fibonacci where I: Zero + One { + fn default() -> Self { + return Fibonacci::{ + a: zero(), + b: one(), + }; + } +} + +impl Fibonacci where I: Zero + One { + pub fn new() -> Self { + return Default::default(); + } +} + +impl Iterator for Fibonacci where I: Zero + One + Add { + type Item = I; + + fn next(&mut self) -> Option { + let prior_a = a; + let prior_b = b; + self.b = self.a + self.b; + self.a = prior_b; + return Some(prior_a); + } +} + +pub struct FibonacciBy3 { + a: I, + b: I, +} + +impl Default for FibonacciBy3 where I: Zero + One { + fn default() -> Self { + let two = one() + one(); + let four = two + two; + return FibonacciBy3::{ + a: two, + b: four + four, + }; + } +} + +impl FibonacciBy3 where I: Zero + One + Add { + pub fn new() -> Self { + return Default::default(); + } +} + +impl Iterator for FibonacciBy3 where I: Zero + One + Add + Mul { + type Item = I; + + fn next(&mut self) -> Option { + let two = one() + one(); + let four = two + two; + let prior_a = a; + let prior_b = b; + self.b = four * self.a + self.b; + self.a = prior_b; + return Some(prior_a); + } +} diff --git a/rust/src/include/iter_cache.rs b/rust/src/include/iter_cache.rs index c85b0041..0e7a1e3f 100644 --- a/rust/src/include/iter_cache.rs +++ b/rust/src/include/iter_cache.rs @@ -6,6 +6,10 @@ use std::sync::Once; static INIT: Once = Once::new(); static mut CACHE_MAP: Option>>>>> = None; +pub fn cache_iterator(iterator: impl Iterator) -> impl Iterator { + return CachingIterator::new(iterator); +} + pub struct CachingIterator where I: Iterator + 'static, diff --git a/rust/src/include/mod.rs b/rust/src/include/mod.rs index 1d9ca496..0ed57c7b 100644 --- a/rust/src/include/mod.rs +++ b/rust/src/include/mod.rs @@ -1,5 +1,6 @@ pub mod iter_cache; pub mod factors; +pub mod fibonacci; pub mod math; pub mod primes; pub mod problems; diff --git a/rust/src/include/primes.rs b/rust/src/include/primes.rs index 2993db66..42bfb6ad 100644 --- a/rust/src/include/primes.rs +++ b/rust/src/include/primes.rs @@ -5,19 +5,15 @@ use std::ops::{Add,Div,Mul,Rem}; use num_traits::{one,zero,One,Zero}; -use crate::include::iter_cache::CachingIterator; +use crate::include::iter_cache::cache_iterator; -pub struct Eratosthenes -where I: Hash -{ +pub struct Eratosthenes where I: Hash { sieve: HashMap>, prime: I, candidate: I, } -impl Default for Eratosthenes -where I: Hash + One + Zero + Add -{ +impl Default for Eratosthenes where I: Hash + One + Zero + Add { fn default() -> Self { return Eratosthenes::{ sieve: HashMap::new(), @@ -27,17 +23,13 @@ where I: Hash + One + Zero + Add } } -impl Eratosthenes -where I: Hash + One + Zero + Add -{ +impl Eratosthenes where I: Hash + One + Zero + Add { pub fn new() -> Eratosthenes { return Default::default(); } } -impl Iterator for Eratosthenes -where I: Hash + One + Zero + Add + Mul + Ord + Copy -{ +impl Iterator for Eratosthenes where I: Hash + One + Zero + Add + Mul + Ord + Copy { type Item = I; fn next(&mut self) -> Option { @@ -68,25 +60,19 @@ where I: Hash + One + Zero + Add + Mul + Ord + Copy } } -pub fn primes() -> impl Iterator -where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static -{ - return CachingIterator::new(Eratosthenes::new()); +pub fn primes() -> impl Iterator where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static { + return cache_iterator(Eratosthenes::new()); } -pub fn primes_until(x: I) -> impl Iterator -where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static -{ +pub fn primes_until(x: I) -> impl Iterator where I: Hash + One + Zero + Add + Mul + Ord + Copy + 'static { return primes::().take_while(move |n| *n < x); } -pub struct PrimeFactors -{ +pub struct PrimeFactors { number: I } -impl PrimeFactors -{ +impl PrimeFactors { pub fn new(x: I) -> PrimeFactors { return PrimeFactors{ number: x @@ -113,8 +99,7 @@ where I: Hash + Zero + One + Add + Ord + Copy + Div + Rem + } } -pub fn prime_factors(x: I) -> PrimeFactors -{ +pub fn prime_factors(x: I) -> impl Iterator { return PrimeFactors::new(x); } diff --git a/rust/src/include/problems.rs b/rust/src/include/problems.rs index 6a82e398..090659c3 100644 --- a/rust/src/include/problems.rs +++ b/rust/src/include/problems.rs @@ -6,6 +6,10 @@ use crate::p~N::p~N; }); use crate::p0027::p0027; use crate::p0034::p0034; +use crate::p0036::p0036; +use crate::p0037::p0037; +use crate::p0045::p0045; +use crate::p0053::p0053; use crate::p0069::p0069; use crate::p0076::p0076; use crate::p0077::p0077; @@ -44,6 +48,10 @@ pub fn get_problem<'b>(n: usize) -> Option> { 24 => Some(( &24, p0024, false)), 27 => Some(( &27, p0027, true)), 34 => Some(( &34, p0034, false)), + 36 => Some(( &36, p0036, false)), + 37 => Some(( &37, p0037, false)), + 45 => Some(( &45, p0045, false)), + 53 => Some(( &53, p0053, false)), 69 => Some(( &69, p0069, false)), 76 => Some(( &76, p0076, false)), 77 => Some(( &77, p0077, false)), diff --git a/rust/src/include/utils.rs b/rust/src/include/utils.rs index 47eea31b..2291ab5f 100644 --- a/rust/src/include/utils.rs +++ b/rust/src/include/utils.rs @@ -1,3 +1,5 @@ +use std::string::ToString; + #[cfg(not(any(target_arch="wasm32", target_arch="wasm64")))] use std::fs::read_to_string; #[cfg(not(any(target_arch="wasm32", target_arch="wasm64")))] @@ -53,4 +55,9 @@ pub fn get_answer(n: usize) -> Answer { } } panic!("Answer not found"); -} \ No newline at end of file +} + +fn is_palindrome(x: I) -> bool where I: ToString { + let s = x.to_string(); + return s == s.chars().rev().collect::(); +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 24e1e1cb..982146db 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -11,6 +11,10 @@ pub mod p~N; }); pub mod p0027; pub mod p0034; +pub mod p0036; +pub mod p0037; +pub mod p0045; +pub mod p0053; pub mod p0069; pub mod p0076; pub mod p0077; diff --git a/rust/src/main.rs b/rust/src/main.rs index 033be8ba..8cf5a724 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -26,6 +26,10 @@ pub mod p~N; }); pub mod p0027; pub mod p0034; +pub mod p0036; +pub mod p0037; +pub mod p0045; +pub mod p0053; pub mod p0069; pub mod p0076; pub mod p0077; @@ -40,9 +44,9 @@ fn main() { for i in sieve { println!("{}", i); } -for i in 4..100 { -println!("{}: {:?}", i, factors::proper_divisors(i).collect::>()); -} + for i in 4..100 { + println!("{}: {:?}", i, factors::proper_divisors(i).collect::>()); + } let supported = generate_supported_problems(false); for id in supported { @@ -73,6 +77,10 @@ seq!(N in 01..=20 { #[case::problem_24(24)] #[case::problem_27(27)] #[case::problem_34(34)] +#[case::problem_36(36)] +#[case::problem_37(37)] +#[case::problem_45(45)] +#[case::problem_53(53)] #[case::problem_69(69)] #[case::problem_76(76)] #[case::problem_77(77)] @@ -100,7 +108,6 @@ fn test_problem(#[case] id: usize) -> Result<(), String> { } }); - #[cfg(test)] #[test] fn test_primes() -> Result<(), String> { @@ -128,3 +135,18 @@ fn test_prime_factors() -> Result<(), String> { } Ok(()) } + +#[cfg(test)] +#[test] +fn test_proper_divisors() -> Result<(), String> { + for i in 4..1024 { + let divisors = factors::proper_divisors(i).collect::>(); + for &factor in divisors.iter() { + if factor == 1 { + continue; + } + assert!(divisors.iter().any(|&x| x * factor == i)); + } + } + Ok(()) +} diff --git a/rust/src/p0002.rs b/rust/src/p0002.rs index 8bde9c0f..d8656873 100644 --- a/rust/src/p0002.rs +++ b/rust/src/p0002.rs @@ -14,17 +14,9 @@ terms. By starting with 1 and 2, the first 10 terms will be: By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms. */ +use crate::include::fibonacci::fib_by_3; use crate::include::utils::Answer; pub fn p0002() -> Answer { - let mut answer: u64 = 0; - let mut i = 2; - let mut j = 8; - while i < 4000000 { - answer += i; - let tmp = 4 * j + i; - i = j; - j = tmp; - } - return Answer::Int(answer.into()); + return Answer::Int(fib_by_3().take_while(|x| x < 4000000).sum::().into()); } diff --git a/rust/src/p0004.rs b/rust/src/p0004.rs index 685cee47..162146cc 100644 --- a/rust/src/p0004.rs +++ b/rust/src/p0004.rs @@ -14,12 +14,7 @@ Find the largest palindrome made from the product of two 3-digit numbers. */ use itertools::Itertools; -use crate::include::utils::Answer; - -fn is_palindrome(x: u32) -> bool { - let s = x.to_string(); - return s == s.chars().rev().collect::(); -} +use crate::include::utils::{is_palindrome,Answer}; pub fn p0004() -> Answer { let mut answer: u32 = 0; diff --git a/rust/src/p0036.rs b/rust/src/p0036.rs new file mode 100644 index 00000000..36e65ac1 --- /dev/null +++ b/rust/src/p0036.rs @@ -0,0 +1,26 @@ +/* +Project Euler Problem 36 + +Rust implementing a `reverse_bits()` function made this much more pleasant than expected + +Problem: + +The decimal number, 585 = 10010010012 (binary), is palindromic in both bases. + +Find the sum of all numbers, less than one million, which are palindromic in +base 10 and base 2. + +(Please note that the palindromic number, in either base, may not include +leading zeros.) +*/ +use crate::include::utils::{is_palindrome,Answer}; + +pub fn p0036() -> Answer { + let mut answer: u64 = 0; + for x in 1..1000000 { + if x == x.reverse_bits() && is_palindrome(x) { + answer += x; + } + } + return Answer::Int(answer.into()); +} diff --git a/rust/src/p0037.rs b/rust/src/p0037.rs new file mode 100644 index 00000000..d6b11d70 --- /dev/null +++ b/rust/src/p0037.rs @@ -0,0 +1,56 @@ +/* +Project Euler Problem 37 + +I was surprised how fast my brute-force solution went, but it worked + +Problem: + +The number 3797 has an interesting property. Being prime itself, it is possible +to continuously remove digits from left to right, and remain prime at each +stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, +379, 37, and 3. + +Find the sum of the only eleven primes that are both truncatable from left to +right and right to left. + +NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes. +*/ +use crate::include::primes::{is_prime,primes}; +use crate::include::utils::Answer; + +pub fn p0037() -> Answer { + let mut answer: u64 = 0; + let mut count: u64 = 0; + for p in primes() { + if count == 11 { + break; + } + else if p < 10 { + continue; + } + else { + let mut left; + let mut right; + right = left = p; + while is_prime(right) { + right = right / 10; + } + if right != 0 { + continue; + } + while is_prime(left) { + x = 10; + while x < left { + x *= 10; + } + left %= x / 10; + } + if left != 0 { + continue; + } + answer += p; + count += 1; + } + } + return Answer::Int(answer.into()); +} diff --git a/rust/src/p0045.rs b/rust/src/p0045.rs new file mode 100644 index 00000000..f26415dc --- /dev/null +++ b/rust/src/p0045.rs @@ -0,0 +1,50 @@ +/* +Project Euler Problem 45 + +Problem: + +Triangle, pentagonal, and hexagonal numbers are generated by the following formulae: +Triangle Tn=n(n+1)/2 1, 3, 6, 10, 15, ... +Pentagonal Pn=n(3n−1)/2 1, 5, 12, 22, 35, ... +Hexagonal Hn=n(2n−1) 1, 6, 15, 28, 45, ... + +It can be verified that T285 = P165 = H143 = 40755. +*/ +use crate::include::primes::{is_prime,primes}; +use crate::include::utils::Answer; + +fn T(n: u64) -> u64 { + return n * (n + 1) / 2; +} + +fn P(n: u64) -> u64 { + return n * (3 * n - 1) / 2; +} + +fn H(n: u64) -> u64 { + return n * (2 * n - 1); +} + +pub fn p0045() -> Answer { + let mut T_idx: u64 = 286; + let mut P_idx: u64 = 166; + let mut H_idx: u64 = 144; + let mut T_val = T(T_idx); + let mut P_val = P(P_idx); + let mut H_val = H(H_idx); + while !(T_val == P_val && P_val == H_val) { + while T_val < P_val || T_val < H_val { + T_idx += 1; + T_val = T(T_idx); + } + while P_val < T_val || P_val < H_val { + P_idx += 1; + P_val = P(P_idx); + } + while H_val < P_val || H_val < T_val { + H_idx += 1; + H_val = H(H_idx); + } + } + return Answer::Int(T_val.into()); +} diff --git a/rust/src/p0053.rs b/rust/src/p0053.rs new file mode 100644 index 00000000..15ba7017 --- /dev/null +++ b/rust/src/p0053.rs @@ -0,0 +1,26 @@ +/* +Project Euler Problem 45 + +Problem: + +Triangle, pentagonal, and hexagonal numbers are generated by the following formulae: +Triangle Tn=n(n+1)/2 1, 3, 6, 10, 15, ... +Pentagonal Pn=n(3n−1)/2 1, 5, 12, 22, 35, ... +Hexagonal Hn=n(2n−1) 1, 6, 15, 28, 45, ... + +It can be verified that T285 = P165 = H143 = 40755. +*/ +use crate::include::math::n_choose_r; +use crate::include::utils::Answer; + +pub fn p0053() -> Answer { + let mut answer: u64 = 0; + for n in 0..101 { + for r in 2..(n-1) { + if n_choose_r(n, r) > 1_000_000 { + answer += 1; + } + } + } + return Answer::Int(answer.into()); +}