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) }