day 5 finished

This commit is contained in:
Dylan Thies
2023-12-06 22:18:41 -05:00
parent 1051b9812e
commit e21503ed71
3 changed files with 460 additions and 8 deletions

View File

@@ -1,18 +1,196 @@
#![warn(clippy::all, clippy::pedantic)]
#[must_use] pub fn part1(_input: &str) -> String {
"Not Finished".to_string()
use nom::{
bytes::complete::tag,
character::complete,
combinator::opt,
multi::separated_list1,
sequence::{separated_pair, terminated, tuple},
IResult,
};
use std::str::FromStr;
#[derive(Debug, PartialEq, Eq)]
struct ParseTypeError;
#[derive(Debug, PartialEq, Clone, Copy)]
enum Type {
Seed,
Soil,
Fertilizer,
Water,
Light,
Temperature,
Humidity,
Location,
}
impl FromStr for Type {
type Err = ParseTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"seed" => Ok(Self::Seed),
"soil" => Ok(Self::Soil),
"fertilizer" => Ok(Self::Fertilizer),
"water" => Ok(Self::Water),
"light" => Ok(Self::Light),
"temperature" => Ok(Self::Temperature),
"humidity" => Ok(Self::Humidity),
"location" => Ok(Self::Location),
_ => Err(ParseTypeError),
}
}
}
#[derive(Debug)]
struct ItemMapEntry {
pub to: u64,
pub from: u64,
pub count: u64,
}
impl ItemMapEntry {
fn to_out(&self, from: u64) -> Option<u64> {
if from < self.from || self.from + self.count < from {
None
} else {
Some(self.to + (from - self.from))
}
}
}
#[derive(Debug)]
struct ItemMap {
pub from_type: Type,
pub to_type: Type,
pub mapping: Vec<ItemMapEntry>,
}
impl ItemMap {
fn map(&self, from: u64) -> u64 {
self.mapping
.iter()
.find_map(|x| x.to_out(from))
.or(Some(from))
.expect("always")
}
}
#[must_use]
pub fn part1(input: &str) -> String {
let (_input, (mut to_process, maps)) = parse_input(input).expect("aoc always has input");
//println!("{_input}");
let mut from_type = Type::Seed;
while from_type != Type::Location {
let current_map = maps
.iter()
.find(|x| x.from_type == from_type)
.expect("should always find");
to_process = to_process
.iter()
.map(|x| current_map.map(*x))
.collect::<Vec<_>>();
//println!("{to_process:#?}");
from_type = current_map.to_type;
}
//println!("{to_process:#?}");
to_process
.iter()
.min()
.expect("always a number")
.to_string()
}
fn parse_item_map_entry(input: &str) -> IResult<&str, ItemMapEntry> {
let (input, to) = complete::u64(input)?;
let (input, _) = complete::space1(input)?;
let (input, from) = complete::u64(input)?;
let (input, _) = complete::space1(input)?;
let (input, count) = complete::u64(input)?;
Ok((input, ItemMapEntry { to, from, count }))
}
fn parse_to_from(input: &str) -> IResult<&str, (Type, Type)> {
let (input, (to_type, from_type)) =
separated_pair(complete::alpha1, tag("-to-"), complete::alpha1)(input)?;
Ok((
input,
(
to_type.parse().expect("there will be a to type"),
from_type.parse().expect("there will be a from type"),
),
))
}
fn parse_map(input: &str) -> IResult<&str, ItemMap> {
let (input, (from_type, to_type)) =
terminated(parse_to_from, tuple((complete::space1, tag("map:"))))(input)?;
let (input, _) = complete::line_ending(input)?;
let (input, mapping) = separated_list1(complete::line_ending, parse_item_map_entry)(input)?;
let (input, _) = opt(complete::line_ending)(input)?;
Ok((
input,
ItemMap {
from_type,
to_type,
mapping,
},
))
}
fn parse_seeds(input: &str) -> IResult<&str, Vec<u64>> {
let (input, _) = tag("seeds:")(input)?;
let (input, _) = complete::space1(input)?;
separated_list1(complete::space1, complete::u64)(input)
}
fn parse_input(input: &str) -> IResult<&str, (Vec<u64>, Vec<ItemMap>)> {
let (input, seeds) = terminated(parse_seeds, complete::line_ending)(input)?;
let (input, _) = complete::line_ending(input)?;
let (input, maps) = separated_list1(complete::line_ending, parse_map)(input)?;
Ok((input, (seeds, maps)))
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "";
const INPUT: &str = "seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4";
#[test]
fn part1_works() {
let result = part1(INPUT);
assert_eq!(result, "Not Finished".to_string());
assert_eq!(result, "35".to_string());
}
}

View File

@@ -1,18 +1,277 @@
#![warn(clippy::all, clippy::pedantic)]
#[must_use] pub fn part2(_input: &str) -> String {
"Not Finished".to_string()
use core::ops::Range;
use itertools::Itertools;
use nom::{
bytes::complete::tag,
character::complete,
combinator::opt,
multi::separated_list1,
sequence::{separated_pair, terminated, tuple},
IResult,
};
use std::str::FromStr;
#[derive(Debug, PartialEq, Eq)]
struct ParseTypeError;
#[derive(Debug, PartialEq, Clone, Copy)]
enum Type {
Seed,
Soil,
Fertilizer,
Water,
Light,
Temperature,
Humidity,
Location,
}
impl FromStr for Type {
type Err = ParseTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"seed" => Ok(Self::Seed),
"soil" => Ok(Self::Soil),
"fertilizer" => Ok(Self::Fertilizer),
"water" => Ok(Self::Water),
"light" => Ok(Self::Light),
"temperature" => Ok(Self::Temperature),
"humidity" => Ok(Self::Humidity),
"location" => Ok(Self::Location),
_ => Err(ParseTypeError),
}
}
}
#[derive(Debug)]
struct ItemMapEntry {
pub to: Range<u64>,
pub from: Range<u64>,
}
#[derive(Debug)]
struct ItemMap {
pub from_type: Type,
pub to_type: Type,
pub mapping: Vec<ItemMapEntry>,
}
impl ItemMap {
fn input_to_output(&self, input: &Range<u64>) -> Vec<Range<u64>> {
/*if let Some(within) = self
.mapping
.iter()
.find(|x| x.from.contains(&input.start) && x.from.contains(&input.end))
{
//fully contained
let offset = input.start - within.from.start;
let to_start = within.to.start + offset;
let to_end = to_start + u64::abs_diff(input.end, input.start);
if to_start == 0 {
println!("{input:#?}");
}
return vec![to_start..to_end];
}*/
let mut output = Vec::new();
let mut input = input.start..input.end;
loop {
input =
if let Some(within) = self.mapping.iter().find(|x| x.from.contains(&input.start)) {
//println!("front - {input:?} - {within:#?} - {:?}", self.from_type);
let (to_start, to_end) = if within.to.start > within.from.start {
let offset = within.to.start - within.from.start;
let end = if input.end + offset > within.to.end {
within.to.end
} else {
input.end + offset
};
(input.start + offset, end)
} else {
let offset = within.from.start - within.to.start;
let end = if input.end - offset > within.to.end {
within.to.end
} else {
input.end - offset
};
(input.start - offset, end)
};
output.push(to_start..to_end);
if input.end <= within.from.end {
break;
}
within.from.end..input.end
} else if let Some(within) = self
.mapping
.iter()
.find(|x| x.from.contains(&(input.end - 1)))
{
//println!("end - {input:?} - {within:#?} - {:?}", self.from_type);
let (to_start, to_end) = if within.to.start > within.from.start {
let offset = within.to.start - within.from.start;
let start = if input.start + offset < within.to.start {
within.to.start
} else {
input.start + offset
};
(start, input.end + offset)
} else {
let offset = within.from.start - within.to.start;
let start = if input.start + offset < within.to.start {
within.to.start
} else {
input.start + offset
};
(start, input.end - offset)
};
output.push(to_start..to_end);
if input.start >= within.from.start {
break;
}
input.start..within.from.start
} else {
//println!("else - {input:#?} - {:?}", self.from_type);
output.push(input.clone());
break;
};
}
output
}
}
#[must_use]
pub fn part2(input: &str) -> String {
let (_input, (mut to_process, maps)) = parse_input(input).expect("aoc always has input");
//println!("{_input}");
let mut from_type = Type::Seed;
while from_type != Type::Location {
let current_map = maps
.iter()
.find(|x| x.from_type == from_type)
.expect("should always find");
to_process = to_process
.iter()
.flat_map(|x| current_map.input_to_output(x))
.unique()
.collect::<Vec<_>>();
//println!("{to_process:#?}");
from_type = current_map.to_type;
}
//println!("{to_process:#?}");
to_process
.iter()
.map(|x| x.start)
.min()
.expect("always a number")
.to_string()
}
fn parse_item_map_entry(input: &str) -> IResult<&str, ItemMapEntry> {
let (input, to) = complete::u64(input)?;
let (input, _) = complete::space1(input)?;
let (input, from) = complete::u64(input)?;
let (input, _) = complete::space1(input)?;
let (input, count) = complete::u64(input)?;
Ok((
input,
ItemMapEntry {
to: to..(to + count),
from: from..(from + count),
},
))
}
fn parse_to_from(input: &str) -> IResult<&str, (Type, Type)> {
let (input, (to_type, from_type)) =
separated_pair(complete::alpha1, tag("-to-"), complete::alpha1)(input)?;
Ok((
input,
(
to_type.parse().expect("there will be a to type"),
from_type.parse().expect("there will be a from type"),
),
))
}
fn parse_map(input: &str) -> IResult<&str, ItemMap> {
let (input, (from_type, to_type)) =
terminated(parse_to_from, tuple((complete::space1, tag("map:"))))(input)?;
let (input, _) = complete::line_ending(input)?;
let (input, mapping) = separated_list1(complete::line_ending, parse_item_map_entry)(input)?;
let (input, _) = opt(complete::line_ending)(input)?;
Ok((
input,
ItemMap {
from_type,
to_type,
mapping,
},
))
}
fn parse_seed_range(input: &str) -> IResult<&str, Range<u64>> {
let (input, (seed, count)) =
separated_pair(complete::u64, complete::space1, complete::u64)(input)?;
Ok((input, seed..(seed + count)))
}
//TODO need to change so that it operates on the ranges and not on the actual numbers
fn parse_seeds(input: &str) -> IResult<&str, Vec<Range<u64>>> {
let (input, _) = tag("seeds:")(input)?;
let (input, _) = complete::space1(input)?;
separated_list1(complete::space1, parse_seed_range)(input)
//println!("{seed_ranges:?}");
}
fn parse_input(input: &str) -> IResult<&str, (Vec<Range<u64>>, Vec<ItemMap>)> {
let (input, seeds) = terminated(parse_seeds, complete::line_ending)(input)?;
let (input, _) = complete::line_ending(input)?;
let (input, maps) = separated_list1(complete::line_ending, parse_map)(input)?;
//println!("{seeds:?}");
Ok((input, (seeds, maps)))
}
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "";
const INPUT: &str = "seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4";
#[test]
fn part2_works() {
let result = part2(INPUT);
assert_eq!(result, "Not Finished".to_string());
assert_eq!(result, "46".to_string());
}
}