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
### <!-- 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] 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] 12 - [Highly divisible triangular number](src/bin/12.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
- [ ] 16 - Power digit sum
- [ ] 17 - Number letter counts

View file

@ -80,26 +80,66 @@ fn largest_grid_product(grid: Vec<Vec<usize>>, adjacent_digits: usize) -> usize
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],
vec![49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0],
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![22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
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![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]
vec![
8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8,
],
vec![
49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 4, 56, 62, 0,
],
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![
22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80,
],
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![
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);

View file

@ -14,7 +14,7 @@ fn factors(number: usize) -> Vec<Vec<usize>> {
let mut factors: Vec<Vec<usize>> = vec![vec![1, number]];
let is_even = number % 2 == 0;
for current_factor in (if is_even {2} else {3})..(max + 1) {
for current_factor in (if is_even { 2 } else { 3 })..(max + 1) {
if number % current_factor != 0 {
continue;
}

View file

@ -204,7 +204,7 @@ const NUMBERS: [f64; 100] = [
77158542502016545090413245809786882778948721859617.0,
72107838435069186155435662884062257473692284509516.0,
20849603980134001723930671666823555245252804609722.0,
53503534226472524250874054075591789781264330331690.0
53503534226472524250874054075591789781264330331690.0,
];
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;
}
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);
}

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 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 owo_colors::OwoColorize;
use std::{fs::{self, File, OpenOptions}, path::Path, io::{Write, BufRead}};
use scraper::{Html, Selector};
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)]
#[clap(about, author, version)]
struct Value {
#[clap(subcommand)]
command: Commands
command: Commands,
}
#[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())
}
})
.build()
).unwrap().as_int().unwrap();
.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 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")?;
@ -84,7 +94,7 @@ async fn new() -> Result<(), Box<dyn std::error::Error>> {
.unwrap()
.inner_html()
.as_str(),
" "
" ",
)
.to_string()
.replace("$$", " ");
@ -117,17 +127,13 @@ fn main() {{
// Read the contents of the readme for editing
let readme_path = base_dir.join("readme.md");
let mut readme_file = OpenOptions::new()
.read(true)
.open(&readme_path)
.unwrap();
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
@ -138,7 +144,10 @@ fn main() {{
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());
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 new_completed = completed_regex
.captures(readme_string.as_str())
.unwrap()[1]
let new_completed = completed_regex.captures(readme_string.as_str()).unwrap()[1]
.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
readme_file = OpenOptions::new()
.write(true)
.open(&readme_path)
.unwrap();
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());
println!(
"{}",
"File successfully created! Good luck (:".green().bold()
);
Ok(())
}
@ -175,6 +188,6 @@ fn main() {
let value = Value::parse();
match value.command {
Commands::New => new().unwrap()
Commands::New => new().unwrap(),
}
}