feat(problem): 22 - names scores, and improved file generation

This commit is contained in:
newt 2024-10-09 18:10:11 +01:00
parent 479648eea0
commit 1c88037e21
6 changed files with 122 additions and 45 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/target
/binaries
/old

View file

@ -11,7 +11,7 @@ I originally started the challenge in [the-honk](https://github.com/newtykins/th
## Challenge Completion
### <!-- completed -->15<!-- completed --> out of 100 public challenges completed.
### <!-- completed -->17<!-- 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)
@ -34,7 +34,7 @@ I originally started the challenge in [the-honk](https://github.com/newtykins/th
- [ ] 19 - Counting Sundays
- [ ] 20 - Factorial digit sum
- [ ] 21 - Amicable numbers
- [ ] 22 - Names scores
- [x] 22 - [Names scores](src/bin/22.rs)
- [ ] 23 - Non-abundant sums
- [ ] 24 - Lexicographic permutations
- [ ] 25 - 1000-digit Fibonacci number

1
resources/p022_names.txt Normal file

File diff suppressed because one or more lines are too long

49
src/bin/22.rs Normal file
View file

@ -0,0 +1,49 @@
/*
Problem 22 - Names scores
Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.
For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.
What is the total of all the name scores in the file?
*/
use regex::Regex;
use std::fs;
fn read_names() -> Vec<String> {
let mut names = fs::read_to_string(euler::resources_path().join("p022_names.txt"))
.unwrap()
.split(",")
.map(|name| Regex::new("\"").unwrap().replace_all(name, "").to_string())
.collect::<Vec<String>>();
names.sort();
return names;
}
fn name_score(name: String, position: usize) -> usize {
let mut letter_sum: usize = 0;
for char in name.chars() {
// Letters start in ASCII at 65
letter_sum += (char as usize) - 64;
}
return letter_sum * position;
}
fn name_score_total(names: Vec<String>) -> usize {
let mut total: usize = 0;
for i in 0..names.len() {
total += name_score(names[i].clone(), i + 1);
}
return total;
}
fn main() {
let names = read_names();
let total = name_score_total(names);
println!("The total of all of the name scores in the file is {total}");
}

17
src/lib.rs Normal file
View file

@ -0,0 +1,17 @@
use std::path::{Path, PathBuf};
fn fetch_dir() -> &'static Path {
return Path::new(env!("CARGO_MANIFEST_DIR"));
}
pub fn code_path() -> PathBuf {
return fetch_dir().join("src").join("bin");
}
pub fn resources_path() -> PathBuf {
return fetch_dir().join("resources");
}
pub fn readme_path() -> PathBuf {
return fetch_dir().join("readme.md");
}

View file

@ -1,4 +1,4 @@
use clap::{Parser, Subcommand};
use clap::{Args, Parser, Subcommand};
use owo_colors::OwoColorize;
use regex::Regex;
use scraper::{Html, Selector};
@ -6,7 +6,6 @@ use std::io::BufReader;
use std::{
fs::{self, File, OpenOptions},
io::{BufRead, Write},
path::Path,
};
#[derive(Parser)]
@ -16,56 +15,66 @@ struct Value {
command: Commands,
}
#[derive(Args, Clone)]
struct NewOptions {
/// The problem to complete
problem: Option<u16>,
}
#[derive(Subcommand)]
enum Commands {
/// Handles the initialisation of a new Project Euler Problem
New,
New(NewOptions),
}
#[tokio::main]
async fn new() -> Result<(), Box<dyn std::error::Error>> {
let base_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let code_path = base_dir.join("src").join("bin");
async fn new(problem: Option<u16>) -> Result<(), Box<dyn std::error::Error>> {
let code_path = euler::code_path();
let problem_number: u16;
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;
// 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();
// 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();
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 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 (?)
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}"))
@ -125,7 +134,7 @@ fn main() {{
drop(file);
// Read the contents of the readme for editing
let readme_path = base_dir.join("readme.md");
let readme_path = euler::readme_path();
let mut readme_file = OpenOptions::new().read(true).open(&readme_path).unwrap();
@ -188,6 +197,6 @@ fn main() {
let value = Value::parse();
match value.command {
Commands::New => new().unwrap(),
Commands::New(options) => new(options.problem).unwrap(),
}
}