You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
aoc2022/day3/src/main.rs

118 lines
2.7 KiB

#[macro_use] extern crate lazy_static;
use smallmap::{
Map,
smallmap,
};
use std::{
collections::BTreeSet,
};
use linebuffer::{
buf::forward,
TryFromBuf,
FromBuf,
ParsedLines,
};
use color_eyre::{
eyre::{
self, eyre,
WrapErr as _,
},
Help as _, SectionExt as _,
};
mod ext;
pub use ext::*;
fn init() -> eyre::Result<()>
{
color_eyre::install()
}
#[derive(Debug, Clone, PartialEq, Eq)] //TODO: implement PartialEq, Eq, PartialOrd, Ord via intersection between `full`s
struct Sack {
split_by: usize,
containers: Vec<BTreeSet<char>>,
full: smallmap::Set<char>, //TODO: When doing the above ^, change to BTreeSet for `intersection()`
}
impl Sack
{
/// Compute the intersection of each `N` part of the container
pub fn intersection(&self) -> impl Iterator<Item = char> + '_
{
self.containers.iter().take_two().flat_map(|(a, b)| b.map(move |b| (a, b)))
.map(|(a, b)| a.intersection(b)).flatten().copied()
}
}
#[inline]
fn read_input_from<R: std::io::Read>(input: R) -> ParsedLines<R, forward::FromStr<Sack>>
{
ParsedLines::new(input)
}
fn read_input() -> eyre::Result<ParsedLines<impl std::io::Read + 'static, forward::FromStr<Sack>>>
{
let reader = std::fs::OpenOptions::new()
.read(true)
.open("input")
.wrap_err("Failed to open input file for reading")?;
Ok(read_input_from(reader))
}
#[derive(Debug)]
pub struct SackParseError{
expected_div: usize,
size: usize,
}
impl std::str::FromStr for Sack
{
type Err = SackParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (first, second) = s.split_at(s.len()/2);
Ok(Self {
split_by: 2,
containers: vec![
first.chars().collect(),
second.chars().collect(),
],
full: s.chars().map(|a| (a, ())).collect(),
})
}
}
#[inline]
fn prop_swivle<'a>(sigh: impl IntoIterator<Item = char>+ 'a) -> impl Iterator<Item = usize> + 'a
{
lazy_static! {
static ref PMAP: Map<char, usize> = ('a'..='z').enumerate().map(|(i, n)| (i+1, n))
.chain (('A'..='Z').enumerate().map(|(i, n)| (i + 27, n)))
.map(|(i, n)| (n, i))
.collect();
}
sigh.into_iter().map(|ref ch| PMAP.get(ch)).flat_map(std::convert::identity).copied()
}
fn main() -> eyre::Result<()> {
init().wrap_err("Panic hook failed to install")?;
let mut input = read_input()?;
let mut psum = 0;
while let Some(sack) = input.try_next()
{
let sack = sack.expect("Failed to parse input line");
psum += prop_swivle(sack.intersection())
.sum::<usize>();
// TODO: part2: find sack.full's intersection through *all other* lines, up to two where the intersection is exactly 1 between all three. This is boring, I give up.
}
println!("{psum}");
Ok(())
}