Adds Day 5 solution 1.

This commit is contained in:
Dennis Brentjes
2023-12-06 11:10:20 +01:00
parent d721d0753e
commit 2946a6a212
5 changed files with 415 additions and 2 deletions

176
src/days/day5.rs Normal file
View 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)
}

View File

@@ -1,4 +1,5 @@
pub mod day1;
pub mod day2;
pub mod day3;
pub mod day4;
pub mod day4;
pub mod day5;

View File

@@ -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())?)
}

View File

@@ -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 {