feat(problem): 22 - names scores, and improved file generation
This commit is contained in:
parent
479648eea0
commit
1c88037e21
6 changed files with 122 additions and 45 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
/binaries
|
||||
/old
|
||||
|
|
|
@ -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
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
49
src/bin/22.rs
Normal 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
17
src/lib.rs
Normal 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");
|
||||
}
|
95
src/main.rs
95
src/main.rs
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue