divide repository in src and lib
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "euler11"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,20 @@
|
||||
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
|
||||
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
|
||||
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
|
||||
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
|
||||
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
|
||||
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
|
||||
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
|
||||
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
|
||||
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
|
||||
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
|
||||
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
|
||||
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
|
||||
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
|
||||
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
|
||||
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
|
||||
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
|
||||
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
|
||||
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
|
||||
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
|
||||
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
|
||||
@@ -0,0 +1,192 @@
|
||||
use std::{fmt::Debug, fs};
|
||||
|
||||
const LENGTH: usize = 4;
|
||||
|
||||
type Data = u32;
|
||||
type Neighbours = Vec<Coordinate>;
|
||||
|
||||
struct Coordinate {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
|
||||
impl Coordinate {
|
||||
fn new(x: usize, y: usize) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Coordinate {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let inner = &format!("{},{}", self.x, self.y);
|
||||
f.write_str(inner)
|
||||
}
|
||||
}
|
||||
|
||||
struct Grid {
|
||||
grid: Vec<Vec<Data>>,
|
||||
nx: usize,
|
||||
ny: usize,
|
||||
curr_x: usize,
|
||||
curr_y: usize,
|
||||
curr_direction: Direction,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
fn from_file(filename: &str) -> Self {
|
||||
let grid: Vec<Vec<_>> = fs::read_to_string(filename)
|
||||
.unwrap()
|
||||
.split_terminator('\n')
|
||||
.map(|line| {
|
||||
line.split_whitespace()
|
||||
.map(|cell| cell.parse::<u8>().unwrap() as Data)
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let ny = grid.len();
|
||||
let nx = grid[0].len();
|
||||
Grid {
|
||||
grid,
|
||||
nx,
|
||||
ny,
|
||||
curr_x: 0,
|
||||
curr_y: 0,
|
||||
curr_direction: Direction::None,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
let mut largest = 0;
|
||||
loop {
|
||||
if let Some(coordinates) = self.next() {
|
||||
let value = coordinates.iter().map(|c| self.grid[c.y][c.x]).product();
|
||||
if value > largest {
|
||||
largest = value;
|
||||
}
|
||||
}
|
||||
if self.done {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{largest}");
|
||||
}
|
||||
|
||||
fn advance_index(&mut self) {
|
||||
if self.curr_x == self.nx - 1 {
|
||||
self.curr_x = 0;
|
||||
self.curr_y += 1;
|
||||
if self.curr_y == self.ny {
|
||||
self.done = true;
|
||||
}
|
||||
} else {
|
||||
self.curr_x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours(&self) -> Option<Neighbours> {
|
||||
match self.curr_direction {
|
||||
Direction::Down => self.get_neighbours_down(),
|
||||
Direction::Right => self.get_neighbours_right(),
|
||||
Direction::DiagonalUp => self.get_neighbours_diag_up(),
|
||||
Direction::DiagonalDown => self.get_neighbours_diag_down(),
|
||||
Direction::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_down(&self) -> Option<Neighbours> {
|
||||
let max_y = self.curr_y + LENGTH;
|
||||
if max_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_y..max_y)
|
||||
.map(|y| Coordinate::new(self.curr_x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_right(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
if max_x > self.nx {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.map(|x| Coordinate::new(x, self.curr_y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_diag_up(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
let min_y = self.curr_y.wrapping_sub(LENGTH);
|
||||
if max_x > self.nx || min_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.zip(self.curr_y..min_y)
|
||||
.map(|(x, y)| Coordinate::new(x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_diag_down(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
let max_y = self.curr_y + LENGTH;
|
||||
if max_x > self.nx || max_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.zip(self.curr_y..max_y)
|
||||
.map(|(x, y)| Coordinate::new(x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Grid {
|
||||
type Item = Neighbours;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let has_wrapped;
|
||||
(self.curr_direction, has_wrapped) = self.curr_direction.next();
|
||||
if has_wrapped {
|
||||
self.advance_index();
|
||||
};
|
||||
self.get_neighbours()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Direction {
|
||||
None,
|
||||
Down,
|
||||
Right,
|
||||
DiagonalUp,
|
||||
DiagonalDown,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
fn next(&self) -> (Self, bool) {
|
||||
match self {
|
||||
Direction::None => (Direction::Down, false),
|
||||
Direction::Down => (Direction::Right, false),
|
||||
Direction::Right => (Direction::DiagonalUp, false),
|
||||
Direction::DiagonalUp => (Direction::DiagonalDown, false),
|
||||
Direction::DiagonalDown => (Direction::Down, true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut grid = Grid::from_file("grid.txt");
|
||||
grid.run();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "euler49"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,120 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
type Int = i64;
|
||||
const MIN_VALUE: Int = 2;
|
||||
const MAX_VALUE: Int = 10_000;
|
||||
const SIZE: usize = (MAX_VALUE - MIN_VALUE) as usize;
|
||||
type Array = [bool; SIZE];
|
||||
type Solution = [Int; 3];
|
||||
|
||||
fn main() {
|
||||
println!("Getting prime numbers up to {}", MAX_VALUE);
|
||||
let primes = Primes::from_array(get_prime_numbers_array());
|
||||
println!("Starting to iterate ...");
|
||||
let result = find_using_iter(&primes);
|
||||
for item in result {
|
||||
println!("{item}");
|
||||
}
|
||||
}
|
||||
|
||||
fn get_prime_numbers_array() -> Array {
|
||||
// Sieve of Eratosthenes
|
||||
let mut result = [true; SIZE];
|
||||
for number_to_check in MIN_VALUE..(MAX_VALUE / 2) {
|
||||
let mut last_number = number_to_check;
|
||||
loop {
|
||||
let current_number = last_number + number_to_check;
|
||||
if current_number >= MAX_VALUE {
|
||||
break;
|
||||
}
|
||||
result[(current_number - MIN_VALUE) as usize] = false;
|
||||
last_number = current_number;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
struct Primes {
|
||||
vector: Vec<Int>,
|
||||
set: HashSet<Int>,
|
||||
}
|
||||
impl Primes {
|
||||
fn from_array(array: Array) -> Primes {
|
||||
let mut vector = Vec::new();
|
||||
let mut set = HashSet::new();
|
||||
for number in MIN_VALUE..MAX_VALUE {
|
||||
if array[(number - MIN_VALUE) as usize] {
|
||||
vector.push(number);
|
||||
set.insert(number);
|
||||
}
|
||||
}
|
||||
Primes { vector, set }
|
||||
}
|
||||
}
|
||||
|
||||
fn find_using_iter(primes: &Primes) -> Solution {
|
||||
for p1 in primes.vector.iter() {
|
||||
let p2 = p1 + 3330;
|
||||
let p3 = p2 + 3330;
|
||||
if primes.set.contains(&p2) && primes.set.contains(&p3) {
|
||||
let candidate = [*p1, p2, p3];
|
||||
if satisfies_checks(&candidate) && candidate[0] != 1487 {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn satisfies_checks(candidates: &Solution) -> bool {
|
||||
let vec: Vec<_> = candidates.iter().map(get_amount_of_digits).collect();
|
||||
vec[0] == vec[1] && vec[0] == vec[2]
|
||||
}
|
||||
|
||||
fn get_amount_of_digits(x: &Int) -> HashMap<i32, usize> {
|
||||
let mut map = get_new_map();
|
||||
x.to_string()
|
||||
.chars()
|
||||
.map(|c| c.to_digit(10).unwrap() as i32)
|
||||
.for_each(|n| {
|
||||
map.insert(n, map.get(&n).unwrap() + 1).unwrap();
|
||||
});
|
||||
map
|
||||
}
|
||||
|
||||
fn get_new_map() -> HashMap<i32, usize> {
|
||||
(0..=9).into_iter().zip([0; 10]).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{get_amount_of_digits, get_new_map, satisfies_checks, Solution};
|
||||
|
||||
#[test]
|
||||
fn test_get_amount_of_digits() {
|
||||
let x = 4731;
|
||||
let hs = get_amount_of_digits(&x);
|
||||
let mut reference = get_new_map();
|
||||
reference.insert(4, 1);
|
||||
reference.insert(7, 1);
|
||||
reference.insert(3, 1);
|
||||
reference.insert(1, 1);
|
||||
assert_eq!(hs, reference);
|
||||
|
||||
let x = 4777;
|
||||
let hs = get_amount_of_digits(&x);
|
||||
let mut reference = get_new_map();
|
||||
reference.insert(4, 1);
|
||||
reference.insert(7, 3);
|
||||
assert_eq!(hs, reference);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_satisfies_checks() {
|
||||
let input: Solution = [1234, 3241, 4321];
|
||||
assert!(satisfies_checks(&input));
|
||||
|
||||
let input: Solution = [1254, 3241, 4321];
|
||||
assert!(!satisfies_checks(&input));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "euler50"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 3
|
||||
@@ -0,0 +1,113 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
// you will probably need to incrase the stack limit
|
||||
// $ ulimit -s
|
||||
// $ ulimit -s 32768
|
||||
|
||||
type Int = i64;
|
||||
const MIN_VALUE: Int = 2;
|
||||
const MAX_VALUE: Int = 1_000_000;
|
||||
const SIZE: usize = (MAX_VALUE - MIN_VALUE) as usize;
|
||||
type Array = [bool; SIZE];
|
||||
|
||||
fn main() {
|
||||
println!("Getting prime numbers up to {}", MAX_VALUE);
|
||||
let primes = Primes::from_array(get_prime_numbers_array());
|
||||
println!("Starting to iterate ...");
|
||||
let result = find_using_iter(&primes).unwrap();
|
||||
println!(
|
||||
"{:?} / sum: {} / len: {}",
|
||||
result,
|
||||
sum_of_vector(result),
|
||||
result.len()
|
||||
);
|
||||
}
|
||||
|
||||
fn get_prime_numbers_array() -> Array {
|
||||
// Sieve of Eratosthenes
|
||||
let mut result = [true; SIZE];
|
||||
for number_to_check in MIN_VALUE..(MAX_VALUE / 2) {
|
||||
let mut last_number = number_to_check;
|
||||
loop {
|
||||
let current_number = last_number + number_to_check;
|
||||
if current_number >= MAX_VALUE {
|
||||
break;
|
||||
}
|
||||
result[(current_number - MIN_VALUE) as usize] = false;
|
||||
last_number = current_number;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn sum_of_vector(vector: &[Int]) -> Int {
|
||||
vector.iter().sum()
|
||||
}
|
||||
|
||||
struct Primes {
|
||||
vector: Vec<Int>,
|
||||
set: HashSet<Int>,
|
||||
}
|
||||
|
||||
struct PrimesIter<'a> {
|
||||
primes: &'a Primes,
|
||||
current_min: usize,
|
||||
current_len: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PrimesIter<'a> {
|
||||
type Item = &'a [Int];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let result = &self.primes.vector[self.current_min..(self.current_min + self.current_len)];
|
||||
if result.iter().sum::<Int>() > MAX_VALUE {
|
||||
self.decrement_search_length();
|
||||
return self.next();
|
||||
}
|
||||
if self.current_min + self.current_len < self.primes.vector.len() {
|
||||
self.current_min += 1;
|
||||
} else {
|
||||
self.decrement_search_length();
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PrimesIter<'a> {
|
||||
fn decrement_search_length(&mut self) {
|
||||
self.current_min = 0;
|
||||
self.current_len -= 1;
|
||||
println!("{}", self.current_len);
|
||||
}
|
||||
}
|
||||
|
||||
impl Primes {
|
||||
fn iter(&self) -> PrimesIter {
|
||||
PrimesIter {
|
||||
primes: self,
|
||||
current_min: 0,
|
||||
current_len: self.vector.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_array(array: Array) -> Primes {
|
||||
let mut vector = Vec::new();
|
||||
let mut set = HashSet::new();
|
||||
for number in MIN_VALUE..MAX_VALUE {
|
||||
if array[(number - MIN_VALUE) as usize] {
|
||||
vector.push(number);
|
||||
set.insert(number);
|
||||
}
|
||||
}
|
||||
Primes { vector, set }
|
||||
}
|
||||
}
|
||||
|
||||
fn find_using_iter(primes: &'_ Primes) -> Option<&'_ [Int]> {
|
||||
for subvector in primes.iter() {
|
||||
if primes.set.contains(&sum_of_vector(subvector)) {
|
||||
return Some(subvector);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "euler51"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
primes = {version = "*", path = "../../lib/primes"}
|
||||
combination = {version = "*", path = "../../lib/combination"}
|
||||
@@ -0,0 +1,133 @@
|
||||
extern crate combination;
|
||||
extern crate primes;
|
||||
|
||||
use combination::PositionCombinations;
|
||||
use primes::Primes;
|
||||
|
||||
type Int = u64;
|
||||
|
||||
// EXAMPLE 1
|
||||
// const MIN_VALUE: Int = 10;
|
||||
// const MAX_VALUE: Int = 99;
|
||||
// const LENGTH: usize = 2;
|
||||
// const MIN_LENGTH: usize = 1;
|
||||
|
||||
// OWN TEST
|
||||
// const MIN_VALUE: Int = 100;
|
||||
// const MAX_VALUE: Int = 999;
|
||||
// const LENGTH: usize = 3;
|
||||
// const MIN_LENGTH: usize = 2;
|
||||
|
||||
// EXAMPLE 2
|
||||
// const MIN_VALUE: Int = 10_000;
|
||||
// const MAX_VALUE: Int = 99_999;
|
||||
// const LENGTH: usize = 5;
|
||||
// const MIN_LENGTH: usize = 2;
|
||||
|
||||
// FINAL
|
||||
const MIN_VALUE: Int = 100_000;
|
||||
const MAX_VALUE: Int = 999_999;
|
||||
const LENGTH: usize = 6;
|
||||
const MIN_LENGTH: usize = 2;
|
||||
|
||||
const MAX_LENGTH: usize = LENGTH - 1;
|
||||
const DIGITS: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
fn main() {
|
||||
let all_primes = Primes::get_between(MIN_VALUE, MAX_VALUE);
|
||||
let mut best_of_all_combinations = vec![];
|
||||
for pattern in PositionCombinations::new(MIN_LENGTH, MAX_LENGTH, LENGTH) {
|
||||
let mut best_this_combination = vec![];
|
||||
let mut primes_to_check = all_primes.clone();
|
||||
while let Some(first) = primes_to_check.pop() {
|
||||
let mut primes_matching_pattern = vec![];
|
||||
let digits = first.to_digits();
|
||||
for digit in DIGITS {
|
||||
let could_be_prime = digits
|
||||
.iter()
|
||||
.zip(pattern.clone())
|
||||
.map(|(d, b)| if b { digit } else { *d })
|
||||
.collect::<Vec<u8>>()
|
||||
.to_num();
|
||||
if primes_to_check.contains(&could_be_prime) || could_be_prime == first {
|
||||
primes_matching_pattern.push(could_be_prime);
|
||||
}
|
||||
}
|
||||
if primes_matching_pattern.len() > 2 {
|
||||
best_this_combination.push(primes_matching_pattern)
|
||||
}
|
||||
}
|
||||
if !best_this_combination.is_empty() {
|
||||
best_of_all_combinations.push(get_longest(best_this_combination, false));
|
||||
}
|
||||
}
|
||||
println!("{:#?}", get_longest(best_of_all_combinations, false));
|
||||
}
|
||||
|
||||
fn get_longest(mut vec: Vec<Vec<Int>>, print: bool) -> Vec<Int> {
|
||||
if vec.is_empty() {
|
||||
panic!("cannot give the longest element of an empty vector")
|
||||
}
|
||||
if print {
|
||||
println!("{:#?}", vec);
|
||||
}
|
||||
vec.sort_by_key(|c| c.len());
|
||||
let length = vec.last().unwrap().len();
|
||||
vec.into_iter().find(|v| v.len() == length).unwrap()
|
||||
}
|
||||
|
||||
trait ToString {
|
||||
fn to_string(&self) -> String;
|
||||
}
|
||||
|
||||
impl ToString for Vec<u8> {
|
||||
fn to_string(&self) -> String {
|
||||
self.iter().map(|d| d.to_string()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
trait ToDigits {
|
||||
fn to_digits(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
trait ToNum {
|
||||
fn to_num(&self) -> Int;
|
||||
}
|
||||
|
||||
impl ToDigits for Int {
|
||||
fn to_digits(&self) -> Vec<u8> {
|
||||
self.to_string()
|
||||
.chars()
|
||||
.map(|x| x.to_digit(10).unwrap() as u8)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToNum for Vec<u8> {
|
||||
fn to_num(&self) -> Int {
|
||||
let mut result = 0;
|
||||
let mut position = 1;
|
||||
for digit in self.iter().rev() {
|
||||
result += *digit as Int * position;
|
||||
position *= 10;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{ToDigits, ToNum};
|
||||
|
||||
#[test]
|
||||
fn test_digits_to_num() {
|
||||
let digits = vec![5, 7, 3, 8, 1];
|
||||
assert_eq!(digits.to_num(), 57381);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_num_to_digits() {
|
||||
let num = 83371;
|
||||
assert_eq!(num.to_digits(), vec![8, 3, 3, 7, 1]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user