day7 parser

master
Avril 4 years ago
parent 2f29b13e7b
commit 2cdad0e0e6
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -6,5 +6,8 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
test = []
[dependencies] [dependencies]
generational-arena = "0.2.8" generational-arena = "0.2.8"

@ -1,103 +1,91 @@
use std::{ use std::{
mem,
ops,
hash::{Hash, Hasher,}, hash::{Hash, Hasher,},
collections::HashSet,
borrow::Borrow,
}; };
use generational_arena::{
Arena,
Index,
};
#[derive(Debug, Clone, Eq)] type Bags = HashSet<Rule>;
pub struct Bag type BagRef = String;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rule
{ {
name: String, bag: BagRef,
contains: Vec<Index>, contains: Vec<(usize, BagRef)>,
} }
impl Hash for Bag { impl Borrow<String> for Rule
#[inline] fn hash<H: Hasher>(&self, state: &mut H) { {
self.as_ref().hash(state) fn borrow(&self) -> &String {
&self.bag
} }
} }
impl<T> PartialEq<T> for Bag impl Hash for Rule {
where T: AsRef<BagRef> fn hash<H: Hasher>(&self, state: &mut H) {
{ self.bag.hash(state)
fn eq(&self, other: &T) -> bool
{
self.as_ref() == other.as_ref()
} }
} }
impl Bag impl Rule
{ {
pub fn new(name: String) -> Self #[inline] pub fn name(&self) -> &str
{ {
Self { &self.bag[..]
name,
contains: Vec::new(),
}
} }
pub fn push_contents(&mut self, idx: Index)
/// Find the rules for each inner bag within this context
pub fn inner_rules<'a>(&'a self, hashes: &'a Bags) -> impl Iterator<Item = &'a Rule> + 'a
{ {
self.contains.push(idx) self.contains.iter().filter_map(move |(_, re)| hashes.get(re))
} }
pub fn bags_in<'a>(&'a self, w: &'a Arena<Bag>) -> impl Iterator<Item = &'a BagRef> + 'a #[inline] pub fn new(bag: impl Into<String>, contains: impl IntoIterator<Item = (usize, String)>) -> Self
{ {
self.contains.iter().filter_map(move |x| w.get(x.clone())).map(Self::as_ref) return Self::new_ex(bag.into(), contains.into_iter().collect());
} }
pub fn contains_in(&self, w: &Arena<Bag>, bag: impl AsRef<BagRef>) -> bool pub fn new_ex(bag: String, contains: Vec<(usize, String)>) -> Self
{ {
for x in self.bags_in(w) Self {bag, contains}
{
if x == bag.as_ref() {
return true;
}
}
false
} }
} pub fn all_rules<'a>(&'a self, hashes: &'a Bags) -> RuleIterator<'a>
impl AsRef<BagRef> for Bag
{
#[inline] fn as_ref(&self) -> &BagRef
{ {
BagRef::new_unchecked(&self.name[..]) RuleIterator
} {
} base: self.contains.iter(),
hashes,
impl ops::Deref for Bag held: Vec::with_capacity(self.contains.len()),
{ }
type Target = BagRef;
#[inline] fn deref(&self) -> &Self::Target {
self.as_ref()
} }
} }
#[derive(Debug, PartialEq, Eq, Hash)] pub struct RuleIterator<'a>
#[repr(transparent)]
pub struct BagRef
{ {
name: str base: std::slice::Iter<'a, (usize, BagRef)>,
hashes: &'a Bags,
held: Vec<&'a Rule>,
} }
impl AsRef<BagRef> for BagRef impl<'a> Iterator for RuleIterator<'a>
{ {
#[inline] fn as_ref(&self) -> &BagRef type Item = &'a Rule;
fn next(&mut self) -> Option<Self::Item>
{ {
self if self.held.is_empty() {
match self.base.next() {
Some((_, re)) => {
self.held.push(self.hashes.get(re).unwrap());
},
None => return None,
}
}
let ret = self.held.remove(0);
self.held.extend(ret.inner_rules(self.hashes));
Some(ret)
} }
}
impl BagRef fn size_hint(&self) -> (usize, Option<usize>) {
{ (self.base.len(), None)
#[inline] fn new_unchecked<'a>(from: &'a str) -> &'a BagRef
{
unsafe {
mem::transmute(from)
}
} }
} }
impl<'a> std::iter::FusedIterator for RuleIterator<'a>{}

@ -2,9 +2,28 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::{
io::BufReader,
fs::OpenOptions,
collections::HashSet,
};
#[cfg(feature="test")]
const INPUT: &str ="input-test";
#[cfg(not(feature="test"))]
const INPUT: &str = "input";
mod parse; mod parse;
mod bag; mod bag;
fn main() { fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Hello, world!"); let parsed: HashSet<_> = parse::parse(BufReader::new(OpenOptions::new().read(true).open(INPUT)?)).collect();
#[cfg(debug_assertions)]
for x in parsed.iter() {
eprintln!("{:?}", x);
}
Ok(())
} }

@ -1,109 +1,48 @@
use std::{ use std::io::BufRead;
io::{
self, BufRead,
},
sync::{
mpsc,
},
thread,
marker::*,
collections::{HashMap, HashSet,},
};
use generational_arena::{
Arena, Index,
};
use super::bag; use super::bag;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] fn parse_rule(from: impl AsRef<str>) -> Option<bag::Rule>
struct Rule
{ {
contents: Vec<(usize, String)>, let from = from.as_ref();
} let mut ps = from.split("bag");
fn parse_rest(from: mpsc::Receiver<String>) -> HashMap<String, Rule> let name = ps.next()?.trim();
{ Some(bag::Rule::new(name, (0..).zip(ps).filter_map(|(i, s)| {
let mut out = HashMap::new(); let (n, s) = if i == 0 {
while let Ok(line) = from.recv() { const JUNK: &str = "s contain ";
} let (spec, rest) = (&s[JUNK.len()..]).split_once(char::is_whitespace).unwrap();
out let n: usize = match spec {
} "no" => 0,
x => x.parse().unwrap(),
#[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<R: BufRead>(from: R) -> Result<Arena<bag::Bag>, io::Error>
{
let mut all_possible = HashSet::<String>::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()); (n, rest.trim())
} else {
if s.contains(".") { return None; }
let s = if s.starts_with("s") {
&s[3..]
} else if s.starts_with(",") {
&s[2..]
} else {
s
}.trim();
//if s.starts_with(".") { return None; }
let (spec, rest) = s.split_once(char::is_whitespace).unwrap();
(spec.parse().unwrap(), rest.trim())
}; };
unwrap!(tx.send(line)); if n < 1 {
} None
let (mut unlinked, nref) = { } else {
let mut ulinks = w.join().unwrap(); Some((n, s.to_owned()))
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<MaybeLinked<_>> into Arena<_>?????
todo!() pub fn parse<R: BufRead>(buf: R) -> impl Iterator<Item = bag::Rule>
{
buf.lines().filter_map(|x| {
x.ok().map(parse_rule).flatten()
})
} }

Loading…
Cancel
Save