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
+31 -25
View File
@@ -13,39 +13,45 @@ fn main() {
squbes.iterate();
squbes.iterate();
squbes.iterate();
println!("{:?}", squbes.output());
println!("{:?}", squbes.get_output());
}
#[derive(Debug)]
struct Squbes {
squbes: HashSet<u64>,
new_squbes: Vec<u64>,
primes: IntoIter<u64>,
primes: Primes<u64>,
primes_iter: IntoIter<u64>,
used_primes: Vec<u64>,
current_prime: u64,
}
impl Squbes {
pub fn new(max: u64) -> Self {
let mut primes = Primes::get_between(2, max).into_vec().into_iter();
let first = primes.next().unwrap();
let second = primes.next().unwrap();
let primes = Primes::get_between(2, max);
let mut primes_iter = primes.to_cloned_iter();
let first = primes_iter.next().unwrap();
let second = primes_iter.next().unwrap();
Self {
squbes: HashSet::new(),
new_squbes: vec![],
primes,
primes_iter,
used_primes: vec![first],
current_prime: second,
}
}
pub fn iterate(&mut self) {
self.calculate_squbes_with_current_prime();
let squbes = self.calculate_squbes_with_current_prime();
self.save_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();
result.sort_unstable();
result
@@ -56,27 +62,27 @@ impl Squbes {
}
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) {
assert_ne!(self.current_prime, 0);
let iter = self
.used_primes
.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 calculate_squbes_with_current_prime(&mut self) -> Vec<u64> {
get_iterator_over_pairs_both_ways(&self.used_primes, self.current_prime)
.map(|(p, q)| Self::core(p, q))
.collect()
}
fn core(p: u64, q: u64) -> u64 {
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);
}
}