use std::collections::HashMap; use std::fs; #[derive(Debug)] struct Range { input: usize, output: usize, offset: usize, } #[derive(Debug)] struct Map { ranges: Vec, next: String, } fn parse() -> Option<(Vec, HashMap)> { // let contents = fs::read_to_string("./day5.txt").expect("Don't find the file"); let contents = fs::read_to_string("./input.txt").expect("Don't find the file"); let mut seeds: Vec = vec![]; let mut maps: HashMap = HashMap::new(); let segments: Vec<&str> = contents.split("\n\n").collect(); match segments[..] { [s, ..] => { let segments: Vec<&str> = s.split(':').collect(); match segments[..] { [_, s] => { s.split_whitespace() .map(|x| x.parse::().unwrap()) .collect::>() .iter() .for_each(|s| seeds.push(*s)); } _ => { return None; } } } _ => { return None; } } for seg in &segments[1..] { let mut ranges: Vec = vec![]; let segments: Vec<&str> = seg.split('\n').collect(); let Some((names, r)) = segments.split_first() else { return None; }; let names = names.replace(' ', "-"); let split = names.split('-').collect::>(); let [name, _, next, _] = &split[..] else { return None; }; for range in r { if range.is_empty() { continue; } let split = range .split_whitespace() .map(|x| x.parse::().unwrap()) .collect::>(); match split[..] { [output, input, off] => ranges.push(Range { input, output, offset: off, }), _ => return None, } } maps.insert( name.to_string(), Map { ranges, next: next.to_string(), }, ); } // println!("Seeds : {:?}", seeds); // println!("Ranges : {:#?}", maps); Some((seeds, maps)) } fn check_range(seed: usize, map: &Map, maps: &HashMap) -> usize { for range in &map.ranges { let input = range.input; let output = range.output; let offset = range.offset; let min = input; let max = input + offset; if min <= seed && seed < max { let o = seed + output - input; let Some(m) = maps.get(&map.next) else { return o; }; return check_range(o, m, maps); } } let Some(m) = maps.get(&map.next) else { return seed; }; check_range(seed, m, maps) } fn puzzle1(seeds: &Vec, maps: &HashMap) { let mut s: Vec = vec![]; let map = maps.get("seed").unwrap(); for seed in seeds { s.push(check_range(*seed, map, maps)); } // println!(" Seeds → : {:?}", s); let min = s.iter().min().unwrap(); println!("Puzzle 1 : {:?}", min); } fn puzzle2(seeds: Vec, maps: HashMap) { let map = maps.get("seed").unwrap(); let ranges: Vec<_> = seeds .chunks(2) .map(|i| std::ops::Range { start: i[0], end: i[0] + i[1], }) .collect(); let min: Vec<_> = ranges .iter() .map(|range| { range .clone() .map(|r| check_range(r, map, &maps)) .min() .unwrap() }) .collect::>(); let min = min.iter().min().unwrap(); println!("Puzzle 2 : {:?}", min); } fn main() { let Some((seeds, maps)) = parse() else { panic!("Fail input parsing") }; puzzle1(&seeds, &maps); puzzle2(seeds, maps); }