diff --git a/src/bin/problem_10.rs b/src/bin/problem_10.rs new file mode 100644 index 0000000..5b700b4 --- /dev/null +++ b/src/bin/problem_10.rs @@ -0,0 +1,21 @@ +fn main() { + let mut primes = vec![]; + + for n in 2..=2_000_000 { + let prime_check_max = (n as f64).sqrt().ceil() as usize; + let mut is_prime = true; + for prime in primes.clone() { + if n % prime == 0 { + is_prime = false; + break; + } else if prime > prime_check_max { + break; + } + } + if is_prime { + primes.push(n); + } + } + + println!("{}", primes.iter().sum::()); +} \ No newline at end of file diff --git a/src/bin/problem_11.rs b/src/bin/problem_11.rs new file mode 100644 index 0000000..19deeff --- /dev/null +++ b/src/bin/problem_11.rs @@ -0,0 +1,83 @@ +fn main() { + let grid = get_grid(); + let greatests = [find_h(grid.clone()), find_v(grid.clone()), find_diag_lr(grid.clone()), find_diag_rl(grid)]; + println!("{}", greatests.iter().max().unwrap()); +} + +fn get_grid() -> Vec> { + vec![ + vec![08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08], + vec![49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00], + vec![81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65], + vec![52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91], + vec![22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80], + vec![24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50], + vec![32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70], + vec![67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21], + vec![24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72], + vec![21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95], + vec![78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92], + vec![16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57], + vec![86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58], + vec![19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40], + vec![04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66], + vec![88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69], + vec![04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36], + vec![20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16], + vec![20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54], + vec![01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48], + ] +} + +fn find_h(grid: Vec>) -> usize { + let mut greatest = 0; + for line in grid { + let greatest_in_line = line.windows(4).map(|nums| { nums.iter().product::() }).max().unwrap(); + if greatest_in_line > greatest { + greatest = greatest_in_line; + } + } + greatest +} + +fn find_v(grid: Vec>) -> usize { + let mut greatest = 0; + let side_len = grid.len(); + for line_quadruplets in grid.windows(4) { + for idx in 0..side_len { + let prod = line_quadruplets[0][idx] * line_quadruplets[1][idx] * line_quadruplets[2][idx] * line_quadruplets[3][idx]; + if prod > greatest { + greatest = prod; + } + } + } + greatest +} + +fn find_diag_lr(grid: Vec>) -> usize { + let mut greatest = 0; + let side_len = grid.len(); + for line_quadruplets in grid.windows(4) { + for idx in 0..side_len-3 { + let prod = line_quadruplets[0][idx] * line_quadruplets[1][idx+1] * line_quadruplets[2][idx+2] * line_quadruplets[3][idx+3]; + if prod > greatest { + greatest = prod; + } + } + } + greatest +} + +fn find_diag_rl(grid: Vec>) -> usize { + let mut greatest = 0; + let side_len = grid.len(); + for line_quadruplets in grid.windows(4) { + for idx in 3..side_len { + let prod = line_quadruplets[0][idx] * line_quadruplets[1][idx-1] * line_quadruplets[2][idx-2] * line_quadruplets[3][idx-3]; + if prod > greatest { + greatest = prod; + } + } + } + greatest +} diff --git a/src/bin/problem_12.rs b/src/bin/problem_12.rs new file mode 100644 index 0000000..2014ada --- /dev/null +++ b/src/bin/problem_12.rs @@ -0,0 +1,29 @@ +fn main() { + let mut n = 1; + loop { + let triangular_num = triangular(n); + let divisors = get_divisors(triangular_num); + if divisors.len() > 500 { + println!("{triangular_num}"); + break; + } + n +=1; + } +} + +fn triangular(nth: usize) -> usize { + (1..=nth).sum::() +} + +fn get_divisors(n: usize) -> Vec { + let mut divisors = vec![1]; + let mut potential_divisor = 2; + while (potential_divisor * potential_divisor) < n { + if n % potential_divisor == 0 { + divisors.push(potential_divisor); + divisors.push(n / potential_divisor); + } + potential_divisor = potential_divisor + 1; + } + divisors +} diff --git a/src/bin/problem_13.rs b/src/bin/problem_13.rs new file mode 100644 index 0000000..11bc891 --- /dev/null +++ b/src/bin/problem_13.rs @@ -0,0 +1,114 @@ +use project_euler::number::Number; + +fn main() { + let mut sum = Number::from(0); + for number in get_nums() { + sum = sum + number; + } + println!("{sum}"); +} + +fn get_nums() -> Vec { + vec![ + Number::from("37107287533902102798797998220837590246510135740250"), + Number::from("46376937677490009712648124896970078050417018260538"), + Number::from("74324986199524741059474233309513058123726617309629"), + Number::from("91942213363574161572522430563301811072406154908250"), + Number::from("23067588207539346171171980310421047513778063246676"), + Number::from("89261670696623633820136378418383684178734361726757"), + Number::from("28112879812849979408065481931592621691275889832738"), + Number::from("44274228917432520321923589422876796487670272189318"), + Number::from("47451445736001306439091167216856844588711603153276"), + Number::from("70386486105843025439939619828917593665686757934951"), + Number::from("62176457141856560629502157223196586755079324193331"), + Number::from("64906352462741904929101432445813822663347944758178"), + Number::from("92575867718337217661963751590579239728245598838407"), + Number::from("58203565325359399008402633568948830189458628227828"), + Number::from("80181199384826282014278194139940567587151170094390"), + Number::from("35398664372827112653829987240784473053190104293586"), + Number::from("86515506006295864861532075273371959191420517255829"), + Number::from("71693888707715466499115593487603532921714970056938"), + Number::from("54370070576826684624621495650076471787294438377604"), + Number::from("53282654108756828443191190634694037855217779295145"), + Number::from("36123272525000296071075082563815656710885258350721"), + Number::from("45876576172410976447339110607218265236877223636045"), + Number::from("17423706905851860660448207621209813287860733969412"), + Number::from("81142660418086830619328460811191061556940512689692"), + Number::from("51934325451728388641918047049293215058642563049483"), + Number::from("62467221648435076201727918039944693004732956340691"), + Number::from("15732444386908125794514089057706229429197107928209"), + Number::from("55037687525678773091862540744969844508330393682126"), + Number::from("18336384825330154686196124348767681297534375946515"), + Number::from("80386287592878490201521685554828717201219257766954"), + Number::from("78182833757993103614740356856449095527097864797581"), + Number::from("16726320100436897842553539920931837441497806860984"), + Number::from("48403098129077791799088218795327364475675590848030"), + Number::from("87086987551392711854517078544161852424320693150332"), + Number::from("59959406895756536782107074926966537676326235447210"), + Number::from("69793950679652694742597709739166693763042633987085"), + Number::from("41052684708299085211399427365734116182760315001271"), + Number::from("65378607361501080857009149939512557028198746004375"), + Number::from("35829035317434717326932123578154982629742552737307"), + Number::from("94953759765105305946966067683156574377167401875275"), + Number::from("88902802571733229619176668713819931811048770190271"), + Number::from("25267680276078003013678680992525463401061632866526"), + Number::from("36270218540497705585629946580636237993140746255962"), + Number::from("24074486908231174977792365466257246923322810917141"), + Number::from("91430288197103288597806669760892938638285025333403"), + Number::from("34413065578016127815921815005561868836468420090470"), + Number::from("23053081172816430487623791969842487255036638784583"), + Number::from("11487696932154902810424020138335124462181441773470"), + Number::from("63783299490636259666498587618221225225512486764533"), + Number::from("67720186971698544312419572409913959008952310058822"), + Number::from("95548255300263520781532296796249481641953868218774"), + Number::from("76085327132285723110424803456124867697064507995236"), + Number::from("37774242535411291684276865538926205024910326572967"), + Number::from("23701913275725675285653248258265463092207058596522"), + Number::from("29798860272258331913126375147341994889534765745501"), + Number::from("18495701454879288984856827726077713721403798879715"), + Number::from("38298203783031473527721580348144513491373226651381"), + Number::from("34829543829199918180278916522431027392251122869539"), + Number::from("40957953066405232632538044100059654939159879593635"), + Number::from("29746152185502371307642255121183693803580388584903"), + Number::from("41698116222072977186158236678424689157993532961922"), + Number::from("62467957194401269043877107275048102390895523597457"), + Number::from("23189706772547915061505504953922979530901129967519"), + Number::from("86188088225875314529584099251203829009407770775672"), + Number::from("11306739708304724483816533873502340845647058077308"), + Number::from("82959174767140363198008187129011875491310547126581"), + Number::from("97623331044818386269515456334926366572897563400500"), + Number::from("42846280183517070527831839425882145521227251250327"), + Number::from("55121603546981200581762165212827652751691296897789"), + Number::from("32238195734329339946437501907836945765883352399886"), + Number::from("75506164965184775180738168837861091527357929701337"), + Number::from("62177842752192623401942399639168044983993173312731"), + Number::from("32924185707147349566916674687634660915035914677504"), + Number::from("99518671430235219628894890102423325116913619626622"), + Number::from("73267460800591547471830798392868535206946944540724"), + Number::from("76841822524674417161514036427982273348055556214818"), + Number::from("97142617910342598647204516893989422179826088076852"), + Number::from("87783646182799346313767754307809363333018982642090"), + Number::from("10848802521674670883215120185883543223812876952786"), + Number::from("71329612474782464538636993009049310363619763878039"), + Number::from("62184073572399794223406235393808339651327408011116"), + Number::from("66627891981488087797941876876144230030984490851411"), + Number::from("60661826293682836764744779239180335110989069790714"), + Number::from("85786944089552990653640447425576083659976645795096"), + Number::from("66024396409905389607120198219976047599490197230297"), + Number::from("64913982680032973156037120041377903785566085089252"), + Number::from("16730939319872750275468906903707539413042652315011"), + Number::from("94809377245048795150954100921645863754710598436791"), + Number::from("78639167021187492431995700641917969777599028300699"), + Number::from("15368713711936614952811305876380278410754449733078"), + Number::from("40789923115535562561142322423255033685442488917353"), + Number::from("44889911501440648020369068063960672322193204149535"), + Number::from("41503128880339536053299340368006977710650566631954"), + Number::from("81234880673210146739058568557934581403627822703280"), + Number::from("82616570773948327592232845941706525094512325230608"), + Number::from("22918802058777319719839450180888072429661980811197"), + Number::from("77158542502016545090413245809786882778948721859617"), + Number::from("72107838435069186155435662884062257473692284509516"), + Number::from("20849603980134001723930671666823555245252804609722"), + Number::from("53503534226472524250874054075591789781264330331690"), + ] +} \ No newline at end of file diff --git a/src/bin/problem_14.rs b/src/bin/problem_14.rs new file mode 100644 index 0000000..b354d57 --- /dev/null +++ b/src/bin/problem_14.rs @@ -0,0 +1,35 @@ +fn main() { + let longest = find_longest(1_000_000); + println!("{longest}"); +} + +fn collatz_seq(start: usize) -> Vec { + let mut sequence = vec![start]; + let mut curr = start; + loop { + if curr == 1 { + break; + } + if curr % 2 == 0{ + curr /= 2; + } else { + curr = 3 * curr + 1; + } + sequence.push(curr); + } + sequence +} + +fn find_longest(max_start: usize) -> usize { + let mut biggest = (0, 0); + + for i in 1..max_start { + let seq = collatz_seq(i); + if seq.len() > biggest.1 { + biggest = (i, seq.len()); + } + } + + biggest.0 +} + diff --git a/src/bin/problem_15.rs b/src/bin/problem_15.rs new file mode 100644 index 0000000..0198420 --- /dev/null +++ b/src/bin/problem_15.rs @@ -0,0 +1,10 @@ +use project_euler::number::Number; + +fn main() { + let width = Number::from(20); + let height = Number::from(20); + let a = (width.clone()+height.clone()).fact(); + let b = width.clone().fact()*height.clone().fact(); + let euler_15 = a/b; + println!("({width}+{height})!/{width}!*{height}!={euler_15}"); +} \ No newline at end of file diff --git a/src/bin/problem_16.rs b/src/bin/problem_16.rs new file mode 100644 index 0000000..e2e9ba1 --- /dev/null +++ b/src/bin/problem_16.rs @@ -0,0 +1,18 @@ +use project_euler::number::Number; + +fn main() { + let power = get_power(1000); + println!("{}", power.digits.iter().sum::()) +} + +fn get_power(exp: usize) -> Number { + let mut number = Number::from(1); + if exp == 0 { + return number; + } + for _n in 1..=exp { + number = number * 2; + } + number +} + diff --git a/src/bin/problem_17.rs b/src/bin/problem_17.rs new file mode 100644 index 0000000..f8a3747 --- /dev/null +++ b/src/bin/problem_17.rs @@ -0,0 +1,114 @@ +use project_euler::number::Number; + +fn main() { + let mut num_letters = 0; + for n in 1..=1000 { + num_letters += number_to_words(Number::from(n)).len(); + } + println!("{num_letters}"); +} + + +fn number_to_words(n: Number) -> String { + let mut number_string = String::new(); + let digits = n.clone().digits; + for (pos, &digit) in digits.iter().enumerate() { + if digits.len() > 1 && digits.len() - 2 == pos { + if digit == 1 { + if digits[digits.len()-1] == 0 { + number_string.push_str("ten"); + } + if digits[digits.len()-1] == 1 { + number_string.push_str("eleven"); + } + if digits[digits.len()-1] == 2 { + number_string.push_str("twelve"); + } + if digits[digits.len()-1] == 3 { + number_string.push_str("thirteen"); + } + if digits[digits.len()-1] == 4 { + number_string.push_str("fourteen"); + } + if digits[digits.len()-1] == 5 { + number_string.push_str("fifteen"); + } + if digits[digits.len()-1] == 6 { + number_string.push_str("sixteen"); + } + if digits[digits.len()-1] == 7 { + number_string.push_str("seventeen"); + } + if digits[digits.len()-1] == 8 { + number_string.push_str("eighteen"); + } + if digits[digits.len()-1] == 9 { + number_string.push_str("nineteen"); + } + } + if digit == 2 { + number_string.push_str("twenty"); + } + if digit == 3 { + number_string.push_str("thirty"); + } + if digit == 4 { + number_string.push_str("forty"); + } + if digit == 5 { + number_string.push_str("fifty"); + } + if digit == 6 { + number_string.push_str("sixty"); + } + if digit == 7 { + number_string.push_str("seventy"); + } + if digit == 8 { + number_string.push_str("eighty"); + } + if digit == 9 { + number_string.push_str("ninety"); + } + } else if digits.len() == 1 || (digits.len() - 2 != pos && !(digits.len() - 1 == pos && digits[digits.len() - 2] == 1)) { + if digit == 1 { + number_string.push_str("one"); + } + if digit == 2 { + number_string.push_str("two"); + } + if digit == 3 { + number_string.push_str("three"); + } + if digit == 4 { + number_string.push_str("four"); + } + if digit == 5 { + number_string.push_str("five"); + } + if digit == 6 { + number_string.push_str("six"); + } + if digit == 7 { + number_string.push_str("seven"); + } + if digit == 8 { + number_string.push_str("eight"); + } + if digit == 9 { + number_string.push_str("nine"); + } + } + if digits.len() > 2 && pos == digits.len() - 3 && digit != 0 { + number_string.push_str("hundred"); + if !(digits[pos + 1] == 0 && digits[pos + 2] == 0) { + number_string.push_str("and"); + } + } + if digits.len() > 3 && pos == digits.len() - 4 && digit != 0 { + number_string.push_str("thousand"); + } + } + println!("{n}: {number_string}"); + number_string +} \ No newline at end of file diff --git a/src/bin/problem_20.rs b/src/bin/problem_20.rs new file mode 100644 index 0000000..c4a2bb1 --- /dev/null +++ b/src/bin/problem_20.rs @@ -0,0 +1,17 @@ +use project_euler::number::Number; + +fn main() { + let factorial = get_factorial(100); + dbg!(factorial.digits.iter().sum::()); +} + +fn get_factorial(factorial: isize) -> Number { + let mut number = Number::from(1); + if factorial == 0 { + return number; + } + for n in 1..=factorial { + number = number * n; + } + number +} \ No newline at end of file diff --git a/src/bin/problem_21.rs b/src/bin/problem_21.rs new file mode 100644 index 0000000..782015c --- /dev/null +++ b/src/bin/problem_21.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; +use std::time::Instant; + +fn main() { + let now = Instant::now(); + let mut amicable_cache: HashMap = HashMap::new(); + let mut despicable_cache: HashMap = HashMap::new(); + let mut sum_amicable = 0; + for i in 2..=10 { + if amicable_cache.get(&i).is_some() { + continue; + } + if despicable_cache.get(&i).is_some() { + continue; + } + let divisors = get_divisors(i); + let sum_divisors = divisors.iter().sum(); + let other_divisors = get_divisors(sum_divisors); + let other_sum_divisors = other_divisors.iter().sum(); + if sum_divisors == other_sum_divisors { + println!("{:?}", divisors); + amicable_cache.insert(other_sum_divisors, sum_divisors); + sum_amicable += sum_divisors + other_sum_divisors; + } else { + println!("{:?}", divisors); + despicable_cache.insert(other_sum_divisors, sum_divisors); + } + } + println!("{:?}", amicable_cache); + println!("{sum_amicable}"); + println!("Time={} µs", now.elapsed().as_micros()); +} + +fn get_divisors(n: isize) -> Vec { + let mut divisors = vec![1]; + let mut potential_divisor = 2; + while (potential_divisor * potential_divisor) < n { + if n % potential_divisor == 0 { + divisors.push(potential_divisor); + divisors.push(n / potential_divisor); + } + potential_divisor = potential_divisor + 1; + } + divisors +} \ No newline at end of file diff --git a/src/bin/problem_25.rs b/src/bin/problem_25.rs new file mode 100644 index 0000000..5d37b40 --- /dev/null +++ b/src/bin/problem_25.rs @@ -0,0 +1,68 @@ +use project_euler::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 = HashMap::new(); +// fn inner_fib_recursion_cached(n: Number, cache: &mut HashMap) -> 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_len = fib.digits.len(); + if fib_len == num_digits { + return n; + } + n += 1; + } +} \ No newline at end of file diff --git a/src/bin/problem_29.rs b/src/bin/problem_29.rs new file mode 100644 index 0000000..a754528 --- /dev/null +++ b/src/bin/problem_29.rs @@ -0,0 +1,14 @@ +use std::collections::HashSet; +use project_euler::number::Number; + +fn main() { + let mut terms: HashSet = HashSet::new(); + let max = 100; + for a in 2..=max { + for b in 2..=max { + let a_num = Number::from(a); + terms.insert(a_num.pow(b as u32)); + } + } + println!("{}", terms.len()); +} \ No newline at end of file diff --git a/src/bin/problem_30.rs b/src/bin/problem_30.rs new file mode 100644 index 0000000..b129802 --- /dev/null +++ b/src/bin/problem_30.rs @@ -0,0 +1,28 @@ +use project_euler::number::Number; + +fn main() { + println!("{}", nth_powers(5)) +} + +fn nth_powers(nth: u32) -> isize { + let mut powers = vec![]; + let mut max = 9isize.pow(nth); + let mut idx = 1; + loop { + let attempt = max * idx; + if Number::from(attempt).digits.len() < idx as usize { + max = (idx - 1) * max; + break; + } + idx += 1; + } + for n in 2..=max { + let num = Number::from(n); + let digits = num.digits; + let sum = digits.iter().map(|&x| x.pow(nth)).sum(); + if n == sum { + powers.push(n); + } + } + powers.iter().sum() +} \ No newline at end of file diff --git a/src/bin/problem_34.rs b/src/bin/problem_34.rs new file mode 100644 index 0000000..d37154c --- /dev/null +++ b/src/bin/problem_34.rs @@ -0,0 +1,35 @@ +use project_euler::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 idx = 1; + loop { + let attempt = max * idx; + if Number::from(attempt).digits.len() < idx as usize { + max = (idx - 1) * max; + break; + } + idx += 1; + } + for n in 3..=max { + let digits_fact_sum = Number::from(n).digits.iter().map(|&digit| factorial(digit)).sum(); + if n == digits_fact_sum { + factorials.push(n); + } + } + factorials.iter().sum() +} \ No newline at end of file diff --git a/src/bin/problem_48.rs b/src/bin/problem_48.rs new file mode 100644 index 0000000..fcfdd52 --- /dev/null +++ b/src/bin/problem_48.rs @@ -0,0 +1,13 @@ +use project_euler::number::Number; + +fn main() { + println!("{}", power_series(1000)); +} + +fn power_series(length: usize) -> Number { + let mut number = Number::from(0); + for i in 1..=length { + number = number + Number::from(i as isize).pow(i as u32); + } + number +} diff --git a/src/bin/problem_9.rs b/src/bin/problem_9.rs new file mode 100644 index 0000000..ab52e17 --- /dev/null +++ b/src/bin/problem_9.rs @@ -0,0 +1,16 @@ +fn main() { + for a in 0..=1000 { + for b in a..=(1000 - a) { + let c = 1000 - (a + b); + if b == c { continue; } + if is_triplet(a, b, c) { + println!("a + b + c = {a} + {b} + {c} = {}", a + b + c); + println!("abc = {}", a * b * c); + } + } + } +} + +fn is_triplet(a: usize, b: usize, c: usize) -> bool { + return a * a + b * b == c * c +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ed0108d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,392 @@ +pub mod number { + use std::cmp::{min, Ordering}; + use std::fmt::{Display, Formatter}; + use std::iter::zip; + use std::ops::{Add, Mul, Div, Sub, Rem}; + + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub enum Sign { + Positif, + Negatif, + } + + #[derive(Clone, Debug, Eq, PartialEq, Hash)] + pub struct Number { + pub digits: Vec, + 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 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 for String { + fn from(value: Number) -> Self { + let string_vec: Vec = 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 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().map(|&digit| digit).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::>().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 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 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); + } + } + +} \ No newline at end of file