161 lines
4.0 KiB
Rust
161 lines
4.0 KiB
Rust
use std::collections::HashMap;
|
|
use std::fs;
|
|
|
|
#[derive(Debug)]
|
|
struct Range {
|
|
input: usize,
|
|
output: usize,
|
|
offset: usize,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Map {
|
|
ranges: Vec<Range>,
|
|
next: String,
|
|
}
|
|
|
|
fn parse() -> Option<(Vec<usize>, HashMap<String, Map>)> {
|
|
// 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<usize> = vec![];
|
|
let mut maps: HashMap<String, Map> = 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::<usize>().unwrap())
|
|
.collect::<Vec<_>>()
|
|
.iter()
|
|
.for_each(|s| seeds.push(*s));
|
|
}
|
|
_ => {
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
|
|
_ => {
|
|
return None;
|
|
}
|
|
}
|
|
|
|
for seg in &segments[1..] {
|
|
let mut ranges: Vec<Range> = 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::<Vec<_>>();
|
|
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::<usize>().unwrap())
|
|
.collect::<Vec<_>>();
|
|
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<String, Map>) -> 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<usize>, maps: &HashMap<String, Map>) {
|
|
let mut s: Vec<usize> = 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<usize>, maps: HashMap<String, Map>) {
|
|
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::<Vec<_>>();
|
|
|
|
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);
|
|
}
|