use std::time; use rayon::prelude::*; struct Almanac { seeds: Vec, seed_to_soil: Vec, soil_to_fertilizer: Vec, fertilizer_to_water: Vec, water_to_light:Vec, light_to_temperature: Vec, temperature_to_humidity: Vec, humidity_to_location: Vec, } impl Almanac { fn new() -> Almanac { Almanac { seeds: Vec::new(), seed_to_soil: Vec::new(), soil_to_fertilizer: Vec::new(), fertilizer_to_water: Vec::new(), water_to_light: Vec::new(), light_to_temperature: Vec::new(), temperature_to_humidity: Vec::new(), humidity_to_location: Vec::new(), } } fn get_soil(&self, seed: u32) -> u32 { map(seed, &self.seed_to_soil) } fn get_fertilizer(&self, seed: u32) -> u32 { map(self.get_soil(seed), &self.soil_to_fertilizer) } fn get_water(&self, seed: u32) -> u32 { map(self.get_fertilizer(seed), &self.fertilizer_to_water) } fn get_light(&self, seed: u32) -> u32 { map(self.get_water(seed), &self.water_to_light) } fn get_temperature(&self, seed: u32) -> u32 { map(self.get_light(seed), &self.light_to_temperature) } fn get_humidity(&self, seed: u32) -> u32 { map(self.get_temperature(seed), &self.temperature_to_humidity) } fn get_location(&self, seed: u32) -> u32 { map(self.get_humidity(seed), &self.humidity_to_location) } } struct Mapping { dst_range_start: u64, src_range_start: u64, range_length: u64 } fn main() { let s = time::Instant::now(); let almanac = load_input(); let mut locations: Vec = Vec::new(); // for seed in &almanac.seeds { // let location = almanac.get_location(*seed); // locations.push(location); // println!("Seed: {}", seed); // println!("Location: {}", location); // println!(); // } // println!("Lowest location #1: {}", locations.iter().min().unwrap()); // locations.clear(); let mut seeds = almanac.seeds.iter(); loop { let seed_start = seeds.next().unwrap_or(&0); if *seed_start == 0 { break; } let seed_end = seed_start + seeds.next().unwrap(); let seed_count = seed_end - seed_start; let s1 = time::Instant::now(); let locs = (*seed_start..seed_end).into_par_iter().map(|seed| { almanac.get_location(seed) }); locations.push(locs.min().unwrap()); let d1 = time::Instant::now().duration_since(s1); println!("Parsed {} seeds in {:?} ({} seeds/s)", seed_count, d1, seed_count as f64 / d1.as_secs_f64()); } let d = time::Instant::now().duration_since(s); println!("Parsed in {:?}", d); println!("Lowest location #2: {}", locations.iter().min().unwrap()); } fn load_input() -> Almanac { let mut almanac = Almanac::new(); let data = std::fs::read_to_string("src/bin/part05.txt") .expect("Could not read file"); let mut lines = data.lines(); almanac.seeds = lines.next().unwrap().split(": ").last().unwrap().split_whitespace().map(|s| s.parse::().unwrap()).collect::>(); almanac.seed_to_soil = parse_map(&mut lines); almanac.soil_to_fertilizer = parse_map(&mut lines); almanac.fertilizer_to_water = parse_map(&mut lines); almanac.water_to_light = parse_map(&mut lines); almanac.light_to_temperature = parse_map(&mut lines); almanac.temperature_to_humidity = parse_map(&mut lines); almanac.humidity_to_location = parse_map(&mut lines); almanac } fn parse_map(line_iter: &mut dyn Iterator) -> Vec { let mut mappings = Vec::new(); line_iter.nth(0); loop { let line = line_iter.next().unwrap_or(""); if line.is_empty() { break; } else if line.ends_with(":") { continue; } let mut raw_mapping = line.split_whitespace(); mappings.push(Mapping { dst_range_start: raw_mapping.next().unwrap().parse::().unwrap(), src_range_start: raw_mapping.next().unwrap().parse::().unwrap(), range_length: raw_mapping.next().unwrap().parse::().unwrap() }); } mappings.sort_by(|a, b| b.src_range_start.cmp(&a.src_range_start)); mappings } fn map(src: u32, mappings: &Vec) -> u32 { let src = src as u64; let mut dst = src; let mapping = mappings.iter().find(|mapping| { src >= mapping.src_range_start && src < mapping.src_range_start + mapping.range_length }); if let Some(mapping) = mapping { dst = (mapping.dst_range_start + src) - mapping.src_range_start; } dst as u32 }