215 lines
6.1 KiB
Rust
215 lines
6.1 KiB
Rust
#![feature(iter_array_chunks)]
|
|
|
|
// use std::thread;
|
|
use std::collections::HashMap;
|
|
use std::fs;
|
|
use std::thread;
|
|
// use iterchunks::IterChunk
|
|
|
|
#[derive(Clone)]
|
|
struct RangePart {
|
|
dest_start: i64,
|
|
source_start: i64,
|
|
length: i64,
|
|
}
|
|
|
|
impl RangePart {
|
|
fn contains(&self, val: i64) -> bool {
|
|
return self.source_start <= val && val < self.source_start + self.length;
|
|
}
|
|
|
|
fn get(&self, val: i64) -> i64 {
|
|
if !self.contains(val) {
|
|
return val;
|
|
}
|
|
|
|
let delta = self.source_start - self.dest_start;
|
|
|
|
return val - delta;
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct RangeMap {
|
|
parts: Vec<RangePart>,
|
|
}
|
|
|
|
impl RangeMap {
|
|
fn new(parts: Vec<RangePart>) -> RangeMap {
|
|
RangeMap { parts }
|
|
}
|
|
|
|
fn get(&self, val: i64) -> i64 {
|
|
for range in self.parts.iter() {
|
|
if range.contains(val.clone()) {
|
|
return range.get(val.clone());
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
}
|
|
|
|
fn min_loc(maps: HashMap<&str, RangeMap>, seeds: Vec<i64>) -> i64 {
|
|
let mut min_location: i64 = i64::MAX;
|
|
|
|
for seed in seeds.iter() {
|
|
let soil = maps["seed-to-soil"].get(*seed);
|
|
let fertilizer = maps["soil-to-fertilizer"].get(soil);
|
|
let water = maps["fertilizer-to-water"].get(fertilizer);
|
|
let light = maps["water-to-light"].get(water);
|
|
let temperature = maps["light-to-temperature"].get(light);
|
|
let humidity = maps["temperature-to-humidity"].get(temperature);
|
|
let location = maps["humidity-to-location"].get(humidity);
|
|
|
|
if location < min_location {
|
|
min_location = location
|
|
}
|
|
}
|
|
|
|
return min_location;
|
|
}
|
|
|
|
fn min_loc_threads(maps: HashMap<&str, RangeMap>, seeds: &Vec<i64>, threads: usize) -> i64 {
|
|
// let maps = maps.clone();
|
|
// let seeds = seeds.clone();
|
|
thread::scope(|s| -> i64 {
|
|
let mut children = vec![];
|
|
for chunk in seeds.chunks(seeds.len() / threads) {
|
|
let maps = maps.clone();
|
|
let chunk = chunk.clone();
|
|
children.push(s.spawn(|| -> i64 { min_loc(maps, chunk.to_vec()) }));
|
|
}
|
|
|
|
children
|
|
.into_iter()
|
|
.map(|c| -> i64 { c.join().unwrap() })
|
|
.min()
|
|
.unwrap()
|
|
})
|
|
}
|
|
|
|
fn main() {
|
|
// let file_contents = fs::read_to_string("sample.txt").expect("No input found");
|
|
let file_contents = fs::read_to_string("input.txt").expect("No input found");
|
|
let mut lines = file_contents.lines();
|
|
|
|
// let start = 1;
|
|
// let len = 2;
|
|
// let r = (start..start+len).collect();
|
|
|
|
let mut windows = lines
|
|
.next()
|
|
.expect("No line found")
|
|
.strip_prefix("seeds: ")
|
|
.expect("No seeds prefix")
|
|
.split_whitespace()
|
|
.map(|value| {
|
|
value
|
|
.parse::<i64>()
|
|
.expect(format!("Expected value to be an int but got : {}", value).as_str())
|
|
})
|
|
.array_chunks::<2>()
|
|
.map(|r| vec![r[0], r[0] + r[1]])
|
|
.collect::<Vec<Vec<i64>>>();
|
|
|
|
windows.sort_by(|a, b| a[0].cmp(&b[0]));
|
|
|
|
let mut merged_windows: Vec<Vec<i64>> = Vec::new();
|
|
merged_windows.push(windows[0].clone());
|
|
|
|
for i in 1..windows.len() {
|
|
let j: usize = merged_windows.len() - 1;
|
|
if windows[i][0] > merged_windows.last().unwrap()[1] {
|
|
merged_windows.push(windows[i].clone());
|
|
continue;
|
|
}
|
|
if windows[i][1] > merged_windows.last().unwrap()[1] {
|
|
merged_windows[j][1] = windows[i][1];
|
|
}
|
|
}
|
|
|
|
let seeds = merged_windows
|
|
.iter()
|
|
.map(|r| {
|
|
// println!("range {} to {}", r[0], r[1]);
|
|
(r[0]..r[1]).collect::<Vec<i64>>()
|
|
})
|
|
.flatten()
|
|
.collect::<Vec<i64>>();
|
|
|
|
/*
|
|
* let seed_set: HashSet<&i64> = HashSet::from_iter(seeds.iter());
|
|
* println!("seeds {}", seed_set.len());
|
|
*/
|
|
|
|
let mut maps: HashMap<&str, RangeMap> = HashMap::new();
|
|
let mut map_name = "";
|
|
let mut ranges: Vec<RangePart> = vec![];
|
|
|
|
for line in lines.map(|l| l.trim()) {
|
|
if line == "" {
|
|
if map_name != "" {
|
|
maps.insert(map_name, RangeMap::new(ranges));
|
|
map_name = "";
|
|
ranges = vec![];
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if map_name == "" {
|
|
map_name = line.split_whitespace().next().unwrap();
|
|
// println!("map {}", map_name);
|
|
continue;
|
|
}
|
|
|
|
let mut parts = line.split_whitespace();
|
|
let dest_start = parts.next().unwrap().parse::<i64>().unwrap();
|
|
let source_start = parts.next().unwrap().parse::<i64>().unwrap();
|
|
let length = parts.next().unwrap().parse::<i64>().unwrap();
|
|
|
|
ranges.push(RangePart {
|
|
dest_start,
|
|
source_start,
|
|
length,
|
|
});
|
|
// println!("adding range {} {} {}", dest_start, source_start, length)
|
|
}
|
|
maps.insert(map_name, RangeMap::new(ranges));
|
|
|
|
/*
|
|
* let mut min_location: i64 = i64::MAX;
|
|
* for seed in seeds.iter() {
|
|
* let soil = maps["seed-to-soil"].get(*seed);
|
|
* let fertilizer = maps["soil-to-fertilizer"].get(soil);
|
|
* let water = maps["fertilizer-to-water"].get(fertilizer);
|
|
* let light = maps["water-to-light"].get(water);
|
|
* let temperature = maps["light-to-temperature"].get(light);
|
|
* let humidity = maps["temperature-to-humidity"].get(temperature);
|
|
* let location = maps["humidity-to-location"].get(humidity);
|
|
*
|
|
* if location < min_location {
|
|
* min_location = location
|
|
* }
|
|
*
|
|
* #<{(|
|
|
* * println!(
|
|
* * "Seed {} to soil {} to fertilizer {} to water {} to light {} to temperature {} to humidity {} to location {}",
|
|
* * seed,
|
|
* * soil,
|
|
* * fertilizer,
|
|
* * water,
|
|
* * light,
|
|
* * temperature,
|
|
* * humidity,
|
|
* * location,
|
|
* * )
|
|
* |)}>#
|
|
* }
|
|
*/
|
|
|
|
let min_location = min_loc_threads(maps, &seeds, 4);
|
|
|
|
println!("answer {}", min_location);
|
|
}
|