feat(problem): 14 - longest collatz sequence

This commit is contained in:
newt 2024-10-09 18:10:10 +01:00
parent f5d308e0a9
commit 264a0c093f
16 changed files with 355 additions and 243 deletions

View file

@ -9,7 +9,7 @@ All of the solutions here are written in rust. [main.rs](src/main.rs) is the hom
## Challenge Completion ## Challenge Completion
### <!-- completed -->13<!-- completed --> out of 100 public challenges completed. ### <!-- completed -->14<!-- completed --> out of 100 public challenges completed.
- [x] 1 - [Multiples of 3 or 5](src/bin/1.rs) - [x] 1 - [Multiples of 3 or 5](src/bin/1.rs)
- [x] 2 - [Even Fibonacci numbers](src/bin/2.rs) - [x] 2 - [Even Fibonacci numbers](src/bin/2.rs)
@ -24,7 +24,7 @@ All of the solutions here are written in rust. [main.rs](src/main.rs) is the hom
- [x] 11 - [Largest product in a grid](src/bin/11.rs) - [x] 11 - [Largest product in a grid](src/bin/11.rs)
- [x] 12 - [Highly divisible triangular number](src/bin/12.rs) - [x] 12 - [Highly divisible triangular number](src/bin/12.rs)
- [x] 13 - [Large sum](src/bin/13.rs) - [x] 13 - [Large sum](src/bin/13.rs)
- [ ] 14 - Longest Collatz sequence - [x] 14 - [Longest Collatz sequence](src/bin/14.rs)
- [ ] 15 - Lattice paths - [ ] 15 - Lattice paths
- [ ] 16 - Power digit sum - [ ] 16 - Power digit sum
- [ ] 17 - Number letter counts - [ ] 17 - Number letter counts

View file

@ -80,26 +80,66 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
fn main() { fn main() {
let grid: Vec<Vec<usize>> = vec![ 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], vec![
vec![49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0], 8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8,
vec![81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65], ],
vec![52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91], vec![
vec![22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80], 49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0,
vec![24, 47, 32, 60, 99, 3, 45, 2, 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![
vec![67, 26, 20, 68, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21], 81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 3, 49, 13, 36, 65,
vec![24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72], ],
vec![21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95], vec![
vec![78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92], 52, 70, 95, 23, 4, 60, 11, 42, 69, 24, 68, 56, 1, 32, 56, 71, 37, 2, 36, 91,
vec![16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57], ],
vec![86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58], vec![
vec![19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40], 22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80,
vec![4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66], ],
vec![88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69], vec![
vec![4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 46, 29, 32, 40, 62, 76, 36], 24, 47, 32, 60, 99, 3, 45, 2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50,
vec![20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 4, 36, 16], ],
vec![20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54], vec![
vec![1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48] 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, 2, 62, 12, 20, 95, 63, 94, 39, 63, 8, 40, 91, 66, 49, 94, 21,
],
vec![
24, 55, 58, 5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72,
],
vec![
21, 36, 23, 9, 75, 0, 76, 44, 20, 45, 35, 14, 0, 61, 33, 97, 34, 31, 33, 95,
],
vec![
78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 3, 80, 4, 62, 16, 14, 9, 53, 56, 92,
],
vec![
16, 39, 5, 42, 96, 35, 31, 47, 55, 58, 88, 24, 0, 17, 54, 24, 36, 29, 85, 57,
],
vec![
86, 56, 0, 48, 35, 71, 89, 7, 5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58,
],
vec![
19, 80, 81, 68, 5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 4, 89, 55, 40,
],
vec![
4, 52, 8, 83, 97, 35, 99, 16, 7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66,
],
vec![
88, 36, 68, 87, 57, 62, 20, 72, 3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69,
],
vec![
4, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 8, 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, 4, 36, 16,
],
vec![
20, 73, 35, 29, 78, 31, 90, 1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 5, 54,
],
vec![
1, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 1, 89, 19, 67, 48,
],
]; ];
let value = largest_grid_product(grid, 4); let value = largest_grid_product(grid, 4);

View file

@ -204,7 +204,7 @@ const NUMBERS: [f64; 100] = [
77158542502016545090413245809786882778948721859617.0, 77158542502016545090413245809786882778948721859617.0,
72107838435069186155435662884062257473692284509516.0, 72107838435069186155435662884062257473692284509516.0,
20849603980134001723930671666823555245252804609722.0, 20849603980134001723930671666823555245252804609722.0,
53503534226472524250874054075591789781264330331690.0 53503534226472524250874054075591789781264330331690.0,
]; ];
fn first_n_digits(number: f64, n: usize) -> Option<usize> { fn first_n_digits(number: f64, n: usize) -> Option<usize> {
@ -214,7 +214,9 @@ fn first_n_digits(number: f64, n: usize) -> Option<usize> {
return None; return None;
} }
let new_number = String::from_iter(string_number.chars().collect::<Vec<char>>()[0..n].iter()).parse::<usize>().unwrap(); let new_number = String::from_iter(string_number.chars().collect::<Vec<char>>()[0..n].iter())
.parse::<usize>()
.unwrap();
return Some(new_number); return Some(new_number);
} }

54
src/bin/14.rs Normal file
View file

@ -0,0 +1,54 @@
/*
Problem 14 - Longest Collatz sequence
The following iterative sequence is defined for the set of positive integers:
n n /2 ( n is even) n 3 n + 1 ( n is odd)
Using the rule above and starting with 13, we generate the following sequence:
13 40 20 10 5 16 8 4 2 1
It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.
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 std::collections::HashMap;
fn f(n: usize) -> usize {
if n % 2 == 0 {
return n / 2;
} else {
return ((3 * n) + 1) / 2;
}
}
fn longest_collatz_sequence(greatest_start: usize) -> usize {
let mut sequence_lengths: HashMap<usize, usize> = HashMap::new();
for i in 1..(greatest_start + 1) {
let mut sequence_length: usize = 0;
let mut current_number = i;
while current_number > 1 {
current_number = f(current_number);
// Eventually the sequence will break down into one we have already computed the length for!
if sequence_lengths.contains_key(&current_number) {
sequence_length += *sequence_lengths.get(&current_number).unwrap();
break;
}
sequence_length += 1;
}
sequence_lengths.insert(i, sequence_length);
}
return *sequence_lengths.iter().max_by_key(|x| x.1).unwrap().0;
}
fn main() {
let starting_number = longest_collatz_sequence(1_000_000);
println!(
"The starting number which produces the longest collatz sequence is {starting_number}"
);
}

View file

@ -24,5 +24,8 @@ fn main() {
let even = sequence.iter().filter(|n| *n % 2 == 0); let even = sequence.iter().filter(|n| *n % 2 == 0);
let sum: usize = even.sum(); let sum: usize = even.sum();
print!("The sum of the first 4000000 even fibonacci numbers is {}", sum); print!(
"The sum of the first 4000000 even fibonacci numbers is {}",
sum
);
} }

View file

@ -1,15 +1,19 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use std::{fs::{self, File, OpenOptions}, path::Path, io::{Write, BufRead}};
use scraper::{Html, Selector};
use regex::Regex; use regex::Regex;
use std::io::{BufReader}; use scraper::{Html, Selector};
use std::io::BufReader;
use std::{
fs::{self, File, OpenOptions},
io::{BufRead, Write},
path::Path,
};
#[derive(Parser)] #[derive(Parser)]
#[clap(about, author, version)] #[clap(about, author, version)]
struct Value { struct Value {
#[clap(subcommand)] #[clap(subcommand)]
command: Commands command: Commands,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
@ -55,13 +59,19 @@ async fn new() -> Result<(), Box<dyn std::error::Error>> {
Err("Please ensure that your input is valid!".to_owned()) Err("Please ensure that your input is valid!".to_owned())
} }
}) })
.build() .build(),
).unwrap().as_int().unwrap(); )
.unwrap()
.as_int()
.unwrap();
// todo: thoughts documents (?) // todo: thoughts documents (?)
// Fetch the problem information // Fetch the problem information
let body = reqwest::get(format!("https://projecteuler.net/problem={problem_number}")).await?.text().await?; let body = reqwest::get(format!("https://projecteuler.net/problem={problem_number}"))
.await?
.text()
.await?;
let document = Html::parse_document(body.as_str()); let document = Html::parse_document(body.as_str());
let title_selector = Selector::parse("h2")?; let title_selector = Selector::parse("h2")?;
@ -84,7 +94,7 @@ async fn new() -> Result<(), Box<dyn std::error::Error>> {
.unwrap() .unwrap()
.inner_html() .inner_html()
.as_str(), .as_str(),
" " " ",
) )
.to_string() .to_string()
.replace("$$", " "); .replace("$$", " ");
@ -117,17 +127,13 @@ fn main() {{
// Read the contents of the readme for editing // Read the contents of the readme for editing
let readme_path = base_dir.join("readme.md"); let readme_path = base_dir.join("readme.md");
let mut readme_file = OpenOptions::new() let mut readme_file = OpenOptions::new().read(true).open(&readme_path).unwrap();
.read(true)
.open(&readme_path)
.unwrap();
let mut readme_content = BufReader::new(&readme_file) let mut readme_content = BufReader::new(&readme_file)
.lines() .lines()
.map(|s| s.unwrap()) .map(|s| s.unwrap())
.collect::<Vec<String>>(); .collect::<Vec<String>>();
drop(readme_file); drop(readme_file);
// Mark the problem as done on the readme // Mark the problem as done on the readme
@ -138,7 +144,10 @@ fn main() {{
if readme_regex.is_match(line) { if readme_regex.is_match(line) {
let matched = readme_regex.captures(line).unwrap(); let matched = readme_regex.captures(line).unwrap();
readme_content[i] = format!("- [x] {problem_number} - [{}](src/bin/{problem_number}.rs)", &matched[1].trim()); readme_content[i] = format!(
"- [x] {problem_number} - [{}](src/bin/{problem_number}.rs)",
&matched[1].trim()
);
} }
} }
@ -147,26 +156,30 @@ fn main() {{
let completed_regex = Regex::new("<!-- completed -->([0-9]+)<!-- completed -->").unwrap(); let completed_regex = Regex::new("<!-- completed -->([0-9]+)<!-- completed -->").unwrap();
let new_completed = completed_regex let new_completed = completed_regex.captures(readme_string.as_str()).unwrap()[1]
.captures(readme_string.as_str())
.unwrap()[1]
.parse::<u8>() .parse::<u8>()
.unwrap() + 1; .unwrap()
+ 1;
readme_string = completed_regex.replace(readme_string.as_str(), format!("<!-- completed -->{new_completed}<!-- completed -->")).to_string(); readme_string = completed_regex
.replace(
readme_string.as_str(),
format!("<!-- completed -->{new_completed}<!-- completed -->"),
)
.to_string();
// Write the new content to the readme // Write the new content to the readme
readme_file = OpenOptions::new() readme_file = OpenOptions::new().write(true).open(&readme_path).unwrap();
.write(true)
.open(&readme_path)
.unwrap();
readme_file.write(readme_string.as_bytes()).unwrap(); readme_file.write(readme_string.as_bytes()).unwrap();
drop(readme_file); drop(readme_file);
// Announce completion! // Announce completion!
println!("{}", "File successfully created! Good luck (:".green().bold()); println!(
"{}",
"File successfully created! Good luck (:".green().bold()
);
Ok(()) Ok(())
} }
@ -175,6 +188,6 @@ fn main() {
let value = Value::parse(); let value = Value::parse();
match value.command { match value.command {
Commands::New => new().unwrap() Commands::New => new().unwrap(),
} }
} }