117 lines
4.3 KiB
Rust
117 lines
4.3 KiB
Rust
|
use std::fs::read_to_string;
|
||
|
use std::cmp;
|
||
|
use std::time::Instant;
|
||
|
|
||
|
fn get_numbers_in_line(str: &str) -> Vec<u32> {
|
||
|
return str.split_whitespace().filter_map(|substr| substr.parse::<u32>().ok()).collect();
|
||
|
}
|
||
|
|
||
|
fn process(seeds: Vec<u32>, mut maps: Vec<Vec<(u32, u32, u32)>>) -> (u32, u32) {
|
||
|
for map in maps.iter_mut() {
|
||
|
map.sort_unstable_by(|&(a, _, _), &(b, _, _)| a.partial_cmp(&b).unwrap());
|
||
|
}
|
||
|
// Task 1 - mapping a single number through all mappings
|
||
|
let min1 = seeds.iter().map(
|
||
|
|seed| {
|
||
|
let mut n = *seed;
|
||
|
for map in &maps {
|
||
|
for &(src, dst, len) in map {
|
||
|
if src > n {
|
||
|
break;
|
||
|
}
|
||
|
if n - src < len {
|
||
|
n = n - src + dst;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
n
|
||
|
}
|
||
|
).min().unwrap();
|
||
|
|
||
|
// Task 2 - mapping whole ranges through all mappings
|
||
|
// Array of ranges that will be mapped for task 2 initialized with pairs from seeds
|
||
|
let mut processed_ranges: Vec<_> = (0..seeds.len()).step_by(2).map(|i| (seeds[i], seeds[i + 1])).collect();
|
||
|
let mut swap_ranges: Vec<(u32, u32)> = Vec::new();
|
||
|
// Map the processed_ranged through all mappings
|
||
|
for map in &maps {
|
||
|
swap_ranges.clear();
|
||
|
for &(working_start, working_len) in &processed_ranges {
|
||
|
// Applying one or more mapping ranges to the processed range
|
||
|
let (mut temp_start, mut temp_len) = (working_start, working_len);
|
||
|
for &(src, dst, len) in map {
|
||
|
// Working range starts before mapping range, means it's an unmapped segment
|
||
|
if temp_start < src {
|
||
|
let out_len = cmp::min(temp_len, src - temp_start);
|
||
|
swap_ranges.push((temp_start, out_len));
|
||
|
if out_len == temp_len {
|
||
|
break;
|
||
|
}
|
||
|
temp_start = src;
|
||
|
}
|
||
|
// Working range is sure to not begin before mapping range
|
||
|
let start_diff = temp_start - src;
|
||
|
// Mapping range is so short that it doesn't reach the working range, skip
|
||
|
if len <= start_diff {
|
||
|
continue;
|
||
|
}
|
||
|
let out_len = cmp::min(temp_len, len - start_diff);
|
||
|
swap_ranges.push((dst + start_diff, out_len));
|
||
|
if out_len == temp_len {
|
||
|
break;
|
||
|
}
|
||
|
// Consume the beginning of the working range
|
||
|
temp_start += out_len;
|
||
|
temp_len -= out_len;
|
||
|
}
|
||
|
}
|
||
|
std::mem::swap(&mut processed_ranges, &mut swap_ranges);
|
||
|
}
|
||
|
// Find the range with lowest starting value, length is guaranteed to be nonzero
|
||
|
let min2 = processed_ranges.iter().map(|&(start, _)| start).min().unwrap();
|
||
|
(min1, min2)
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
let time_start = Instant::now();
|
||
|
// Set of inputs
|
||
|
let mut seeds: Vec<u32> = Vec::new();
|
||
|
// Mappings of ranges, ordered in order to easily find the lowest relevant range
|
||
|
// Order: (src, dst, len)
|
||
|
let mut maps: Vec<Vec<(u32, u32, u32)>> = Vec::new();
|
||
|
maps.push(Vec::new());
|
||
|
let mut did_read_seeds: bool = false;
|
||
|
for line in read_to_string("input.txt").unwrap().lines() {
|
||
|
if !did_read_seeds {
|
||
|
seeds = get_numbers_in_line(line);
|
||
|
did_read_seeds = true;
|
||
|
} else {
|
||
|
let numbers = get_numbers_in_line(line);
|
||
|
if numbers.len() == 3 {
|
||
|
maps.last_mut().unwrap().push((numbers[1],numbers[0], numbers[2]));
|
||
|
} else {
|
||
|
if !maps.last().unwrap().is_empty() {
|
||
|
maps.push(Vec::new());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if maps.last().unwrap().is_empty() {
|
||
|
maps.pop();
|
||
|
}
|
||
|
let time_start_no_io = Instant::now();
|
||
|
|
||
|
// for _ in 0..1000 {
|
||
|
// let (_, _) = process(seeds.clone(), maps.clone());
|
||
|
// }
|
||
|
let (min1, min2) = process(seeds, maps);
|
||
|
|
||
|
// Measurements
|
||
|
let elapsed = time_start.elapsed().as_nanos();
|
||
|
let elapsed_no_io = time_start_no_io.elapsed().as_nanos();
|
||
|
println!("Time: {}ns", elapsed);
|
||
|
println!("Time without file i/o: {}ns", elapsed_no_io);
|
||
|
println!("Min location1: {}", min1);
|
||
|
println!("Min location2: {}", min2);
|
||
|
}
|