day 5 part 2
This commit is contained in:
parent
4437121bb0
commit
22ee9226c2
3 changed files with 192 additions and 26 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -35,6 +35,7 @@ dependencies = [
|
|||
"bit-vec",
|
||||
"chumsky",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"paste",
|
||||
]
|
||||
|
||||
|
@ -79,6 +80,12 @@ dependencies = [
|
|||
"stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
@ -105,6 +112,15 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
|
|
|
@ -10,4 +10,5 @@ ariadne = "0.3"
|
|||
bit-vec = "0.6"
|
||||
chumsky = "0.9"
|
||||
indexmap = "2"
|
||||
itertools = "0.12"
|
||||
paste = "1"
|
||||
|
|
201
src/bin/day5.rs
201
src/bin/day5.rs
|
@ -3,29 +3,158 @@
|
|||
|
||||
use aoc23::read;
|
||||
use chumsky::{prelude::*, text::int};
|
||||
use itertools::Itertools as _;
|
||||
use std::{
|
||||
fmt::{self, Debug, Display},
|
||||
ops::{Add, Deref, DerefMut}
|
||||
};
|
||||
|
||||
struct Range {
|
||||
source_start: usize,
|
||||
target_start: usize,
|
||||
trait Newtype:
|
||||
Copy
|
||||
+ Debug
|
||||
+ Ord
|
||||
+ From<usize>
|
||||
+ Into<usize>
|
||||
+ Deref<Target = usize>
|
||||
+ DerefMut
|
||||
+ Display
|
||||
+ Add<usize, Output = Self>
|
||||
{
|
||||
}
|
||||
|
||||
macro_rules! newtype {
|
||||
($( struct $newtype:ident($inner:ident);)*) => {
|
||||
$(
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
struct $newtype($inner);
|
||||
|
||||
impl From<$inner> for $newtype {
|
||||
fn from(inner: $inner) -> Self {
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$newtype> for $inner {
|
||||
fn from(newtype: $newtype) -> Self {
|
||||
newtype.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for $newtype {
|
||||
type Target = $inner;
|
||||
|
||||
fn deref(&self) -> &$inner {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for $newtype {
|
||||
fn deref_mut(&mut self) -> &mut $inner {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for $newtype {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$inner> for $newtype {
|
||||
type Output = $newtype;
|
||||
|
||||
fn add(self, rhs: $inner) -> Self {
|
||||
Self(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Newtype for $newtype {}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
newtype! {
|
||||
struct Seed(usize);
|
||||
struct Soil(usize);
|
||||
struct Fertilizer(usize);
|
||||
struct Water(usize);
|
||||
struct Light(usize);
|
||||
struct Temperature(usize);
|
||||
struct Humidity(usize);
|
||||
struct Location(usize);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Range<S, T> {
|
||||
source_start: S,
|
||||
target_start: T,
|
||||
len: usize
|
||||
}
|
||||
|
||||
struct Map {
|
||||
ranges: Vec<Range>
|
||||
struct Map<S, T> {
|
||||
ranges: Vec<Range<S, T>>
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn get(&self, source: usize) -> usize {
|
||||
impl<S, T> Map<S, T>
|
||||
where
|
||||
S: Newtype,
|
||||
T: Newtype
|
||||
{
|
||||
fn get(&self, source: S) -> T {
|
||||
for r in &self.ranges {
|
||||
let Some(offset) = source.checked_sub(r.source_start) else {
|
||||
let Some(offset) = source.checked_sub(r.source_start.into()) else {
|
||||
continue;
|
||||
};
|
||||
if offset < r.len {
|
||||
return r.target_start + offset;
|
||||
return (r.target_start.into() + offset).into();
|
||||
}
|
||||
}
|
||||
|
||||
source
|
||||
source.into().into()
|
||||
}
|
||||
|
||||
fn get_range_impl(&self, start: S, len: usize) -> Vec<(T, usize)> {
|
||||
let mut result = Vec::new();
|
||||
for r in &self.ranges {
|
||||
let possible_start = start.max(r.source_start);
|
||||
let possible_end = (start + len).min(r.source_start + r.len);
|
||||
if possible_start < possible_end {
|
||||
let range = (
|
||||
r.target_start + (possible_start.into() - r.source_start.into()),
|
||||
possible_end.into() - possible_start.into()
|
||||
);
|
||||
// eprintln!("({start:?}, {len}) => {range:?} ({r:?}");
|
||||
result.push(range);
|
||||
|
||||
if start < possible_start {
|
||||
result.extend(
|
||||
self.get_range_impl(start, possible_start.into() - start.into())
|
||||
);
|
||||
}
|
||||
if (start + len) > possible_end {
|
||||
result.extend(self.get_range_impl(
|
||||
possible_end,
|
||||
start.into() + len - possible_end.into()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.is_empty() {
|
||||
result.push((start.into().into(), len));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn get_range(&self, (start, len): (S, usize)) -> Vec<(T, usize)> {
|
||||
let result = self.get_range_impl(start, len);
|
||||
|
||||
// for range in &result {
|
||||
// eprintln!("({start:?}, {len}) => {range:?}");
|
||||
// }
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
||||
|
@ -38,8 +167,8 @@ impl Map {
|
|||
ranges: ranges
|
||||
.into_iter()
|
||||
.map(|ints: Vec<String>| Range {
|
||||
source_start: ints[1].parse().unwrap(),
|
||||
target_start: ints[0].parse().unwrap(),
|
||||
source_start: ints[1].parse::<usize>().unwrap().into(),
|
||||
target_start: ints[0].parse::<usize>().unwrap().into(),
|
||||
len: ints[2].parse().unwrap()
|
||||
})
|
||||
.collect()
|
||||
|
@ -48,25 +177,27 @@ impl Map {
|
|||
}
|
||||
|
||||
struct Almanac {
|
||||
seeds: Vec<usize>,
|
||||
seed_to_soil: Map,
|
||||
soil_to_fertilizer: Map,
|
||||
fertilizer_to_water: Map,
|
||||
water_to_light: Map,
|
||||
light_to_temperature: Map,
|
||||
temperature_to_humidity: Map,
|
||||
humidity_to_location: Map
|
||||
seeds: Vec<Seed>,
|
||||
seed_to_soil: Map<Seed, Soil>,
|
||||
soil_to_fertilizer: Map<Soil, Fertilizer>,
|
||||
fertilizer_to_water: Map<Fertilizer, Water>,
|
||||
water_to_light: Map<Water, Light>,
|
||||
light_to_temperature: Map<Light, Temperature>,
|
||||
temperature_to_humidity: Map<Temperature, Humidity>,
|
||||
humidity_to_location: Map<Humidity, Location>
|
||||
}
|
||||
|
||||
impl Almanac {
|
||||
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
||||
fn parse_another_map<'a, P, T>(
|
||||
fn parse_another_map<'a, P, R, S, T>(
|
||||
parser: P,
|
||||
name: &'a str
|
||||
) -> impl Parser<char, (T, Map), Error = Simple<char>> + 'a
|
||||
) -> impl Parser<char, (R, Map<S, T>), Error = Simple<char>> + 'a
|
||||
where
|
||||
P: Parser<char, T, Error = Simple<char>> + 'a,
|
||||
T: 'a
|
||||
P: Parser<char, R, Error = Simple<char>> + 'a,
|
||||
R: 'a,
|
||||
S: Newtype + 'a,
|
||||
T: Newtype + 'a
|
||||
{
|
||||
parser
|
||||
.then_ignore(just(name))
|
||||
|
@ -78,8 +209,8 @@ impl Almanac {
|
|||
.ignore_then(int(10).separated_by(just(" ")))
|
||||
.map(|ints: Vec<String>| {
|
||||
ints.into_iter()
|
||||
.map(|int| int.parse().unwrap())
|
||||
.collect::<Vec<usize>>()
|
||||
.map(|int| int.parse::<usize>().unwrap().into())
|
||||
.collect::<Vec<Seed>>()
|
||||
})
|
||||
.then_ignore(just("\n\n"));
|
||||
let parser = parse_another_map(parser, "seed-to-soil").then_ignore(just("\n"));
|
||||
|
@ -152,5 +283,23 @@ fn main() -> anyhow::Result<()> {
|
|||
.unwrap();
|
||||
println!("{min_loc}");
|
||||
|
||||
let min_loc = almanac
|
||||
.seeds
|
||||
.iter()
|
||||
.copied()
|
||||
.tuples()
|
||||
.map(|(start, len)| (start, len.into()))
|
||||
.flat_map(|range| almanac.seed_to_soil.get_range(range))
|
||||
.flat_map(|range| almanac.soil_to_fertilizer.get_range(range))
|
||||
.flat_map(|range| almanac.fertilizer_to_water.get_range(range))
|
||||
.flat_map(|range| almanac.water_to_light.get_range(range))
|
||||
.flat_map(|range| almanac.light_to_temperature.get_range(range))
|
||||
.flat_map(|range| almanac.temperature_to_humidity.get_range(range))
|
||||
.flat_map(|range| almanac.humidity_to_location.get_range(range))
|
||||
.map(|(start, _)| start)
|
||||
.min()
|
||||
.unwrap();
|
||||
println!("{min_loc}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue