feat(tools): cli to help generate files for new problems, and problem 1 rewritten in rust

This commit is contained in:
newt 2024-10-09 18:10:08 +01:00
parent a0a6f8c8f7
commit 62becdbc65
6 changed files with 2066 additions and 3 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
/ignore

1903
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,17 @@
[package]
name = "euler"
version = "0.1.0"
version = "1.0.0"
edition = "2021"
default-run = "euler"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[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"

1
readme.md Normal file
View file

@ -0,0 +1 @@
# readme coming soon

29
src/bin/1.rs Normal file
View file

@ -0,0 +1,29 @@
// Problem 1 - Multiples of 3 or 5
// If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
// Find the sum of all the multiples of 3 or 5 below 1000.
use std::collections::HashSet;
fn multiples_of(multipliers: &Vec<usize>, upper_bound: usize) -> HashSet<usize> {
let mut results: HashSet<usize> = HashSet::new();
// Find all of the numbers between 1 and the upper bound that are multiples of one of the numbers
// in the multipliers vec
for i in 1..upper_bound {
for number in multipliers {
if i % number == 0 {
results.insert(i);
}
}
}
return results;
}
fn main() {
let multiples = multiples_of(&vec![3, 5], 1000);
let sum: usize = multiples.iter().sum();
println!("The sum of the multiples of 3 and 5 up until 1000 is {sum}");
}

View file

@ -1,3 +1,123 @@
fn main() {
println!("Hello, world!");
use clap::{Parser, Subcommand};
use owo_colors::OwoColorize;
use std::{fs, path::Path, io::Write};
use scraper::{Html, Selector};
use regex::Regex;
#[derive(Parser)]
#[clap(about, author, version)]
struct Value {
#[clap(subcommand)]
command: Commands
}
#[derive(Subcommand)]
enum Commands {
/// Handles the initialisation of a new Project Euler Problem
New,
}
#[tokio::main]
async fn new() -> Result<(), Box<dyn std::error::Error>> {
let code_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("bin");
let 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();
// todo: thoughts documents (?)
// Fetch the problem information
let body = reqwest::get(format!("https://projecteuler.net/problem={problem_number}")).await?.text().await?;
let document = Html::parse_document(Box::leak(body.into_boxed_str()));
let title_selector = Selector::parse("h2")?;
let content_selector = Selector::parse(".problem_content")?;
let re = Regex::new(r"<[^>]*>").unwrap();
let mut title = document
.select(&title_selector)
.next()
.unwrap()
.text()
.collect::<Vec<&str>>()
.join("");
let mut problem = re.replace_all(
Box::leak(
document
.select(&content_selector)
.next()
.unwrap()
.inner_html()
.into_boxed_str()
),
" "
).to_string();
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").filter(|s| s != &"").collect::<Vec<&str>>().join("\n//")
);
// Create the file
let mut file = fs::File::create(code_path.join(format!("{problem_number}.rs"))).unwrap();
file.write(file_body.as_bytes()).unwrap();
drop(file);
// todo: update readme
// Announce completion!
println!("{}", "File successfully created! Good luck (:".green());
Ok(())
}
// todo: runner
fn main() {
let value = Value::parse();
match value.command {
Commands::New => new().unwrap(),
}
}