divide repository in src and lib

This commit is contained in:
timeshifter
2022-08-14 21:14:01 +02:00
parent 4bac3290e5
commit a43cdc4494
19 changed files with 41 additions and 10 deletions
+8
View File
@@ -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]
+20
View File
@@ -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
+192
View File
@@ -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();
}
+8
View File
@@ -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]
+120
View File
@@ -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));
}
}
+12
View File
@@ -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
+113
View File
@@ -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
}
+10
View File
@@ -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"}
View File
+133
View File
@@ -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]);
}
}