Generify day 19 over all pattern vectors
This commit is contained in:
parent
ca14b85812
commit
506eff857e
|
@ -3,18 +3,14 @@ extern crate test;
|
||||||
use aoc2020::common::*;
|
use aoc2020::common::*;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
enum Rule {
|
enum Rule {
|
||||||
Char(u8),
|
Char(u8),
|
||||||
And((usize, usize)),
|
And(Vec<usize>),
|
||||||
AndOr((usize, usize), (usize, usize)),
|
AndOr(Vec<usize>, Vec<usize>),
|
||||||
Or((usize, usize)),
|
Any(Vec<usize>),
|
||||||
Useless(usize), // just delegates to another rule and makes parsing annoying
|
Useless(usize), // just delegates to another rule and makes parsing annoying
|
||||||
// This is why you don’t change the requirements once the implementation is done. REEEEEE
|
Either(Vec<usize>, Vec<usize>),
|
||||||
Special8(usize, (usize, usize)),
|
|
||||||
Special11((usize, usize), (usize, usize, usize)),
|
|
||||||
// If Rule was a recursive struct, this could have been defined as And(first, And(second, third)), but alas
|
|
||||||
Triple((usize, usize, usize)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Parsed<'a> = (RuleSet, &'a str);
|
type Parsed<'a> = (RuleSet, &'a str);
|
||||||
|
@ -23,40 +19,38 @@ type Parsed<'a> = (RuleSet, &'a str);
|
||||||
struct RuleSet(Vec<Rule>);
|
struct RuleSet(Vec<Rule>);
|
||||||
|
|
||||||
impl RuleSet {
|
impl RuleSet {
|
||||||
|
fn and_combinations(&self, s: &str, rules: &[usize], start: usize) -> Vec<usize> {
|
||||||
|
if let Some(&rule) = rules.first() {
|
||||||
|
if s.len() <= start {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
self.matches(&s[start..], self.0[rule].clone())
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|i| self.and_combinations(s, &rules[1..], start + i).into_iter())
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
vec![start]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn matches(&self, s: &str, rule: Rule) -> Vec<usize> {
|
fn matches(&self, s: &str, rule: Rule) -> Vec<usize> {
|
||||||
if s.len() == 0 {
|
if s.len() == 0 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
match rule {
|
match rule {
|
||||||
Rule::Char(c) => (s.as_bytes().first() == Some(&c)).then(|| vec![1]).unwrap_or_else(Vec::new),
|
Rule::Char(c) => (s.as_bytes().first() == Some(&c)).then(|| vec![1]).unwrap_or_else(Vec::new),
|
||||||
Rule::And((r1, r2)) => self
|
Rule::And(v) => self.and_combinations(s, v.as_slice(), 0),
|
||||||
.matches(s, self.0[r1])
|
Rule::AndOr(v1, v2) => self
|
||||||
|
.matches(s, Rule::And(v1))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|i| self.matches(&s[i..], self.0[r2]).into_iter().map(move |j| i + j))
|
.chain(self.matches(s, Rule::And(v2)))
|
||||||
.collect(),
|
.collect(),
|
||||||
Rule::AndOr((r1, r2), (r3, r4)) => self
|
Rule::Any(v) => v.into_iter().flat_map(|r| self.matches(s, self.0[r].clone())).collect(),
|
||||||
.matches(s, Rule::And((r1, r2)))
|
Rule::Useless(r) => self.matches(s, self.0[r].clone()),
|
||||||
.into_iter()
|
Rule::Either(first, second) => self
|
||||||
.chain(self.matches(s, Rule::And((r3, r4))))
|
|
||||||
.collect(),
|
|
||||||
Rule::Or((r1, r2)) => self.matches(s, self.0[r1]).into_iter().chain(self.matches(s, self.0[r2])).collect(),
|
|
||||||
Rule::Useless(r) => self.matches(s, self.0[r]),
|
|
||||||
// part 2 shit below:
|
|
||||||
Rule::Special8(first, second) => self
|
|
||||||
.matches(s, self.0[first])
|
|
||||||
.into_iter()
|
|
||||||
.chain(self.matches(s, Rule::And(second)))
|
|
||||||
.collect(),
|
|
||||||
Rule::Special11(first, second) => self
|
|
||||||
.matches(s, Rule::And(first))
|
.matches(s, Rule::And(first))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(self.matches(s, Rule::Triple(second)))
|
.chain(self.matches(s, Rule::And(second)))
|
||||||
.collect(),
|
|
||||||
Rule::Triple((r1, r2, r3)) => self
|
|
||||||
.matches(s, self.0[r1])
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|i| self.matches(&s[i..], self.0[r2]).into_iter().map(move |j| i + j))
|
|
||||||
.flat_map(|i| self.matches(&s[i..], self.0[r3]).into_iter().map(move |j| i + j))
|
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,12 +74,12 @@ fn parse_input<'a>(raw: &'a str) -> Parsed<'a> {
|
||||||
split
|
split
|
||||||
.clone()
|
.clone()
|
||||||
.next_tuple()
|
.next_tuple()
|
||||||
.map(|(a, b, c, d)| Rule::AndOr((a, b), (c, d)))
|
.map(|(a, b, c, d)| Rule::AndOr(vec![a, b], vec![c, d]))
|
||||||
.or_else(|| split.next_tuple().map(|(a, b)| Rule::Or((a, b))))
|
.or_else(|| split.next_tuple().map(|(a, b)| Rule::Any(vec![a, b])))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
chr if chr.contains('"') => Rule::Char(chr.bytes().skip_while(|&b| b != b'"').skip(1).next().unwrap()),
|
chr if chr.contains('"') => Rule::Char(chr.bytes().skip_while(|&b| b != b'"').skip(1).next().unwrap()),
|
||||||
and if and.contains(' ') => Rule::And(and.split(' ').map(|s| s.parse().unwrap()).next_tuple().unwrap()),
|
and if and.contains(' ') => Rule::And(and.split(' ').map(|s| s.parse().unwrap()).collect()),
|
||||||
useless => Rule::Useless(useless.parse().unwrap()),
|
useless => Rule::Useless(useless.parse().unwrap()),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -94,15 +88,21 @@ fn parse_input<'a>(raw: &'a str) -> Parsed<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1((rules, input): &Parsed) -> usize {
|
fn part1((rules, input): &Parsed) -> usize {
|
||||||
input.lines().filter(|l| rules.matches(l, rules.0[0]).contains(&l.len())).count()
|
input
|
||||||
|
.lines()
|
||||||
|
.filter(|l| rules.matches(l, rules.0[0].clone()).contains(&l.len()))
|
||||||
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(parsed: &Parsed) -> usize {
|
fn part2(parsed: &Parsed) -> usize {
|
||||||
let mut rules = parsed.0.clone();
|
let mut rules = parsed.0.clone();
|
||||||
rules.0[8] = Rule::Special8(42, (42, 8));
|
rules.0[8] = Rule::Either(vec![42], vec![42, 8]);
|
||||||
rules.0[11] = Rule::Special11((42, 31), (42, 11, 31));
|
rules.0[11] = Rule::Either(vec![42, 31], vec![42, 11, 31]);
|
||||||
dbg!(parsed.1.lines().map(|l| (l, rules.matches(l, rules.0[0]))).collect_vec());
|
parsed
|
||||||
parsed.1.lines().filter(|l| rules.matches(l, rules.0[0]).contains(&l.len())).count()
|
.1
|
||||||
|
.lines()
|
||||||
|
.filter(|l| rules.matches(l, rules.0[0].clone()).contains(&l.len()))
|
||||||
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user