Merge remote-tracking branch 'refs/remotes/origin/main'

This commit is contained in:
timeshifter
2024-09-08 11:25:35 +02:00
15 changed files with 589 additions and 34 deletions
+10 -8
View File
@@ -96,18 +96,18 @@ where
while !(self.unvisited_without_distance.is_empty() while !(self.unvisited_without_distance.is_empty()
&& self.unvisited_with_distance.is_empty()) && self.unvisited_with_distance.is_empty())
{ {
let coord = self.get_unvisited_coord_with_smallest_distance_from_start(); let to_visit = self.get_unvisited_coord_with_smallest_distance_from_start();
let neighbours = self.get_neighbours(&coord); self.visit(to_visit);
let previous_distance = *self.matrix.get(coord).unwrap().get_distance().unwrap(); let neighbours = self.get_neighbours(&to_visit);
let previous_distance = *self.matrix.get(to_visit).unwrap().get_distance().unwrap();
for neighbour in neighbours { for neighbour in neighbours {
self.update_neighbour(neighbour, coord, previous_distance); self.update_neighbour(neighbour, to_visit, previous_distance);
} }
} }
} }
fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate { fn get_unvisited_coord_with_smallest_distance_from_start(&mut self) -> Coordinate {
let coord = self self.unvisited_with_distance
.unvisited_with_distance
.iter() .iter()
.filter_map(|c| { .filter_map(|c| {
let node = self.matrix.get(*c).unwrap(); let node = self.matrix.get(*c).unwrap();
@@ -115,9 +115,11 @@ where
}) })
.reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) }) .reduce(|(c0, v0), (c1, v1)| if v0 < v1 { (c0, v0) } else { (c1, v1) })
.map(|(c, _)| *c) .map(|(c, _)| *c)
.unwrap_or(self.start); .unwrap_or(self.start)
}
fn visit(&mut self, coord: (usize, usize)) {
self.unvisited_with_distance.remove(&coord); self.unvisited_with_distance.remove(&coord);
coord
} }
fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> { fn get_neighbours(&self, coordinate: &Coordinate) -> Vec<Coordinate> {
+6 -1
View File
@@ -6,12 +6,13 @@ use std::fs::File;
use std::hash::Hash; use std::hash::Hash;
use std::io::Write; use std::io::Write;
use std::slice::Iter; use std::slice::Iter;
use std::vec::IntoIter;
use num::FromPrimitive; use num::FromPrimitive;
use num::Num; use num::Num;
use num::ToPrimitive; use num::ToPrimitive;
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct Primes<T> { pub struct Primes<T> {
vector: Vec<T>, vector: Vec<T>,
set: HashSet<T>, set: HashSet<T>,
@@ -110,6 +111,10 @@ where
pub fn into_vec(self) -> Vec<T> { pub fn into_vec(self) -> Vec<T> {
self.vector self.vector
} }
pub fn to_cloned_iter(&self) -> IntoIter<T> {
self.vector.clone().into_iter()
}
} }
#[cfg(test)] #[cfg(test)]
+31 -25
View File
@@ -13,39 +13,45 @@ fn main() {
squbes.iterate(); squbes.iterate();
squbes.iterate(); squbes.iterate();
squbes.iterate(); squbes.iterate();
println!("{:?}", squbes.output()); println!("{:?}", squbes.get_output());
} }
#[derive(Debug)] #[derive(Debug)]
struct Squbes { struct Squbes {
squbes: HashSet<u64>, squbes: HashSet<u64>,
new_squbes: Vec<u64>, primes: Primes<u64>,
primes: IntoIter<u64>, primes_iter: IntoIter<u64>,
used_primes: Vec<u64>, used_primes: Vec<u64>,
current_prime: u64, current_prime: u64,
} }
impl Squbes { impl Squbes {
pub fn new(max: u64) -> Self { pub fn new(max: u64) -> Self {
let mut primes = Primes::get_between(2, max).into_vec().into_iter(); let primes = Primes::get_between(2, max);
let first = primes.next().unwrap(); let mut primes_iter = primes.to_cloned_iter();
let second = primes.next().unwrap(); let first = primes_iter.next().unwrap();
let second = primes_iter.next().unwrap();
Self { Self {
squbes: HashSet::new(), squbes: HashSet::new(),
new_squbes: vec![],
primes, primes,
primes_iter,
used_primes: vec![first], used_primes: vec![first],
current_prime: second, current_prime: second,
} }
} }
pub fn iterate(&mut self) { pub fn iterate(&mut self) {
self.calculate_squbes_with_current_prime(); let squbes = self.calculate_squbes_with_current_prime();
self.save_current_prime(); self.save_current_prime();
self.update_current_prime(); self.update_current_prime();
self.save_new_squbes();
} }
pub fn output(&self) -> Vec<u64> { fn save_new_squbes(&mut self) {
todo!()
}
pub fn get_output(&self) -> Vec<u64> {
let mut result: Vec<_> = self.squbes.iter().copied().collect(); let mut result: Vec<_> = self.squbes.iter().copied().collect();
result.sort_unstable(); result.sort_unstable();
result result
@@ -56,27 +62,27 @@ impl Squbes {
} }
fn update_current_prime(&mut self) { fn update_current_prime(&mut self) {
self.current_prime = self.primes.next().unwrap(); self.current_prime = self.primes_iter.next().unwrap();
} }
fn calculate_squbes_with_current_prime(&mut self) { fn calculate_squbes_with_current_prime(&mut self) -> Vec<u64> {
assert_ne!(self.current_prime, 0); get_iterator_over_pairs_both_ways(&self.used_primes, self.current_prime)
let iter = self .map(|(p, q)| Self::core(p, q))
.used_primes .collect()
.iter()
.copied()
.zip([self.current_prime].into_iter().cycle())
.chain(
[self.current_prime]
.into_iter()
.cycle()
.zip(self.used_primes.iter().copied()),
)
.map(|(p, q)| Self::core(p, q));
self.new_squbes.extend(iter);
} }
fn core(p: u64, q: u64) -> u64 { fn core(p: u64, q: u64) -> u64 {
p.pow(2) * q.pow(3) p.pow(2) * q.pow(3)
} }
} }
fn get_iterator_over_pairs_both_ways(
vec: &[u64],
value: u64,
) -> impl Iterator<Item = (u64, u64)> + '_ {
iterate_vec_and_scalar(vec, value).flat_map(|(x, y)| [(x, y), (y, x)].into_iter())
}
fn iterate_vec_and_scalar(vec: &[u64], value: u64) -> impl Iterator<Item = (u64, u64)> + '_ {
vec.iter().copied().zip([value].into_iter().cycle())
}
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "euler85"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+66
View File
@@ -0,0 +1,66 @@
const TARGET: usize = 2_000_000;
fn main() {
let mut x = 1_000;
let mut y = 2;
let mut grid = Grid::new(x, y);
let mut number;
let mut best_grid = grid.clone();
let mut best_diff = 5_000_000;
loop {
number = grid.number_rectangles();
let diff = number.abs_diff(TARGET);
if diff < best_diff {
best_diff = diff;
best_grid = grid.clone();
}
if number < TARGET {
y += 1;
} else {
x -= 1;
}
if x == 1 {
break;
}
grid = Grid::new(x, y);
}
let area = best_grid.area();
println!("{area}");
}
#[derive(Debug, Clone)]
struct Grid {
x: usize,
y: usize,
}
impl Grid {
fn new(x: usize, y: usize) -> Self {
Self { x, y }
}
fn number_rectangles(&self) -> usize {
let mut result = 0;
for x in 1..=self.x {
for y in 1..=self.y {
result += self.fits(x, y);
}
}
result
}
fn fits(&self, x: usize, y: usize) -> usize {
let fits_in_x = self.x - (x - 1);
let fits_in_y = self.y - (y - 1);
fits_in_x * fits_in_y
}
fn area(&self) -> usize {
self.x * self.y
}
}
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "euler86"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
lto = "fat"
debug = true
+60
View File
@@ -0,0 +1,60 @@
use std::f64::EPSILON;
const TARGET: u32 = 1_000_000;
fn main() {
let mut m = 1;
let mut distinct = 0;
loop {
println!("trying: {m}");
for x in 1..m + 1 {
for y in x..m + 1 {
let z = m;
let c = Cuboid::new(x, y, z);
if c.shortest_path_is_integer() {
distinct += 1;
};
}
}
if distinct > TARGET {
break;
}
m += 1;
}
println!("\n{m}");
}
struct Cuboid {
x: u32,
y: u32,
z: u32,
}
impl Cuboid {
fn new(x: u32, y: u32, z: u32) -> Self {
Self { x, y, z }
}
fn shortest_path_is_integer(&self) -> bool {
// because of the way we iterator over x, y and z, these are guaranteed to be in order
// and therefore produces the shortest path
let shortest_path = pythagorean(self.x + self.y, self.z);
is_integer(shortest_path)
}
}
fn pythagorean(x: u32, y: u32) -> f64 {
((x.pow(2) + y.pow(2)) as f64).sqrt()
}
fn is_integer(result: f64) -> bool {
let rounded = result.round();
(result - rounded).abs() <= EPSILON
}
+9
View File
@@ -0,0 +1,9 @@
[package]
name = "euler92"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
lto = "fat"
+38
View File
@@ -0,0 +1,38 @@
const MAXIMUM: usize = 10_000_000;
fn main() {
let mut arrives_at_89 = 0;
for i in 1..MAXIMUM {
let mut number = i;
loop {
let sum: usize = number
.to_digits()
.into_iter()
.map(|d| d.pow(2) as usize)
.sum();
if sum == 89 {
arrives_at_89 += 1;
break;
} else if sum == 1 {
break;
}
number = sum;
}
}
println!("{arrives_at_89}");
}
trait ToDigits {
fn to_digits(&self) -> Vec<u8>;
}
impl ToDigits for usize {
fn to_digits(&self) -> Vec<u8> {
self.to_string()
.chars()
.map(|c| c.to_digit(10).unwrap() as _)
.collect()
}
}
+9
View File
@@ -0,0 +1,9 @@
[package]
name = "euler93"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
itertools = "*"
+141
View File
@@ -0,0 +1,141 @@
use std::cmp::Ordering;
use itertools::Itertools;
type Num = f64;
type Quadruple = [Num; 4];
const ALL_DIGITS: [Num; 10] = [0., 1., 2., 3., 4., 5., 6., 7., 8., 9.];
fn main() {
let mut digits_length = vec![];
for quadruple_vec in ALL_DIGITS.into_iter().permutations(4) {
let quadruple = vec_to_quadruple(quadruple_vec);
let digits = Digits(quadruple);
let permutations = digits.permutations();
let mut results: Vec<_> = permutations
.into_iter()
.flat_map(find_integer_results)
.collect();
results.sort_unstable_by(|n1, n2| {
if n1 < n2 {
Ordering::Less
} else {
Ordering::Greater
}
});
let result = results
.into_iter()
.tuple_windows()
.filter(|(v0, v1)| (v1 - v0) > Num::EPSILON)
.map(|(n1, _)| n1) // TODO last number may be missing?
.collect_vec();
let length = number_consecutive_positive_integers(result);
digits_length.push((quadruple, length));
}
digits_length.sort_unstable_by(|a, b| a.1.cmp(&b.1));
let mut result = digits_length.last().unwrap().0;
result.sort_by(Num::total_cmp);
let s: String = result
.into_iter()
.map(|d| char::from_digit(d as u32, 10).unwrap())
.collect();
println!("{s}");
}
fn number_consecutive_positive_integers(result: Vec<f64>) -> usize {
let length = result.len();
result
.into_iter()
.tuple_windows()
.filter(|(a, b)| b - 1.5 > *a)
.map(|(a, _)| a.round() as usize)
.next()
.unwrap_or(length)
}
fn find_integer_results(quadruple: Quadruple) -> Vec<Num> {
let [i0, i1, i2, i3] = quadruple;
let mut result = vec![];
for op1 in Operations::iter() {
for op2 in Operations::iter() {
for op3 in Operations::iter() {
let num = op3(op2(op1(i0, i1), i2), i3);
if num > 0. && is_integer(num) {
result.push(num);
}
}
}
}
result
}
fn is_integer(num: Num) -> bool {
(num.round() - num).abs() <= Num::EPSILON
}
struct Digits(Quadruple);
impl Digits {
fn permutations(&self) -> Vec<Quadruple> {
self.0
.into_iter()
.permutations(4)
.map(vec_to_quadruple)
.collect()
}
}
fn vec_to_quadruple(v: Vec<f64>) -> Quadruple {
unsafe {
let i0 = *v.get_unchecked(0);
let i1 = *v.get_unchecked(1);
let i2 = *v.get_unchecked(2);
let i3 = *v.get_unchecked(3);
[i0, i1, i2, i3]
}
}
struct Operations {
last: usize,
}
impl Iterator for Operations {
type Item = Box<dyn Fn(Num, Num) -> Num>;
fn next(&mut self) -> Option<Self::Item> {
self.last += 1;
match self.last {
1 => Some(Box::new(|l, r| l + r)),
2 => Some(Box::new(|l, r| l - r)),
3 => Some(Box::new(|l, r| r - l)),
4 => Some(Box::new(|l, r| l * r)),
5 => Some(Box::new(|l, r| l / r)),
6 => Some(Box::new(|l, r| r / l)),
_ => None,
}
}
}
impl Operations {
fn iter() -> Self {
Self { last: 0 }
}
}
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "euler94"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
f128 = "0.2.9"
num-traits = "0.2.15"
[profile.release]
lto = "fat"
codegen-units = 1
+55
View File
@@ -0,0 +1,55 @@
type Num = usize;
fn main() {
let mut sum = 0;
let mut i = 5;
'outer: loop {
if i > 333_333_334 {
break;
}
let a = i;
if a % 2 == 0 {
i += 1;
continue;
}
for c in [a - 1, a + 1] {
let t = Triangle::new(a, c);
if t.has_integer_area() {
println!("{:.10}, {:.10}", t.a, t.c);
sum += t.perimeter();
i = ((i as f64) * 3.59).trunc() as usize;
continue 'outer;
}
}
i += 1;
}
println!("{sum:.15}");
}
struct Triangle {
a: Num,
c: Num,
}
impl Triangle {
fn new(a: Num, c: Num) -> Self {
Self { a, c }
}
fn perimeter(&self) -> Num {
2 * self.a + self.c
}
fn has_integer_area(&self) -> bool {
let h = 4 * self.a.pow(2) - self.c.pow(2);
let root = (h as f64).sqrt().trunc() as usize;
root * root == h
}
}
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "euler95"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dev-dependencies]
rstest = "0.17"
[profile.release]
debug = true
lto = "fat"
+118
View File
@@ -0,0 +1,118 @@
use std::collections::HashSet;
const MAX: usize = 1_000_000;
fn main() {
let mut chains = vec![];
let mut part_of_any_chain = HashSet::new();
for current in 1..MAX {
if part_of_any_chain.contains(&current) {
continue;
}
try_build_chain_from_number(MAX, current, &mut chains, &mut part_of_any_chain);
}
chains.sort_by_key(|chain| chain.len());
let longest = chains.last().unwrap();
let smallest = longest.iter().min().unwrap().to_owned();
println!("{smallest}");
}
fn build_proper_divisors(max: usize) -> Vec<Vec<usize>> {
todo!()
}
fn try_build_chain_from_number(
max: usize,
mut current: usize,
chains: &mut Vec<Vec<usize>>,
part_of_any_chain: &mut HashSet<usize>,
) {
let mut maybe_chain = vec![];
loop {
maybe_chain.push(current);
let next: usize = get_proper_divisors(current).into_iter().sum();
if next > max || next == 0 {
break;
}
if maybe_chain.contains(&next) {
if maybe_chain.len() > 1 && *maybe_chain.first().unwrap() == next {
for number in &maybe_chain {
part_of_any_chain.insert(*number);
}
println!("{}", maybe_chain.first().unwrap());
chains.push(maybe_chain);
}
break;
}
current = next;
}
}
fn get_proper_divisors(x: usize) -> Vec<usize> {
let mut result = vec![1];
let limit = x / 2 + 1;
for i in 2..limit {
if result.contains(&i) {
break;
}
if x % i == 0 {
let div_1 = i;
let div_2 = x / i;
result.push(div_1);
if div_2 != div_1 {
result.push(div_2);
}
}
}
result.sort_unstable();
result
}
#[cfg(test)]
mod tests {
use rstest::rstest;
#[rstest]
#[case(6, vec![1, 2, 3])]
#[case(28, vec![1, 2, 4, 7, 14])]
#[case(12_496, vec![1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248])]
fn proper_divisor(#[case] input: usize, #[case] expected: Vec<usize>) {
use crate::get_proper_divisors;
assert_eq!(get_proper_divisors(input), expected);
}
#[rstest]
#[case(220, vec![vec![220, 284]])]
#[case(12_496, vec![vec![12_496, 14_288, 15_472, 14_536, 14_264]])]
fn chain(#[case] input: usize, #[case] expected: Vec<Vec<usize>>) {
use std::collections::HashSet;
use crate::try_build_chain_from_number;
let max = expected.iter().flatten().max().unwrap().to_owned();
let mut part_of_any_chain = HashSet::new();
let mut chains = vec![];
try_build_chain_from_number(max, input, &mut chains, &mut part_of_any_chain);
assert_eq!(chains, expected);
}
}