2020: day19: part 2
This commit is contained in:
parent
fb9a7e3fc9
commit
c0b388dfa0
47
aoc2020/input/day19_provided2.txt
Normal file
47
aoc2020/input/day19_provided2.txt
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
42: 9 14 | 10 1
|
||||||
|
9: 14 27 | 1 26
|
||||||
|
10: 23 14 | 28 1
|
||||||
|
1: "a"
|
||||||
|
11: 42 31
|
||||||
|
5: 1 14 | 15 1
|
||||||
|
19: 14 1 | 14 14
|
||||||
|
12: 24 14 | 19 1
|
||||||
|
16: 15 1 | 14 14
|
||||||
|
31: 14 17 | 1 13
|
||||||
|
6: 14 14 | 1 14
|
||||||
|
2: 1 24 | 14 4
|
||||||
|
0: 8 11
|
||||||
|
13: 14 3 | 1 12
|
||||||
|
15: 1 | 14
|
||||||
|
17: 14 2 | 1 7
|
||||||
|
23: 25 1 | 22 14
|
||||||
|
28: 16 1
|
||||||
|
4: 1 1
|
||||||
|
20: 14 14 | 1 15
|
||||||
|
3: 5 14 | 16 1
|
||||||
|
27: 1 6 | 14 18
|
||||||
|
14: "b"
|
||||||
|
21: 14 1 | 1 14
|
||||||
|
25: 1 1 | 1 14
|
||||||
|
22: 14 14
|
||||||
|
8: 42
|
||||||
|
26: 14 22 | 1 20
|
||||||
|
18: 15 15
|
||||||
|
7: 14 5 | 1 21
|
||||||
|
24: 14 1
|
||||||
|
|
||||||
|
abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa
|
||||||
|
bbabbbbaabaabba
|
||||||
|
babbbbaabbbbbabbbbbbaabaaabaaa
|
||||||
|
aaabbbbbbaaaabaababaabababbabaaabbababababaaa
|
||||||
|
bbbbbbbaaaabbbbaaabbabaaa
|
||||||
|
bbbababbbbaaaaaaaabbababaaababaabab
|
||||||
|
ababaaaaaabaaab
|
||||||
|
ababaaaaabbbaba
|
||||||
|
baabbaaaabbaaaababbaababb
|
||||||
|
abbbbabbbbaaaababbbbbbaaaababb
|
||||||
|
aaaaabbaabaaaaababaa
|
||||||
|
aaaabbaaaabbaaa
|
||||||
|
aaaabbaabbaaaaaaabbbabbbaaabbaabaaa
|
||||||
|
babaaabbbaaabaababbaabababaaab
|
||||||
|
aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba
|
|
@ -9,6 +9,7 @@ pub fn run() -> Result<String> {
|
||||||
let mut res = String::with_capacity(128);
|
let mut res = String::with_capacity(128);
|
||||||
|
|
||||||
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
writeln!(res, "part 1: {}", part1(INPUT)?)?;
|
||||||
|
writeln!(res, "part 2: {}", part2(INPUT)?)?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
@ -45,6 +46,32 @@ fn part1(input: &str) -> Result<usize> {
|
||||||
Ok(lines.filter(|l| rules[&0].matches(&rules, l)).count())
|
Ok(lines.filter(|l| rules[&0].matches(&rules, l)).count())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn part2(input: &str) -> Result<usize> {
|
||||||
|
let mut parts = input.split("\n\n");
|
||||||
|
|
||||||
|
let rules = parts.next().context("no rules before linebreak")?;
|
||||||
|
let mut rules = get_rules(rules)?;
|
||||||
|
|
||||||
|
let lines = parts.next().context("no lines after linebreak")?.lines();
|
||||||
|
|
||||||
|
rules.insert(
|
||||||
|
8,
|
||||||
|
Rule::Either(
|
||||||
|
Rule::Chain(vec![42]).into(),
|
||||||
|
Rule::Chain(vec![42, 8]).into(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
11,
|
||||||
|
Rule::Either(
|
||||||
|
Rule::Chain(vec![42, 31]).into(),
|
||||||
|
Rule::Chain(vec![42, 11, 31]).into(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(lines.filter(|l| rules[&0].matches(&rules, l)).count())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Rule {
|
enum Rule {
|
||||||
Character(char),
|
Character(char),
|
||||||
|
@ -53,48 +80,47 @@ enum Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rule {
|
impl Rule {
|
||||||
fn matches_rec<'a>(&self, rules: &HashMap<usize, Rule>, mut s: &'a str) -> (bool, &'a str) {
|
fn matches_rec<'a>(&self, rules: &HashMap<usize, Rule>, s: &'a str) -> Vec<&'a str> {
|
||||||
match self {
|
|
||||||
Rule::Character(c) => {
|
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return (false, s);
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = s.chars().next().unwrap() == *c;
|
match self {
|
||||||
|
Rule::Character(c) => {
|
||||||
(res, &s[1..])
|
let mut res = Vec::new();
|
||||||
|
if s.chars().next().unwrap() == *c {
|
||||||
|
res.push(&s[1..]);
|
||||||
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
Rule::Chain(idxs) => {
|
Rule::Chain(idxs) => {
|
||||||
|
let mut partial_matches = vec![s];
|
||||||
|
|
||||||
for idx in idxs {
|
for idx in idxs {
|
||||||
let rule = &rules[idx];
|
let rule = &rules[idx];
|
||||||
let (res, new_s) = rule.matches_rec(rules, s);
|
let mut new_partial_matches = Vec::new();
|
||||||
if !res {
|
for partial_match in partial_matches {
|
||||||
return (false, s);
|
new_partial_matches.append(&mut rule.matches_rec(rules, partial_match));
|
||||||
|
}
|
||||||
|
partial_matches = new_partial_matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
s = new_s;
|
partial_matches
|
||||||
}
|
|
||||||
|
|
||||||
(true, s)
|
|
||||||
}
|
}
|
||||||
Rule::Either(r1, r2) => {
|
Rule::Either(r1, r2) => {
|
||||||
let (res1, s1) = r1.matches_rec(rules, s);
|
let mut res = r1.matches_rec(rules, s);
|
||||||
if res1 {
|
res.append(&mut r2.matches_rec(rules, s));
|
||||||
return (true, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (res2, s2) = r2.matches_rec(rules, s);
|
res
|
||||||
|
|
||||||
(res2, s2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches(&self, rules: &HashMap<usize, Rule>, s: &str) -> bool {
|
fn matches(&self, rules: &HashMap<usize, Rule>, s: &str) -> bool {
|
||||||
let (res, s_res) = self.matches_rec(rules, s);
|
let res = self.matches_rec(rules, s);
|
||||||
|
|
||||||
res && s_res.is_empty()
|
res.contains(&"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,11 +161,12 @@ impl std::str::FromStr for Rule {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const PROVIDED: &str = include_str!("../input/day19_provided.txt");
|
const PROVIDED1: &str = include_str!("../input/day19_provided1.txt");
|
||||||
|
const PROVIDED2: &str = include_str!("../input/day19_provided2.txt");
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part1_provided() {
|
fn part1_provided() {
|
||||||
let mut parts = PROVIDED.split("\n\n");
|
let mut parts = PROVIDED1.split("\n\n");
|
||||||
|
|
||||||
let rules = get_rules(parts.next().unwrap()).unwrap();
|
let rules = get_rules(parts.next().unwrap()).unwrap();
|
||||||
|
|
||||||
|
@ -165,4 +192,14 @@ mod tests {
|
||||||
fn part1_real() {
|
fn part1_real() {
|
||||||
assert_eq!(part1(INPUT).unwrap(), 144);
|
assert_eq!(part1(INPUT).unwrap(), 144);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_provided() {
|
||||||
|
assert_eq!(part2(PROVIDED2).unwrap(), 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_real() {
|
||||||
|
assert_eq!(part2(INPUT).unwrap(), 260);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue