Adds Day 5 solution 1.
This commit is contained in:
176
src/days/day5.rs
Normal file
176
src/days/day5.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
use std::{path::Path, str::FromStr};
|
||||
|
||||
use crate::{error::AdventError, input::read_into};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RangeMap {
|
||||
start: u32,
|
||||
dest: u32,
|
||||
length: u32,
|
||||
}
|
||||
|
||||
impl RangeMap {
|
||||
fn map(self: &Self, input: u32) -> Option<u32> {
|
||||
let upper_bound: u64 = self.start as u64 + self.length as u64;
|
||||
if input >= self.start && (input as u64) < upper_bound {
|
||||
Some(input - self.start + self.dest)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Mapping {
|
||||
range_maps: Vec<RangeMap>
|
||||
}
|
||||
|
||||
impl Mapping {
|
||||
fn map(self: &Self, input: u32) -> u32 {
|
||||
for range_map in self.range_maps.iter() {
|
||||
match range_map.map(input) {
|
||||
Some(x) => return x,
|
||||
None => continue
|
||||
}
|
||||
}
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Almanac {
|
||||
seeds: Vec<u32>,
|
||||
seed_to_soil_map: Mapping,
|
||||
soil_to_fertilizer_map: Mapping,
|
||||
fertilizer_to_water_map: Mapping,
|
||||
water_to_light_map: Mapping,
|
||||
light_to_temperature_map: Mapping,
|
||||
temperature_to_humidity_map: Mapping,
|
||||
humidity_to_location_map: Mapping
|
||||
}
|
||||
|
||||
impl Almanac {
|
||||
fn new() -> Self {
|
||||
Almanac {
|
||||
seeds: vec![],
|
||||
seed_to_soil_map: Mapping{range_maps: vec![] },
|
||||
soil_to_fertilizer_map: Mapping{range_maps: vec![] },
|
||||
fertilizer_to_water_map: Mapping{range_maps: vec![] },
|
||||
water_to_light_map: Mapping{range_maps: vec![] },
|
||||
light_to_temperature_map: Mapping{range_maps: vec![] },
|
||||
temperature_to_humidity_map: Mapping{range_maps: vec![] },
|
||||
humidity_to_location_map: Mapping{range_maps: vec![] },
|
||||
}
|
||||
}
|
||||
|
||||
fn find_closest(self: &Self) -> u32 {
|
||||
let total_mapping = vec![
|
||||
&self.seed_to_soil_map,
|
||||
&self.soil_to_fertilizer_map,
|
||||
&self.fertilizer_to_water_map,
|
||||
&self.water_to_light_map,
|
||||
&self.light_to_temperature_map,
|
||||
&self.temperature_to_humidity_map,
|
||||
&self.humidity_to_location_map
|
||||
];
|
||||
self.seeds.clone().into_iter().map(|seed| {
|
||||
total_mapping
|
||||
.iter()
|
||||
.fold(seed, | input, map| {
|
||||
map.map(input)
|
||||
})
|
||||
}).min().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
enum State {
|
||||
None,
|
||||
SeedToSoil,
|
||||
SoilToFertilizer,
|
||||
FertilizerToWater,
|
||||
WaterToLight,
|
||||
LightToTemperature,
|
||||
TemperatureToHumidity,
|
||||
HumidityToLocation,
|
||||
}
|
||||
|
||||
impl FromStr for Almanac {
|
||||
type Err = AdventError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
const SEEDS_HEADER: &'static str = "seeds: ";
|
||||
const SEED_TO_SOIL_MAP_HEADER: &'static str = "seed-to-soil map:";
|
||||
const SOIL_TO_FERTILIZER_MAP_HEADER: &'static str = "soil-to-fertilizer map:";
|
||||
const FERTILIZER_TO_WATER_MAP_HEADER: &'static str = "fertilizer-to-water map:";
|
||||
const WATER_TO_LIGHT_MAP_HEADER: &'static str = "water-to-light map:";
|
||||
const LIGHT_TO_TEMPERATURE_MAP_HEADER: &'static str = "light-to-temperature map:";
|
||||
const TEMPERATURE_TO_HUMIDITY_MAP_HEADER: &'static str = "temperature-to-humidity map:";
|
||||
const HUMIDITY_TO_LOCATION_MAP_HEADER: &'static str = "humidity-to-location map:";
|
||||
|
||||
let mut almanac = Almanac::new();
|
||||
let mut state = State::None;
|
||||
|
||||
for line in s.lines() {
|
||||
if line.trim().is_empty() { continue; }
|
||||
|
||||
if line.starts_with(SEEDS_HEADER) {
|
||||
almanac.seeds = line
|
||||
.trim()
|
||||
.split_ascii_whitespace()
|
||||
.skip(1)
|
||||
.map(|s| -> Result<u32, AdventError> {
|
||||
Ok(s.trim().parse::<u32>()?)
|
||||
}).collect::<Result<Vec<u32>, AdventError>>()?;
|
||||
continue;
|
||||
}
|
||||
|
||||
if !match line.trim() {
|
||||
SEED_TO_SOIL_MAP_HEADER => { state = State::SeedToSoil; true }
|
||||
SOIL_TO_FERTILIZER_MAP_HEADER => { state = State::SoilToFertilizer; true }
|
||||
FERTILIZER_TO_WATER_MAP_HEADER => { state = State::FertilizerToWater; true }
|
||||
WATER_TO_LIGHT_MAP_HEADER => { state = State::WaterToLight; true }
|
||||
LIGHT_TO_TEMPERATURE_MAP_HEADER => { state = State::LightToTemperature; true }
|
||||
TEMPERATURE_TO_HUMIDITY_MAP_HEADER => { state = State::TemperatureToHumidity; true }
|
||||
HUMIDITY_TO_LOCATION_MAP_HEADER => { state = State::HumidityToLocation; true }
|
||||
_ => false
|
||||
} {
|
||||
let mapping = line
|
||||
.trim()
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| -> Result<u32, AdventError> {
|
||||
Ok(s.parse::<u32>()?)
|
||||
}).collect::<Result<Vec<u32>, AdventError>>()?;
|
||||
let range_map = RangeMap {
|
||||
dest: mapping[0],
|
||||
start: mapping[1],
|
||||
length: mapping[2]
|
||||
};
|
||||
|
||||
match state {
|
||||
State::None => Err(AdventError("Not in any state".into())),
|
||||
State::SeedToSoil => Ok(almanac.seed_to_soil_map.range_maps.push(range_map)),
|
||||
State::SoilToFertilizer => Ok(almanac.soil_to_fertilizer_map.range_maps.push(range_map)),
|
||||
State::FertilizerToWater => Ok(almanac.fertilizer_to_water_map.range_maps.push(range_map)),
|
||||
State::WaterToLight => Ok(almanac.water_to_light_map.range_maps.push(range_map)),
|
||||
State::LightToTemperature => Ok(almanac.light_to_temperature_map.range_maps.push(range_map)),
|
||||
State::TemperatureToHumidity => Ok(almanac.temperature_to_humidity_map.range_maps.push(range_map)),
|
||||
State::HumidityToLocation => Ok(almanac.humidity_to_location_map.range_maps.push(range_map)),
|
||||
}?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(almanac)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn one() -> Result<u32, AdventError>
|
||||
{
|
||||
let almanac = read_into::<Almanac>(Path::new("resources/input5.txt".into()))?;
|
||||
Ok(almanac.find_closest())
|
||||
}
|
||||
|
||||
pub fn two() -> Result<u32, AdventError>
|
||||
{
|
||||
Ok(0)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod day1;
|
||||
pub mod day2;
|
||||
pub mod day3;
|
||||
pub mod day4;
|
||||
pub mod day4;
|
||||
pub mod day5;
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{io::{BufReader, BufRead}, fs::File, str::FromStr, path::{Path, PathBuf}};
|
||||
use std::{io::{BufReader, BufRead, Read}, fs::File, str::FromStr, path::{Path, PathBuf}};
|
||||
|
||||
use crate::error::AdventError;
|
||||
|
||||
@@ -8,4 +8,13 @@ pub fn read_into_vec<T:FromStr>(file_path : &Path) -> Result<Vec<T>, AdventError
|
||||
let file = File::open(path).expect("no such file");
|
||||
let buf = BufReader::new(file);
|
||||
buf.lines().map(|line| T::from_str(line?.as_str()).map_err(Into::into)).collect::<Result<Vec<T>, AdventError>>()
|
||||
}
|
||||
|
||||
pub fn read_into<T:FromStr>(file_path: &Path) -> Result<T, AdventError> where AdventError: From<<T as FromStr>::Err> {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
path.push(file_path);
|
||||
let mut file = File::open(path).expect("no such file");
|
||||
let mut str: String = "".to_string();
|
||||
file.read_to_string(&mut str)?;
|
||||
Ok(T::from_str(str.as_str())?)
|
||||
}
|
||||
@@ -15,6 +15,7 @@ fn main() -> Result<(), AdventError> {
|
||||
(day2::one as fn() -> Result<u32, AdventError>, day2::two as fn() -> Result<u32, AdventError>),
|
||||
(day3::one as fn() -> Result<u32, AdventError>, day3::two as fn() -> Result<u32, AdventError>),
|
||||
(day4::one as fn() -> Result<u32, AdventError>, day4::two as fn() -> Result<u32, AdventError>),
|
||||
(day5::one as fn() -> Result<u32, AdventError>, day5::two as fn() -> Result<u32, AdventError>),
|
||||
];
|
||||
|
||||
if env::args().len() != 3 {
|
||||
|
||||
Reference in New Issue
Block a user