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",
|
"bit-vec",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"itertools",
|
||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -79,6 +80,12 @@ dependencies = [
|
||||||
"stacker",
|
"stacker",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -105,6 +112,15 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.150"
|
version = "0.2.150"
|
||||||
|
|
|
@ -10,4 +10,5 @@ ariadne = "0.3"
|
||||||
bit-vec = "0.6"
|
bit-vec = "0.6"
|
||||||
chumsky = "0.9"
|
chumsky = "0.9"
|
||||||
indexmap = "2"
|
indexmap = "2"
|
||||||
|
itertools = "0.12"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
|
201
src/bin/day5.rs
201
src/bin/day5.rs
|
@ -3,29 +3,158 @@
|
||||||
|
|
||||||
use aoc23::read;
|
use aoc23::read;
|
||||||
use chumsky::{prelude::*, text::int};
|
use chumsky::{prelude::*, text::int};
|
||||||
|
use itertools::Itertools as _;
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Debug, Display},
|
||||||
|
ops::{Add, Deref, DerefMut}
|
||||||
|
};
|
||||||
|
|
||||||
struct Range {
|
trait Newtype:
|
||||||
source_start: usize,
|
Copy
|
||||||
target_start: usize,
|
+ 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
|
len: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Map {
|
struct Map<S, T> {
|
||||||
ranges: Vec<Range>
|
ranges: Vec<Range<S, T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl<S, T> Map<S, T>
|
||||||
fn get(&self, source: usize) -> usize {
|
where
|
||||||
|
S: Newtype,
|
||||||
|
T: Newtype
|
||||||
|
{
|
||||||
|
fn get(&self, source: S) -> T {
|
||||||
for r in &self.ranges {
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
if offset < r.len {
|
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>> {
|
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
||||||
|
@ -38,8 +167,8 @@ impl Map {
|
||||||
ranges: ranges
|
ranges: ranges
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ints: Vec<String>| Range {
|
.map(|ints: Vec<String>| Range {
|
||||||
source_start: ints[1].parse().unwrap(),
|
source_start: ints[1].parse::<usize>().unwrap().into(),
|
||||||
target_start: ints[0].parse().unwrap(),
|
target_start: ints[0].parse::<usize>().unwrap().into(),
|
||||||
len: ints[2].parse().unwrap()
|
len: ints[2].parse().unwrap()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -48,25 +177,27 @@ impl Map {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Almanac {
|
struct Almanac {
|
||||||
seeds: Vec<usize>,
|
seeds: Vec<Seed>,
|
||||||
seed_to_soil: Map,
|
seed_to_soil: Map<Seed, Soil>,
|
||||||
soil_to_fertilizer: Map,
|
soil_to_fertilizer: Map<Soil, Fertilizer>,
|
||||||
fertilizer_to_water: Map,
|
fertilizer_to_water: Map<Fertilizer, Water>,
|
||||||
water_to_light: Map,
|
water_to_light: Map<Water, Light>,
|
||||||
light_to_temperature: Map,
|
light_to_temperature: Map<Light, Temperature>,
|
||||||
temperature_to_humidity: Map,
|
temperature_to_humidity: Map<Temperature, Humidity>,
|
||||||
humidity_to_location: Map
|
humidity_to_location: Map<Humidity, Location>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Almanac {
|
impl Almanac {
|
||||||
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
|
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,
|
parser: P,
|
||||||
name: &'a str
|
name: &'a str
|
||||||
) -> impl Parser<char, (T, Map), Error = Simple<char>> + 'a
|
) -> impl Parser<char, (R, Map<S, T>), Error = Simple<char>> + 'a
|
||||||
where
|
where
|
||||||
P: Parser<char, T, Error = Simple<char>> + 'a,
|
P: Parser<char, R, Error = Simple<char>> + 'a,
|
||||||
T: 'a
|
R: 'a,
|
||||||
|
S: Newtype + 'a,
|
||||||
|
T: Newtype + 'a
|
||||||
{
|
{
|
||||||
parser
|
parser
|
||||||
.then_ignore(just(name))
|
.then_ignore(just(name))
|
||||||
|
@ -78,8 +209,8 @@ impl Almanac {
|
||||||
.ignore_then(int(10).separated_by(just(" ")))
|
.ignore_then(int(10).separated_by(just(" ")))
|
||||||
.map(|ints: Vec<String>| {
|
.map(|ints: Vec<String>| {
|
||||||
ints.into_iter()
|
ints.into_iter()
|
||||||
.map(|int| int.parse().unwrap())
|
.map(|int| int.parse::<usize>().unwrap().into())
|
||||||
.collect::<Vec<usize>>()
|
.collect::<Vec<Seed>>()
|
||||||
})
|
})
|
||||||
.then_ignore(just("\n\n"));
|
.then_ignore(just("\n\n"));
|
||||||
let parser = parse_another_map(parser, "seed-to-soil").then_ignore(just("\n"));
|
let parser = parse_another_map(parser, "seed-to-soil").then_ignore(just("\n"));
|
||||||
|
@ -152,5 +283,23 @@ fn main() -> anyhow::Result<()> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{min_loc}");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue