use std::fs::File; use std::io::{self, BufRead}; use std::path::Path; use std::str::FromStr; // Define type aliases for clarity type SeedNumber = (i32, i32); type CategoryItem = (i32, i32, i32); type SeedNumbers = Vec; type Category = Vec; type Categories = Vec; fn read_lines

(filename: P) -> io::Result>> where P: AsRef, { let file = File::open(filename)?; Ok(io::BufReader::new(file).lines()) } fn parse_input(file_path: &str) -> io::Result<(SeedNumbers, Categories)> { let mut seeds_numbers = SeedNumbers::new(); let mut categories = Categories::new(); let mut current_category = Category::new(); let mut is_seed_line = true; for line in read_lines(file_path)? { let line = line?; if line.is_empty() { if !current_category.is_empty() { categories.push(current_category); current_category = Category::new(); } is_seed_line = false; continue; } if is_seed_line { let seeds_ranges: Vec = line .split_whitespace() .skip(1) .filter_map(|s| i32::from_str(s).ok()) .collect(); for seeds in seeds_ranges.chunks(2) { if seeds.len() == 2 { seeds_numbers.extend((seeds[0]..seeds[0] + seeds[1]).map(|n| (n, n + 1))); } } } else { let numbers: Vec = line .split_whitespace() .filter_map(|s| i32::from_str(s).ok()) .collect(); if numbers.len() == 3 { current_category.push((numbers[0], numbers[1], numbers[2])); } } } if !current_category.is_empty() { categories.push(current_category); } Ok((seeds_numbers, categories)) } fn process_categories(mut seeds_numbers: SeedNumbers, categories: Categories) -> SeedNumbers { for category in categories { let mut sources = SeedNumbers::new(); while let Some((start, end)) = seeds_numbers.pop() { let mut is_mapped = false; for &(destination, source, length) in &category { let overlap_start = std::cmp::max(start, source); let overlap_end = std::cmp::min(end, source + length); if overlap_start < overlap_end { sources.push(( overlap_start - source + destination, overlap_end - source + destination, )); if overlap_start > start { seeds_numbers.push((start, overlap_start)); } if end > overlap_end { seeds_numbers.push((overlap_end, end)); } is_mapped = true; break; } } if !is_mapped { sources.push((start, end)); } } seeds_numbers = sources; } seeds_numbers } fn find_lowest_location(file_path: &str) -> io::Result { let (seeds_numbers, categories) = parse_input(file_path)?; let processed_seeds = process_categories(seeds_numbers, categories); let lowest_location = processed_seeds .iter() .map(|&(start, _)| start) .min() .unwrap(); Ok(lowest_location) } fn main() -> io::Result<()> { // Test let test_result = find_lowest_location("../test.txt")?; assert_eq!( test_result, 46, "Test failed. Expected 46, got {}", test_result ); println!("Test passed."); // Process actual input let result = find_lowest_location("../input.txt")?; println!("Total result from input.txt: {}", result); Ok(()) }