commit e8fb670ee5bcbb21f4bcb3dbb63aec89f769aac5 Author: Thomas de Gruijter Date: Tue Dec 2 18:45:40 2025 +0100 day 2 diff --git a/past-solutions/2-1.rs b/past-solutions/2-1.rs new file mode 100644 index 0000000..7b56a01 --- /dev/null +++ b/past-solutions/2-1.rs @@ -0,0 +1,120 @@ +use std::io::Read; +use std::iter; +use std::num::{NonZero, NonZeroU32}; + +fn main() { + let mut problem = parse_problem(); + + println!("Parsed problem: {:?}", problem); + + println!("Count in total: {}", compute_problem(&mut problem)) +} + +#[derive(Debug)] +struct Problem{ + ranges: Vec<(u64, u64)> +} + +#[derive(Debug)] +struct CleanedProblem{ + ranges: Vec<(u64, u64, NonZeroU32)> +} + +fn parse_problem() -> Problem { + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).expect("Failed to read input"); + + let ranges = input.split(','). + map(|x| x.split_once('-').expect("dash in there")) + .map(|x| (x.0.parse::().expect("Parse error on 0"), x.1.parse::().expect("Parse error on 1"))) + .collect::>(); + + return Problem{ + ranges, + }; +} + +fn compute_problem(problem: &mut Problem) -> u64 { + //Potentialy ensure it is not overlapping + let problem = clean_problem(problem); + + println!("Cleaned problem: {:?}", problem); + + let count = problem.ranges.iter().map(|range| compute_range(range.0, range.1)).sum::(); + + return count; +} + +fn clean_problem(problem: &Problem) -> CleanedProblem { + let new_ranges = problem.ranges.iter().map(|(lower, upper)|{ + if (upper < lower){ + return vec![] + } + + let digitCountU = count_digits(*upper); + let digitCountL = count_digits(*lower); + + if (digitCountL == digitCountU){ + return vec![(*lower, *upper, digitCountU)]; + } + + let lowestOfDegree = lowestOfDegree(digitCountU); + + return vec![(*lower, lowestOfDegree-1, digitCountL), (lowestOfDegree, *upper, digitCountU)]; + }).flatten().collect::>(); + + return CleanedProblem{ranges: new_ranges}; +} + +fn lowestOfDegree(degree : NonZeroU32) -> u64{ + 10u64.pow(degree.get() - 1) +} + +fn compute_range(lower_bound: u64, upper_bound: u64) -> u64 { + assert!(lower_bound > 0 && upper_bound > 0); + assert!(upper_bound > lower_bound); + assert!(count_digits(upper_bound) == count_digits(lower_bound)); + + let digitCount = count_digits(upper_bound); + + if digitCount.get() % 2 != 0{ + return 0; + } + + + let halfDigitCount = NonZeroU32::new(digitCount.get() / 2).unwrap(); + + + + let mut half = (lower_bound / 10u64.pow(halfDigitCount.get())).min(lower_bound % 10u64.pow(halfDigitCount.get())); + let mut count = 0; + + loop{ + let whole = combine_numbers(half, halfDigitCount); + if whole >= lower_bound && whole <= upper_bound{ + count += whole; + }else if whole > upper_bound{ + break; + } + + half += 1; + } + + return count; +} + +fn count_digits(mut n : u64) -> NonZeroU32{ + assert!(n > 0); + let mut count = 0u64; + + while (n != 0){ + n = n / 10; + count +=1 ; + } + + return unsafe{NonZeroU32::new_unchecked(count as u32)}; +} + +fn combine_numbers(half : u64, degree : NonZeroU32) -> u64 { + return half + half * 10u64.pow(degree.get() as u32) +} \ No newline at end of file diff --git a/past-solutions/2-2.rs b/past-solutions/2-2.rs new file mode 100644 index 0000000..9d08ac8 --- /dev/null +++ b/past-solutions/2-2.rs @@ -0,0 +1,114 @@ +use std::collections::HashSet; +use std::io::Read; +use std::iter; +use std::num::{NonZero, NonZeroU32, NonZeroU64}; +use rayon::prelude::*; + +fn main() { + let mut problem = parse_problem(); + + println!("Count in total: {}", compute_problem(&mut problem)) +} + +#[derive(Debug)] +struct Problem{ + ranges: Vec<(u64, u64)> +} + +#[derive(Debug)] +struct CleanedProblem{ + ranges: Vec<(u64, u64, NonZeroU32)> +} + +fn parse_problem() -> Problem { + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).expect("Failed to read input"); + + let ranges = input.split(','). + map(|x| x.split_once('-').expect("dash in there")) + .map(|x| (x.0.parse::().expect("Parse error on 0"), x.1.parse::().expect("Parse error on 1"))) + .collect::>(); + + return Problem{ + ranges, + }; +} + +fn compute_problem(problem: &mut Problem) -> u64 { + //Potentialy ensure it is not overlapping + let problem = clean_problem(problem); + let count = problem.ranges.par_iter().map(|range| compute_range(range.0, range.1)).sum::(); + + return count; +} + +fn clean_problem(problem: &Problem) -> CleanedProblem { + let new_ranges = problem.ranges.iter().map(|(lower, upper)|{ + if (upper < lower){ + return vec![] + } + + let digitCountU = count_digits(*upper); + let digitCountL = count_digits(*lower); + + if (digitCountL == digitCountU){ + return vec![(*lower, *upper, digitCountU)]; + } + + let lowestOfDegree = lowest_of_degree(digitCountU); + + return vec![(*lower, lowestOfDegree-1, digitCountL), (lowestOfDegree, *upper, digitCountU)]; + }).flatten().collect::>(); + + return CleanedProblem{ranges: new_ranges}; +} + +fn lowest_of_degree(degree : NonZeroU32) -> u64{ + 10u64.pow(degree.get() - 1) +} + +fn compute_range(lower_bound: u64, upper_bound: u64) -> u64 { + + let digitCount = count_digits(lower_bound); + + (lower_bound..=upper_bound).map(|i|{ + if is_combination(i) { + Some(i) + }else{ + None + } + }).flatten().sum() +} + +fn count_digits(mut n : u64) -> NonZeroU32{ + let mut count = 0u64; + + while (n != 0){ + n = n / 10; + count +=1 ; + } + + return unsafe{NonZeroU32::new_unchecked(count as u32)}; +} + +fn is_combination(n: u64) -> bool { + let digit_count = count_digits(n).get(); + + (1..=digit_count) + .filter(|count| digit_count % count == 0) + .filter(|count| *count <= digit_count/ 2) + .any(|count| { + let mask = 10u64.pow(count as u32); + let block = n % mask; + + let mut x = n; + while x > 0 { + if x % mask != block { + return false; + } + x /= mask; + } + true + }) +} + diff --git a/rust-workspace/.gitignore b/rust-workspace/.gitignore new file mode 100644 index 0000000..185ca35 --- /dev/null +++ b/rust-workspace/.gitignore @@ -0,0 +1,3 @@ +/target + +.idea diff --git a/rust-workspace/Cargo.lock b/rust-workspace/Cargo.lock new file mode 100644 index 0000000..59ae180 --- /dev/null +++ b/rust-workspace/Cargo.lock @@ -0,0 +1,61 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rust-workspace" +version = "0.1.0" +dependencies = [ + "rayon", +] diff --git a/rust-workspace/Cargo.toml b/rust-workspace/Cargo.toml new file mode 100644 index 0000000..20fa284 --- /dev/null +++ b/rust-workspace/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust-workspace" +version = "0.1.0" +edition = "2024" + +[dependencies] +rayon = "1.11.0" diff --git a/rust-workspace/input.txt b/rust-workspace/input.txt new file mode 100644 index 0000000..71d0e89 --- /dev/null +++ b/rust-workspace/input.txt @@ -0,0 +1 @@ +9595822750-9596086139,1957-2424,88663-137581,48152-65638,12354817-12385558,435647-489419,518494-609540,2459-3699,646671-688518,195-245,295420-352048,346-514,8686839668-8686892985,51798991-51835611,8766267-8977105,2-17,967351-995831,6184891-6331321,6161577722-6161678622,912862710-913019953,6550936-6625232,4767634976-4767662856,2122995-2257010,1194-1754,779-1160,22-38,4961-6948,39-53,102-120,169741-245433,92902394-92956787,531-721,64-101,15596-20965,774184-943987,8395-11781,30178-47948,94338815-94398813 \ No newline at end of file diff --git a/rust-workspace/src/main.rs b/rust-workspace/src/main.rs new file mode 100644 index 0000000..9d08ac8 --- /dev/null +++ b/rust-workspace/src/main.rs @@ -0,0 +1,114 @@ +use std::collections::HashSet; +use std::io::Read; +use std::iter; +use std::num::{NonZero, NonZeroU32, NonZeroU64}; +use rayon::prelude::*; + +fn main() { + let mut problem = parse_problem(); + + println!("Count in total: {}", compute_problem(&mut problem)) +} + +#[derive(Debug)] +struct Problem{ + ranges: Vec<(u64, u64)> +} + +#[derive(Debug)] +struct CleanedProblem{ + ranges: Vec<(u64, u64, NonZeroU32)> +} + +fn parse_problem() -> Problem { + let mut input = String::new(); + std::io::stdin().read_to_string(&mut input).expect("Failed to read input"); + + let ranges = input.split(','). + map(|x| x.split_once('-').expect("dash in there")) + .map(|x| (x.0.parse::().expect("Parse error on 0"), x.1.parse::().expect("Parse error on 1"))) + .collect::>(); + + return Problem{ + ranges, + }; +} + +fn compute_problem(problem: &mut Problem) -> u64 { + //Potentialy ensure it is not overlapping + let problem = clean_problem(problem); + let count = problem.ranges.par_iter().map(|range| compute_range(range.0, range.1)).sum::(); + + return count; +} + +fn clean_problem(problem: &Problem) -> CleanedProblem { + let new_ranges = problem.ranges.iter().map(|(lower, upper)|{ + if (upper < lower){ + return vec![] + } + + let digitCountU = count_digits(*upper); + let digitCountL = count_digits(*lower); + + if (digitCountL == digitCountU){ + return vec![(*lower, *upper, digitCountU)]; + } + + let lowestOfDegree = lowest_of_degree(digitCountU); + + return vec![(*lower, lowestOfDegree-1, digitCountL), (lowestOfDegree, *upper, digitCountU)]; + }).flatten().collect::>(); + + return CleanedProblem{ranges: new_ranges}; +} + +fn lowest_of_degree(degree : NonZeroU32) -> u64{ + 10u64.pow(degree.get() - 1) +} + +fn compute_range(lower_bound: u64, upper_bound: u64) -> u64 { + + let digitCount = count_digits(lower_bound); + + (lower_bound..=upper_bound).map(|i|{ + if is_combination(i) { + Some(i) + }else{ + None + } + }).flatten().sum() +} + +fn count_digits(mut n : u64) -> NonZeroU32{ + let mut count = 0u64; + + while (n != 0){ + n = n / 10; + count +=1 ; + } + + return unsafe{NonZeroU32::new_unchecked(count as u32)}; +} + +fn is_combination(n: u64) -> bool { + let digit_count = count_digits(n).get(); + + (1..=digit_count) + .filter(|count| digit_count % count == 0) + .filter(|count| *count <= digit_count/ 2) + .any(|count| { + let mask = 10u64.pow(count as u32); + let block = n % mask; + + let mut x = n; + while x > 0 { + if x % mask != block { + return false; + } + x /= mask; + } + true + }) +} + diff --git a/rust-workspace/test_input.txt b/rust-workspace/test_input.txt new file mode 100644 index 0000000..bd04584 --- /dev/null +++ b/rust-workspace/test_input.txt @@ -0,0 +1 @@ +11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124 \ No newline at end of file