Day 5
This commit is contained in:
150
src/bin/day05.rs
Normal file
150
src/bin/day05.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Range {
|
||||
start: i64,
|
||||
end: i64,
|
||||
}
|
||||
|
||||
impl Range {
|
||||
fn new(start: i64, end: i64) -> Range {
|
||||
Range {
|
||||
start: start.min(end),
|
||||
end: end.max(start),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_start_size(start: i64, size: i64) -> Range {
|
||||
Range {
|
||||
start,
|
||||
end: start + size,
|
||||
}
|
||||
}
|
||||
|
||||
fn intersects(&self, other: &Range) -> bool {
|
||||
!(self.end <= other.start || other.end <= self.start)
|
||||
}
|
||||
|
||||
fn intersect(&self, other: &Range) -> Option<Range> {
|
||||
if self.intersects(other) {
|
||||
Some(Range::new(
|
||||
self.start.max(other.start),
|
||||
self.end.min(other.end),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn contains(&self, value: i64) -> bool {
|
||||
self.start <= value && value <= self.end
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
offset: i64,
|
||||
range: Range,
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
fn new(dest: i64, start: i64, size: i64) -> Entry {
|
||||
Entry {
|
||||
offset: dest - start,
|
||||
range: Range::from_start_size(start, size),
|
||||
}
|
||||
}
|
||||
|
||||
fn translate(&self, value: i64) -> Option<i64> {
|
||||
if self.range.contains(value) {
|
||||
Some(value + self.offset)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let filename = env::args()
|
||||
.nth(1)
|
||||
.context("./day03 <path to puzzle input>")?;
|
||||
let input = fs::read_to_string(filename)?;
|
||||
|
||||
let mut sections = input.split("\n\n");
|
||||
|
||||
let seeds = sections
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(' ')
|
||||
.skip(1)
|
||||
.map(|w| w.parse::<i64>().unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let maps = sections
|
||||
.map(|mp| {
|
||||
mp.lines()
|
||||
.skip(1)
|
||||
.map(|line| {
|
||||
let mut l = line.split(' ').map(|v| v.parse::<i64>().unwrap());
|
||||
|
||||
let dest = l.next().unwrap();
|
||||
let start = l.next().unwrap();
|
||||
let size = l.next().unwrap();
|
||||
|
||||
Entry::new(dest, start, size)
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect::<Vec<Vec<_>>>();
|
||||
|
||||
let convert =
|
||||
|value, map: &Vec<Entry>| map.iter().find_map(|m| m.translate(value)).unwrap_or(value);
|
||||
let find_location = |&seed| maps.iter().fold(seed, convert);
|
||||
let part1 = seeds.iter().map(find_location).min().unwrap();
|
||||
|
||||
let mut inputs = Vec::new();
|
||||
let mut outputs = Vec::new();
|
||||
let mut rests = Vec::new();
|
||||
|
||||
let mut chunked = seeds.chunks(2);
|
||||
while let Some(&[start, size]) = chunked.next() {
|
||||
inputs.push(Range::from_start_size(start, size));
|
||||
}
|
||||
|
||||
for map in maps.iter() {
|
||||
for map_section in map.iter() {
|
||||
for range in inputs.iter() {
|
||||
if let Some(intersection) = map_section.range.intersect(&range) {
|
||||
outputs.push(Range::new(
|
||||
intersection.start + map_section.offset,
|
||||
intersection.end + map_section.offset,
|
||||
));
|
||||
|
||||
if range.start < map_section.range.start {
|
||||
rests.push(Range::new(range.start, map_section.range.start));
|
||||
}
|
||||
|
||||
if map_section.range.end < range.end {
|
||||
rests.push(Range::new(map_section.range.end, range.end))
|
||||
}
|
||||
} else {
|
||||
rests.push(range.clone());
|
||||
}
|
||||
}
|
||||
|
||||
inputs.clear();
|
||||
inputs.append(&mut rests);
|
||||
}
|
||||
|
||||
inputs.append(&mut outputs);
|
||||
}
|
||||
|
||||
let part2 = inputs.into_iter().map(|range| range.start).min().unwrap();
|
||||
|
||||
println!("1) {}", part1);
|
||||
println!("2) {}", part2);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user