diff --git a/day7/Cargo.toml b/day7/Cargo.toml new file mode 100644 index 0000000..3812153 --- /dev/null +++ b/day7/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day7" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +generational-arena = "0.2.8" diff --git a/day7/src/bag.rs b/day7/src/bag.rs new file mode 100644 index 0000000..3ce43fc --- /dev/null +++ b/day7/src/bag.rs @@ -0,0 +1,103 @@ +use std::{ + mem, + ops, + hash::{Hash, Hasher,}, +}; +use generational_arena::{ + Arena, + Index, +}; + +#[derive(Debug, Clone, Eq)] +pub struct Bag +{ + name: String, + contains: Vec, +} + +impl Hash for Bag { + #[inline] fn hash(&self, state: &mut H) { + self.as_ref().hash(state) + } +} + +impl PartialEq for Bag +where T: AsRef +{ + fn eq(&self, other: &T) -> bool + { + self.as_ref() == other.as_ref() + } +} + +impl Bag +{ + pub fn new(name: String) -> Self + { + Self { + name, + contains: Vec::new(), + } + } + pub fn push_contents(&mut self, idx: Index) + { + self.contains.push(idx) + } + pub fn bags_in<'a>(&'a self, w: &'a Arena) -> impl Iterator + 'a + { + self.contains.iter().filter_map(move |x| w.get(x.clone())).map(Self::as_ref) + } + pub fn contains_in(&self, w: &Arena, bag: impl AsRef) -> bool + { + for x in self.bags_in(w) + { + if x == bag.as_ref() { + return true; + } + } + false + } + +} + +impl AsRef for Bag +{ + #[inline] fn as_ref(&self) -> &BagRef + { + BagRef::new_unchecked(&self.name[..]) + } +} + +impl ops::Deref for Bag +{ + type Target = BagRef; + #[inline] fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct BagRef +{ + name: str +} + +impl AsRef for BagRef +{ + #[inline] fn as_ref(&self) -> &BagRef + { + self + } +} + + +impl BagRef +{ + #[inline] fn new_unchecked<'a>(from: &'a str) -> &'a BagRef + { + unsafe { + mem::transmute(from) + } + } +} diff --git a/day7/src/main.rs b/day7/src/main.rs new file mode 100644 index 0000000..1c0436f --- /dev/null +++ b/day7/src/main.rs @@ -0,0 +1,10 @@ +#![feature(str_split_once)] + +#![allow(dead_code)] + +mod parse; +mod bag; + +fn main() { + println!("Hello, world!"); +} diff --git a/day7/src/parse.rs b/day7/src/parse.rs new file mode 100644 index 0000000..4d7ac98 --- /dev/null +++ b/day7/src/parse.rs @@ -0,0 +1,109 @@ +use std::{ + io::{ + self, BufRead, + }, + sync::{ + mpsc, + }, + thread, + marker::*, + collections::{HashMap, HashSet,}, +}; +use generational_arena::{ + Arena, Index, +}; +use super::bag; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct Rule +{ + contents: Vec<(usize, String)>, +} + +fn parse_rest(from: mpsc::Receiver) -> HashMap +{ + let mut out = HashMap::new(); + while let Ok(line) = from.recv() { + + } + out +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct UnlinkedBag<'a> +{ + name: &'a str, + cont: Rule, +} + +enum MaybeLinked<'a> +{ + Unlinked(UnlinkedBag<'a>), + Linked(bag::Bag), +} + +pub fn parse(from: R) -> Result, io::Error> +{ + let mut all_possible = HashSet::::new(); + let (tx, rx) = mpsc::channel(); + let w = thread::spawn(move || parse_rest(rx)); + + macro_rules! unwrap { + (? $opt:expr) => { + match $opt { + Some(v) => v, + _ => continue, + } + }; + ($res:expr) => { + unwrap!(? $res.ok()) + } + } + for line in from.lines() + { + let mut line = line?; + + let irest = { + const SPLIT: &str = "bags contain"; + let bn = { + let idx = unwrap!(? line.find(SPLIT)); + &line[..idx] + }; + all_possible.insert(bn.trim().to_owned()); + }; + unwrap!(tx.send(line)); + } + let (mut unlinked, nref) = { + let mut ulinks = w.join().unwrap(); + let mut unlinked = Arena::with_capacity(all_possible.len()); + let mut nref = HashMap::new(); + for name in all_possible.iter() + { + let urule = ulinks.remove(name).unwrap(); + let idx = unlinked.insert(MaybeLinked::Unlinked(UnlinkedBag{name, cont: urule})); + nref.insert(name, idx); + } + (unlinked, nref) + }; + + let indecies: Vec<_> = unlinked.iter().map(|(i, _)| i).collect(); + for idx in indecies.into_iter() + { + let current = unlinked.get_mut(idx).unwrap(); + let linked = match current { + MaybeLinked::Unlinked(UnlinkedBag{name, cont: rule}) => { + let mut linking = bag::Bag::new(name.to_owned()); + for (_, cont) in rule.contents.iter() { + linking.push_contents(*nref.get(cont).unwrap()); + } + linking + }, + _=> continue, + }; + *current = MaybeLinked::Linked(linked); + } + + //TODO: how tf can we convert from Arena> into Arena<_>????? + + todo!() +}