feat(cli): run command with benchmarking

This commit is contained in:
newt 2024-10-09 18:10:12 +01:00
parent 5accea1fb2
commit 525ba998df
30 changed files with 830 additions and 240 deletions

View file

@ -9,5 +9,9 @@
"**/target": true,
"**/Cargo.lock": true,
"**/euler.png": true
},
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true
}
}

194
Cargo.lock generated
View file

@ -129,6 +129,49 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossterm"
version = "0.23.2"
@ -215,6 +258,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591"
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "encoding_rs"
version = "0.8.31"
@ -226,13 +275,13 @@ dependencies = [
[[package]]
name = "errno"
version = "0.2.8"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
@ -254,6 +303,7 @@ dependencies = [
"num-bigint",
"owo-colors",
"phf 0.11.1",
"rayon",
"regex",
"requestty",
"reqwest",
@ -432,6 +482,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "html-escape"
version = "0.2.13"
@ -557,12 +613,13 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.3"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.1",
"libc",
"windows-sys 0.42.0",
"windows-sys 0.48.0",
]
[[package]]
@ -573,14 +630,14 @@ checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "is-terminal"
version = "0.4.2"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi",
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.42.0",
"windows-sys 0.48.0",
]
[[package]]
@ -612,15 +669,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.139"
version = "0.2.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "lock_api"
@ -673,6 +730,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -757,7 +823,7 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"hermit-abi 0.2.6",
"libc",
]
@ -1146,6 +1212,28 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@ -1253,16 +1341,16 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.36.5"
version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.42.0",
"windows-sys 0.48.0",
]
[[package]]
@ -1886,21 +1974,51 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_gnullvm 0.42.0",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm",
"windows_x86_64_gnullvm 0.42.0",
"windows_x86_64_msvc 0.42.0",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
@ -1913,6 +2031,12 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
@ -1925,6 +2049,12 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
@ -1937,6 +2067,12 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
@ -1949,12 +2085,24 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
@ -1967,6 +2115,12 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winreg"
version = "0.10.1"

View file

@ -6,15 +6,16 @@ default-run = "euler"
[dependencies]
clap = { version = "4.0.4", features = ["derive"] }
owo-colors = "3.5.0"
scraper = "0.14.0"
requestty = "0.4.1"
reqwest = "0.11"
tokio = { version = "1.23", features = ["full"] }
regex = "1"
html-escape = "0.2.13"
num-bigint = "0.4.3"
phf = { version = "0.11.1", features = ["macros"] }
rayon = "1.7.0"
owo-colors = "3.5.0"
num-bigint = "0.4.3"
[profile.release]
opt-level = "z"

View file

@ -7,11 +7,16 @@
All of the solutions here are written in rust. [main.rs](src/main.rs) is the home to my helper command line that can scaffold files for me quickly, prefaced with a statement of the problem! As per the rules of the challenge, I may only publish the solutions to the first 100 problems here, so I will stop after that but still continue the challenge.
I originally started the challenge in [the-honk](https://github.com/newtykins/the-honk) in TypeScript, and am currently in the process of porting over all of my already completed challenges. Check out my old work [here](https://github.com/newtykins/the-honk/tree/main/challenges/euler).
### Allowed Dependencies
- [rayon](https://lib.rs/rayon) for concurrency
- [phf](https://lib.rs/phf) for compile-time static maps
- [regex](https://lib.rs/regex) for regex (duh)
- [num_bigint](https://lib.rs/num_bigint) for bigints
## Challenge Completion
### <!-- completed -->22<!-- completed --> out of 100 public challenges completed.
### <!-- completed -->21<!-- completed --> out of 100 public challenges completed.
- [x] 1 - [Multiples of 3 or 5](src/bin/1.rs)
- [x] 2 - [Even Fibonacci numbers](src/bin/2.rs)
@ -114,4 +119,4 @@ I originally started the challenge in [the-honk](https://github.com/newtykins/th
- [ ] 99 - Largest exponential
- [ ] 100 - Arranged probability
<sub>Check out Project Euler <a href="https://projecteuler.net">here</a>.</sub>
<sub>Check out Project Euler <a href="https://projecteuler.net">here</a>.</sub>

View file

@ -5,6 +5,7 @@ If we list all the natural numbers below 10 that are multiples of 3 or 5, we get
Find the sum of all the multiples of 3 or 5 below 1000.
*/
use rayon::prelude::*;
use std::collections::HashSet;
fn multiples_of(multipliers: &Vec<usize>, upper_bound: usize) -> HashSet<usize> {
@ -23,9 +24,9 @@ fn multiples_of(multipliers: &Vec<usize>, upper_bound: usize) -> HashSet<usize>
return results;
}
fn main() {
pub fn main() {
let multiples = multiples_of(&vec![3, 5], 1000);
let sum: usize = multiples.iter().sum();
let sum: usize = multiples.par_iter().sum();
println!("The sum of the multiples of 3 and 5 up until 1000 is {sum}");
}

View file

@ -7,6 +7,9 @@ Find the sum of all the primes below two million.
// Implementation of the Sieve of Eratosthenes
// https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
use rayon::prelude::*;
fn find_primes(upper_bound: usize) -> Vec<usize> {
let mut mask = vec![true; upper_bound];
let mut primes: Vec<usize> = vec![];
@ -32,10 +35,10 @@ fn find_primes(upper_bound: usize) -> Vec<usize> {
fn sum_of_primes(upper_bound: usize) -> usize {
let primes = find_primes(upper_bound);
return primes.iter().sum::<usize>();
return primes.par_iter().sum::<usize>();
}
fn main() {
pub fn main() {
let value = sum_of_primes(2000000);
println!("The sum of the primes up until 2000000 is {value}");

View file

@ -26,6 +26,8 @@ The product of these numbers is 26 × 63 × 78 × 14 = 1788696.
What is the greatest product of four adjacent numbers in the same direction (up, down, left, right, or diagonally) in the 20×20 grid?
*/
use rayon::prelude::*;
fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize {
let mut products: Vec<usize> = vec![];
@ -37,7 +39,7 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
// Horizontal product
if horizontal {
let selection = &row[j..(j + adjacent_digits)];
products.push(selection.iter().product());
products.push(selection.par_iter().product());
}
// Vertical product
@ -48,7 +50,7 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
selection.push(grid[i + k][j]);
}
products.push(selection.iter().product());
products.push(selection.par_iter().product());
}
// Forward diagonal product
@ -59,7 +61,7 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
selection.push(grid[i + k][j + k]);
}
products.push(selection.iter().product());
products.push(selection.par_iter().product());
}
// Reverse diagonal product
@ -70,15 +72,15 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
selection.push(grid[i + k][j - k]);
}
products.push(selection.iter().product());
products.push(selection.par_iter().product());
}
}
}
return *products.iter().max().unwrap();
return *products.par_iter().max().unwrap();
}
fn main() {
pub fn main() {
let grid: Vec<Vec<usize>> = vec![
vec![
8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8,

View file

@ -40,7 +40,7 @@ fn first_triangle_with_n_divisors(n: usize) -> usize {
}
}
fn main() {
pub fn main() {
let value = first_triangle_with_n_divisors(500);
println!("The first triangle number with over 500 divisors is {value}");

View file

@ -104,6 +104,8 @@ Work out the first ten digits of the sum of the following one-hundred 50-digit n
53503534226472524250874054075591789781264330331690
*/
use rayon::prelude::*;
const NUMBERS: [f64; 100] = [
37107287533902102798797998220837590246510135740250.0,
46376937677490009712648124896970078050417018260538.0,
@ -221,8 +223,8 @@ fn first_n_digits(number: f64, n: usize) -> Option<usize> {
return Some(new_number);
}
fn main() {
let digits = first_n_digits(NUMBERS.iter().sum(), 10).unwrap();
pub fn main() {
let digits = first_n_digits(NUMBERS.par_iter().sum(), 10).unwrap();
println!("The first 10 digits of the sum: {digits}");
}

View file

@ -10,6 +10,7 @@ Which starting number, under one million, produces the longest chain?
NOTE: Once the chain starts the terms are allowed to go above one million.
*/
use rayon::prelude::*;
use std::collections::HashMap;
fn f(n: usize) -> usize {
@ -42,10 +43,10 @@ fn longest_collatz_sequence(greatest_start: usize) -> usize {
sequence_lengths.insert(i, sequence_length);
}
return *sequence_lengths.iter().max_by_key(|x| x.1).unwrap().0;
return *sequence_lengths.par_iter().max_by_key(|x| x.1).unwrap().0;
}
fn main() {
pub fn main() {
let starting_number = longest_collatz_sequence(1_000_000);
println!(

View file

@ -35,7 +35,7 @@ fn count_lattice_paths(width: usize, height: usize) -> usize {
}
}
fn main() {
pub fn main() {
let routes = count_lattice_paths(20, 20);
println!("The amount of routes through a 20x20 grid is {routes}");

View file

@ -32,7 +32,7 @@ fn power_digit_sum(base: usize, power: u32) -> usize {
sum
}
fn main() {
pub fn main() {
let sum = power_digit_sum(2, 1000);
println!("The sum of the digits of the number 2^1000 is {}!", sum);

View file

@ -103,7 +103,7 @@ fn letter_count(upper_bound: usize) -> usize {
sum
}
fn main() {
pub fn main() {
let sum = letter_count(1000);
println!(

View file

@ -37,7 +37,7 @@ fn maximum_path_sum(triangle: Vec<Vec<usize>>) -> usize {
return tri[0][0];
}
fn main() {
pub fn main() {
let triangle: Vec<Vec<usize>> = vec![
vec![75],
vec![95, 64],
@ -55,7 +55,7 @@ fn main() {
vec![63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31],
vec![4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23],
];
let sum = maximum_path_sum(triangle);
println!("The maximum path sum of the triangle is {}!", sum);

View file

@ -6,6 +6,8 @@ Each new term in the Fibonacci sequence is generated by adding the previous two
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
*/
use rayon::prelude::*;
fn fibonacci(upper_bound: usize) -> Vec<usize> {
// F_0 = 1, F_1 = 2
let mut sequence = vec![1, 2];
@ -19,9 +21,9 @@ fn fibonacci(upper_bound: usize) -> Vec<usize> {
return sequence;
}
fn main() {
pub fn main() {
let sequence = fibonacci(4000000);
let even = sequence.iter().filter(|n| *n % 2 == 0);
let even = sequence.par_iter().filter(|n| *n % 2 == 0);
let sum: usize = even.sum();
print!(

View file

@ -41,7 +41,7 @@ fn name_score_total(names: Vec<String>) -> usize {
return total;
}
fn main() {
pub fn main() {
let names = read_names();
let total = name_score_total(names);

View file

@ -29,7 +29,7 @@ fn largest_prime_factor(number: usize) -> usize {
return primes[primes.len() - 1];
}
fn main() {
pub fn main() {
let factor = largest_prime_factor(600851475143);
println!("The largest prime factor of 600851475143 is {factor}");
}

View file

@ -5,6 +5,8 @@ A palindromic number reads the same both ways. The largest palindrome made from
Find the largest palindrome made from the product of two 3-digit numbers.
*/
use rayon::prelude::*;
fn largest_pallindromic_number(lower_bound: usize, upper_bound: usize) -> usize {
let mut products: Vec<usize> = vec![];
@ -16,7 +18,7 @@ fn largest_pallindromic_number(lower_bound: usize, upper_bound: usize) -> usize
// Filter for pallindromic numbers
let mut pallindromic = products
.iter()
.par_iter()
.filter(|x| x.to_string() == x.to_string().chars().rev().collect::<String>())
.collect::<Vec<&usize>>();
@ -27,7 +29,7 @@ fn largest_pallindromic_number(lower_bound: usize, upper_bound: usize) -> usize
return *pallindromic[0];
}
fn main() {
pub fn main() {
let number = largest_pallindromic_number(100, 999);
println!("The largest pallindromic number made from the product of two three-digit numbers is {number}");

View file

@ -49,7 +49,7 @@ fn count_triangle_words(words: Vec<String>) -> usize {
return count;
}
fn main() {
pub fn main() {
let words = read_words();
let count = count_triangle_words(words);

View file

@ -45,7 +45,7 @@ fn first_value_divisible_by(start: usize, end: usize) -> Option<usize> {
return Some(result);
}
fn main() {
pub fn main() {
let number = first_value_divisible_by(1, 20).unwrap();
println!("The smallest number that is divisible by all integers between 1 and 20 is {number}");

View file

@ -9,6 +9,8 @@ Hence the difference between the sum of the squares of the first ten natural num
Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
*/
use rayon::prelude::*;
const LOWER_BOUND: usize = 1;
const UPPER_BOUND: usize = 100;
@ -23,7 +25,7 @@ fn sum_of_squares(lower_bound: usize, upper_bound: usize) -> Option<usize> {
squares.push(i.pow(2));
}
return Some(squares.iter().sum());
return Some(squares.par_iter().sum());
}
fn square_of_sum(lower_bound: usize, upper_bound: usize) -> Option<usize> {
@ -34,7 +36,7 @@ fn square_of_sum(lower_bound: usize, upper_bound: usize) -> Option<usize> {
return Some(((lower_bound..(upper_bound + 1)).sum::<usize>()).pow(2));
}
fn main() {
pub fn main() {
let squared_sum = square_of_sum(LOWER_BOUND, UPPER_BOUND).unwrap();
let summed_squares = sum_of_squares(LOWER_BOUND, UPPER_BOUND).unwrap();
let difference = squared_sum - summed_squares;

View file

@ -35,7 +35,7 @@ fn maximum_path_sum(triangle: Vec<Vec<usize>>) -> usize {
return tri[0][0];
}
fn main() {
pub fn main() {
let triangle = read_triangle();
let sum = maximum_path_sum(triangle);
println!("The maximum path sum of the triangle is {}!", sum);

View file

@ -54,7 +54,7 @@ fn nth_prime(n: usize) -> Option<usize> {
return Some(primes[n - 1]);
}
fn main() {
pub fn main() {
let number = nth_prime(10001).unwrap();
println!("The 10,001st prime number is {number}");

View file

@ -71,7 +71,7 @@ fn largest_product(number: &str, adjacent_digits: usize) -> Option<usize> {
return Some(products[0]);
}
fn main() {
pub fn main() {
let value = largest_product(NUMBER, ADJACENT_DIGITS).unwrap();
println!("The thirteen adjacent digits in the number that have the greatest product have a product of {value}");

View file

@ -34,7 +34,7 @@ fn triplet_with_sum(sum: isize) -> Option<(isize, isize, isize)> {
return None;
}
fn main() {
pub fn main() {
let (a, b, c) = triplet_with_sum(1000).unwrap();
println!("a = {a}, b = {b}, c = {c} // abc = {}", a * b * c);

2
src/commands/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod new;
pub mod run;

183
src/commands/new.rs Normal file
View file

@ -0,0 +1,183 @@
use owo_colors::OwoColorize;
use regex::Regex;
use scraper::{Html, Selector};
use std::io::BufReader;
use std::{
fs::{File, OpenOptions},
io::{BufRead, Write},
};
#[tokio::main]
pub async fn execute(problem: Option<u8>) -> Result<(), Box<dyn std::error::Error>> {
let code_path = euler::code_path();
let problem_number = euler::problem_number(
problem,
&code_path,
"Which problem would you like to solve?",
);
// Fetch the problem information
let body = reqwest::get(format!("https://projecteuler.net/problem={problem_number}"))
.await?
.text()
.await?;
let document = Html::parse_document(body.as_str());
let title_selector = Selector::parse("h2")?;
let content_selector = Selector::parse(".problem_content")?;
let html_tag_regex = Regex::new(r"<[^>]*>")?;
let mut title = document
.select(&title_selector)
.next()
.unwrap()
.text()
.collect::<Vec<&str>>()
.join("");
let mut problem = html_tag_regex
.replace_all(
document
.select(&content_selector)
.next()
.unwrap()
.inner_html()
.as_str(),
" ",
)
.to_string()
.replace("$$", " ");
let file_body = format!(
"/*
Problem {} - {}
{}
*/
pub fn main() {{
println!(\"Hello World!\");
}}",
problem_number,
html_escape::decode_html_entities(&mut title).to_string(),
html_escape::decode_html_entities(&mut problem)
.split("\n")
.map(|s| s.trim())
.filter(|s| s != &"")
.collect::<Vec<&str>>()
.join("\n")
);
// Create the file
let mut file = File::create(code_path.join(format!("{problem_number}.rs")))?;
file.write(file_body.as_bytes())?;
drop(file);
// Read the contents of the readme for editing
let readme_path = euler::readme_path();
let mut readme_file = OpenOptions::new().read(true).open(&readme_path)?;
let mut readme_content = BufReader::new(&readme_file)
.lines()
.map(|s| s.unwrap())
.collect::<Vec<String>>();
drop(readme_file);
// Mark the problem as done on the readme
let readme_regex = Regex::new(format!(" {problem_number} - (.*)").as_str())?;
for i in 0..readme_content.len() {
let line = readme_content[i].as_str();
if readme_regex.is_match(line) {
let matched = readme_regex.captures(line).unwrap();
readme_content[i] = format!(
"- [x] {problem_number} - [{}](src/bin/{problem_number}.rs)",
&matched[1].trim()
);
}
}
// Update the summary statistics on the readme
let mut readme_string = readme_content.join("\n");
let completed_regex = Regex::new("<!-- completed -->([0-9]+)<!-- completed -->")?;
let new_completed =
completed_regex.captures(readme_string.as_str()).unwrap()[1].parse::<u8>()? + 1;
readme_string = completed_regex
.replace(
readme_string.as_str(),
format!("<!-- completed -->{new_completed}<!-- completed -->"),
)
.to_string();
// Write the new content to the readme
readme_file = OpenOptions::new().write(true).open(&readme_path)?;
readme_file.write(readme_string.as_bytes())?;
drop(readme_file);
// Modify the run command
let run_path = euler::run_path();
let mut run_file = OpenOptions::new().read(true).open(&run_path)?;
let mut run_content = BufReader::new(&run_file)
.lines()
.map(|s| s.unwrap())
.collect::<Vec<String>>();
drop(run_file);
// Import the problem's file
let import_regex = Regex::new(r#"// #\[path = "\.\./bin/{x}\.rs"]"#.replace("{x}", problem_number.to_string().as_str()).as_str())?;
for i in 0..run_content.len() {
let line = run_content[i].as_str();
if import_regex.is_match(line) {
run_content[i] = line.replace("// ", "");
run_content[i + 1] = run_content[i + 1].replace("// ", "");
break;
}
}
// Add the problem to the match statement
let match_regex = Regex::new(
r"// {x} =>"
.replace("{x}", problem_number.to_string().as_str())
.as_str(),
)?;
for i in 0..run_content.len() {
let line = run_content[i].as_str();
if match_regex.is_match(line) {
run_content[i] = line.replace("// ", "");
break;
}
}
// Write the new content to the run file
run_file = OpenOptions::new()
.write(true)
.truncate(true)
.open(&run_path)?;
run_file.write(run_content.join("\n").as_bytes())?;
drop(run_file);
// Announce completion!
println!(
"{}",
"File successfully created! Good luck (:".green().bold()
);
Ok(())
}

338
src/commands/run.rs Normal file
View file

@ -0,0 +1,338 @@
use owo_colors::OwoColorize;
#[path = "../bin/8.rs"]
mod eight;
#[path = "../bin/18.rs"]
mod eighteen;
#[path = "../bin/11.rs"]
mod eleven;
#[path = "../bin/15.rs"]
mod fifteen;
#[path = "../bin/5.rs"]
mod five;
#[path = "../bin/4.rs"]
mod four;
#[path = "../bin/14.rs"]
mod fourteen;
#[path = "../bin/9.rs"]
mod nine;
#[path = "../bin/1.rs"]
mod one;
#[path = "../bin/7.rs"]
mod seven;
#[path = "../bin/17.rs"]
mod seventeen;
#[path = "../bin/6.rs"]
mod six;
#[path = "../bin/16.rs"]
mod sixteen;
#[path = "../bin/10.rs"]
mod ten;
#[path = "../bin/13.rs"]
mod thirteen;
#[path = "../bin/3.rs"]
mod three;
#[path = "../bin/12.rs"]
mod twelve;
#[path = "../bin/2.rs"]
mod two;
// #[path = "../bin/19.rs"]
// mod nineteen;
// #[path = "../bin/20.rs"]
// mod twenty;
// #[path = "../bin/21.rs"]
// mod twenty_one;
#[path = "../bin/22.rs"]
mod twenty_two;
// #[path = "../bin/23.rs"]
// mod twenty_three;
// #[path = "../bin/24.rs"]
// mod twenty_four;
// #[path = "../bin/25.rs"]
// mod twenty_five;
// #[path = "../bin/26.rs"]
// mod twenty_six;
// #[path = "../bin/27.rs"]
// mod twenty_seven;
// #[path = "../bin/28.rs"]
// mod twenty_eight;
// #[path = "../bin/29.rs"]
// mod twenty_nine;
// #[path = "../bin/30.rs"]
// mod thirty;
// #[path = "../bin/31.rs"]
// mod thirty_one;
// #[path = "../bin/32.rs"]
// mod thirty_two;
// #[path = "../bin/33.rs"]
// mod thirty_three;
// #[path = "../bin/34.rs"]
// mod thirty_four;
// #[path = "../bin/35.rs"]
// mod thirty_five;
// #[path = "../bin/36.rs"]
// mod thirty_six;
// #[path = "../bin/37.rs"]
// mod thirty_seven;
// #[path = "../bin/38.rs"]
// mod thirty_eight;
// #[path = "../bin/39.rs"]
// mod thirty_nine;
// #[path = "../bin/40.rs"]
// mod forty;
// #[path = "../bin/41.rs"]
// mod forty_one;
#[path = "../bin/42.rs"]
mod forty_two;
// #[path = "../bin/43.rs"]
// mod forty_three;
// #[path = "../bin/44.rs"]
// mod forty_four;
// #[path = "../bin/45.rs"]
// mod forty_five;
// #[path = "../bin/46.rs"]
// mod forty_six;
// #[path = "../bin/47.rs"]
// mod forty_seven;
// #[path = "../bin/48.rs"]
// mod forty_eight;
// #[path = "../bin/49.rs"]
// mod forty_nine;
// #[path = "../bin/50.rs"]
// mod fifty;
// #[path = "../bin/51.rs"]
// mod fifty_one;
// #[path = "../bin/52.rs"]
// mod fifty_two;
// #[path = "../bin/53.rs"]
// mod fifty_three;
// #[path = "../bin/54.rs"]
// mod fifty_four;
// #[path = "../bin/55.rs"]
// mod fifty_five;
// #[path = "../bin/56.rs"]
// mod fifty_six;
// #[path = "../bin/57.rs"]
// mod fifty_seven;
// #[path = "../bin/58.rs"]
// mod fifty_eight;
// #[path = "../bin/59.rs"]
// mod fifty_nine;
// #[path = "../bin/60.rs"]
// mod sixty;
// #[path = "../bin/61.rs"]
// mod sixty_one;
// #[path = "../bin/62.rs"]
// mod sixty_two;
// #[path = "../bin/63.rs"]
// mod sixty_three;
// #[path = "../bin/64.rs"]
// mod sixty_four;
// #[path = "../bin/65.rs"]
// mod sixty_five;
// #[path = "../bin/66.rs"]
// mod sixty_six;
#[path = "../bin/67.rs"]
mod sixty_seven;
// #[path = "../bin/68.rs"]
// mod sixty_eight;
// #[path = "../bin/69.rs"]
// mod sixty_nine;
// #[path = "../bin/70.rs"]
// mod seventy;
// #[path = "../bin/71.rs"]
// mod seventy_one;
// #[path = "../bin/72.rs"]
// mod seventy_two;
// #[path = "../bin/73.rs"]
// mod seventy_three;
// #[path = "../bin/74.rs"]
// mod seventy_four;
// #[path = "../bin/75.rs"]
// mod seventy_five;
// #[path = "../bin/76.rs"]
// mod seventy_six;
// #[path = "../bin/77.rs"]
// mod seventy_seven;
// #[path = "../bin/78.rs"]
// mod seventy_eight;
// #[path = "../bin/79.rs"]
// mod seventy_nine;
// #[path = "../bin/80.rs"]
// mod eighty;
// #[path = "../bin/81.rs"]
// mod eighty_one;
// #[path = "../bin/82.rs"]
// mod eighty_two;
// #[path = "../bin/83.rs"]
// mod eighty_three;
// #[path = "../bin/84.rs"]
// mod eighty_four;
// #[path = "../bin/85.rs"]
// mod eighty_five;
// #[path = "../bin/86.rs"]
// mod eighty_six;
// #[path = "../bin/87.rs"]
// mod eighty_seven;
// #[path = "../bin/88.rs"]
// mod eighty_eight;
// #[path = "../bin/89.rs"]
// mod eighty_nine;
// #[path = "../bin/90.rs"]
// mod ninety;
// #[path = "../bin/91.rs"]
// mod ninety_one;
// #[path = "../bin/92.rs"]
// mod ninety_two;
// #[path = "../bin/93.rs"]
// mod ninety_three;
// #[path = "../bin/94.rs"]
// mod ninety_four;
// #[path = "../bin/95.rs"]
// mod ninety_five;
// #[path = "../bin/96.rs"]
// mod ninety_six;
// #[path = "../bin/97.rs"]
// mod ninety_seven;
// #[path = "../bin/98.rs"]
// mod ninety_eight;
// #[path = "../bin/99.rs"]
// mod ninety_nine;
// #[path = "../bin/100.rs"]
// mod one_hundred;
#[tokio::main]
pub async fn execute(
problem: Option<u8>,
benchmark: bool,
) -> Result<(), Box<dyn std::error::Error>> {
let code_path = euler::code_path();
let problem_number =
euler::problem_number(problem, &code_path, "Which problem would you like to run?");
let start = std::time::Instant::now();
let mut exists = true;
match problem_number {
1 => one::main(),
2 => two::main(),
3 => three::main(),
4 => four::main(),
5 => five::main(),
6 => six::main(),
7 => seven::main(),
8 => eight::main(),
9 => nine::main(),
10 => ten::main(),
11 => eleven::main(),
12 => twelve::main(),
13 => thirteen::main(),
14 => fourteen::main(),
15 => fifteen::main(),
16 => sixteen::main(),
17 => seventeen::main(),
18 => eighteen::main(),
// 19 => nineteen::main(),
// 20 => twenty::main(),
// 21 => twenty_one::main(),
22 => twenty_two::main(),
// 23 => twenty_three::main(),
// 24 => twenty_four::main(),
// 25 => twenty_five::main(),
// 26 => twenty_six::main(),
// 27 => twenty_seven::main(),
// 28 => twenty_eight::main(),
// 29 => twenty_nine::main(),
// 30 => thirty::main(),
// 31 => thirty_one::main(),
// 32 => thirty_two::main(),
// 33 => thirty_three::main(),
// 34 => thirty_four::main(),
// 35 => thirty_five::main(),
// 36 => thirty_six::main(),
// 37 => thirty_seven::main(),
// 38 => thirty_eight::main(),
// 39 => thirty_nine::main(),
// 40 => forty::main(),
// 41 => forty_one::main(),
// 42 => forty_two::main(),
// 43 => forty_three::main(),
// 44 => forty_four::main(),
// 45 => forty_five::main(),
// 46 => forty_six::main(),
// 47 => forty_seven::main(),
// 48 => forty_eight::main(),
// 49 => forty_nine::main(),
// 50 => fifty::main(),
// 51 => fifty_one::main(),
// 52 => fifty_two::main(),
// 53 => fifty_three::main(),
// 54 => fifty_four::main(),
// 55 => fifty_five::main(),
// 56 => fifty_six::main(),
// 57 => fifty_seven::main(),
// 58 => fifty_eight::main(),
// 59 => fifty_nine::main(),
// 60 => sixty::main(),
// 61 => sixty_one::main(),
// 62 => sixty_two::main(),
// 63 => sixty_three::main(),
// 64 => sixty_four::main(),
// 65 => sixty_five::main(),
// 66 => sixty_six::main(),
67 => sixty_seven::main(),
// 68 => sixty_eight::main(),
// 69 => sixty_nine::main(),
// 70 => seventy::main(),
// 71 => seventy_one::main(),
// 72 => seventy_two::main(),
// 73 => seventy_three::main(),
// 74 => seventy_four::main(),
// 75 => seventy_five::main(),
// 76 => seventy_six::main(),
// 77 => seventy_seven::main(),
// 78 => seventy_eight::main(),
// 79 => seventy_nine::main(),
// 80 => eighty::main(),
// 81 => eighty_one::main(),
// 82 => eighty_two::main(),
// 83 => eighty_three::main(),
// 84 => eighty_four::main(),
// 85 => eighty_five::main(),
// 86 => eighty_six::main(),
// 87 => eighty_seven::main(),
// 88 => eighty_eight::main(),
// 89 => eighty_nine::main(),
// 90 => ninety::main(),
// 91 => ninety_one::main(),
// 92 => ninety_two::main(),
// 93 => ninety_three::main(),
// 94 => ninety_four::main(),
// 95 => ninety_five::main(),
// 96 => ninety_six::main(),
// 97 => ninety_seven::main(),
// 98 => ninety_eight::main(),
// 99 => ninety_nine::main(),
// 100 => one_hundred::main(),
_ => {
exists = false;
println!(
"{} {} {}",
"Problem".red().bold(),
problem_number.red().bold(),
"is not in this repository!".red().bold()
)
}
}
let duration = start.elapsed();
if benchmark && exists {
println!(
"Time elapsed when executing problem {} is: {:?}",
problem_number, duration
);
}
Ok(())
}

View file

@ -15,3 +15,51 @@ pub fn resources_path() -> PathBuf {
pub fn readme_path() -> PathBuf {
return fetch_dir().join("readme.md");
}
pub fn run_path() -> PathBuf {
return fetch_dir().join("src").join("commands").join("run.rs");
}
pub fn problem_number(problem: Option<u8>, code_path: &PathBuf, prompt: &str) -> u8 {
if let Some(n) = problem {
return n;
} else {
return requestty::prompt_one(
requestty::Question::int("problemNumber")
.message(prompt)
.validate(|n, _| {
// All numbers must be positive
let mut pass = false;
// Ensure that the problem has not already got a file associated with it
let files = std::fs::read_dir(code_path).unwrap();
for file in files {
let file_number = file
.unwrap()
.file_name()
.to_str()
.unwrap()
.split('.')
.collect::<Vec<&str>>()[0]
.parse::<i64>()
.unwrap();
if n == file_number {
pass = true;
}
}
if pass {
Ok(())
} else {
Err("Please ensure that your input is valid!".to_owned())
}
})
.build(),
)
.unwrap()
.as_int()
.unwrap() as u8;
}
}

View file

@ -1,12 +1,7 @@
#![allow(dead_code)]
use clap::{Args, Parser, Subcommand};
use owo_colors::OwoColorize;
use regex::Regex;
use scraper::{Html, Selector};
use std::io::BufReader;
use std::{
fs::{self, File, OpenOptions},
io::{BufRead, Write},
};
mod commands;
#[derive(Parser)]
#[clap(about, author, version)]
@ -15,188 +10,33 @@ struct Value {
command: Commands,
}
#[derive(Args, Clone)]
struct NewOptions {
/// The problem to complete
problem: Option<u16>,
#[derive(Args)]
struct NewArgs {
problem: Option<u8>,
}
#[derive(Args)]
struct RunArgs {
problem: Option<u8>,
#[arg(short, long, default_value_t = false)]
benchmark: bool,
}
#[derive(Subcommand)]
enum Commands {
/// Handles the initialisation of a new Project Euler Problem
New(NewOptions),
New(NewArgs),
/// Runs the solution to a problem
Run(RunArgs),
}
#[tokio::main]
async fn new(problem: Option<u16>) -> Result<(), Box<dyn std::error::Error>> {
let code_path = euler::code_path();
let problem_number: u16;
// Determine the problem number
match problem {
Some(n) => problem_number = n,
None => {
problem_number = requestty::prompt_one(
requestty::Question::int("problemNumber")
.message("Which problem would you like to solve?")
.validate(|n, _| {
// All numbers must be positive
let mut pass = n > 0;
// Ensure that the problem has not already got a file associated with it
let files = fs::read_dir(&code_path).unwrap();
for file in files {
let file_number = file
.unwrap()
.file_name()
.to_str()
.unwrap()
.split('.')
.collect::<Vec<&str>>()[0]
.parse::<i64>()
.unwrap();
if n == file_number && pass {
pass = false;
}
}
if pass {
Ok(())
} else {
Err("Please ensure that your input is valid!".to_owned())
}
})
.build(),
)
.unwrap()
.as_int()
.unwrap() as u16;
}
}
// Fetch the problem information
let body = reqwest::get(format!("https://projecteuler.net/problem={problem_number}"))
.await?
.text()
.await?;
let document = Html::parse_document(body.as_str());
let title_selector = Selector::parse("h2")?;
let content_selector = Selector::parse(".problem_content")?;
let html_tag_regex = Regex::new(r"<[^>]*>").unwrap();
let mut title = document
.select(&title_selector)
.next()
.unwrap()
.text()
.collect::<Vec<&str>>()
.join("");
let mut problem = html_tag_regex
.replace_all(
document
.select(&content_selector)
.next()
.unwrap()
.inner_html()
.as_str(),
" ",
)
.to_string()
.replace("$$", " ");
let file_body = format!(
"/*
Problem {} - {}
{}
*/
fn main() {{
println!(\"Hello World!\");
}}",
problem_number,
html_escape::decode_html_entities(&mut title).to_string(),
html_escape::decode_html_entities(&mut problem)
.split("\n")
.map(|s| s.trim())
.filter(|s| s != &"")
.collect::<Vec<&str>>()
.join("\n")
);
// Create the file
let mut file = File::create(code_path.join(format!("{problem_number}.rs"))).unwrap();
file.write(file_body.as_bytes()).unwrap();
drop(file);
// Read the contents of the readme for editing
let readme_path = euler::readme_path();
let mut readme_file = OpenOptions::new().read(true).open(&readme_path).unwrap();
let mut readme_content = BufReader::new(&readme_file)
.lines()
.map(|s| s.unwrap())
.collect::<Vec<String>>();
drop(readme_file);
// Mark the problem as done on the readme
let readme_regex = Regex::new(format!(" {problem_number} - (.*)").as_str()).unwrap();
for i in 0..readme_content.len() {
let line = readme_content[i].as_str();
if readme_regex.is_match(line) {
let matched = readme_regex.captures(line).unwrap();
readme_content[i] = format!(
"- [x] {problem_number} - [{}](src/bin/{problem_number}.rs)",
&matched[1].trim()
);
}
}
// Update the summary statistics on the readme
let mut readme_string = readme_content.join("\n");
let completed_regex = Regex::new("<!-- completed -->([0-9]+)<!-- completed -->").unwrap();
let new_completed = completed_regex.captures(readme_string.as_str()).unwrap()[1]
.parse::<u8>()
.unwrap()
+ 1;
readme_string = completed_regex
.replace(
readme_string.as_str(),
format!("<!-- completed -->{new_completed}<!-- completed -->"),
)
.to_string();
// Write the new content to the readme
readme_file = OpenOptions::new().write(true).open(&readme_path).unwrap();
readme_file.write(readme_string.as_bytes()).unwrap();
drop(readme_file);
// Announce completion!
println!(
"{}",
"File successfully created! Good luck (:".green().bold()
);
Ok(())
}
fn main() {
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let value = Value::parse();
match value.command {
Commands::New(options) => new(options.problem).unwrap(),
Commands::New(NewArgs { problem }) => commands::new::execute(problem),
Commands::Run(RunArgs { problem, benchmark }) => commands::run::execute(problem, benchmark),
}
}