2020: day19: part 2

This commit is contained in:
Antoine Martin 2020-12-20 18:47:42 +01:00
parent fb9a7e3fc9
commit c0b388dfa0
3 changed files with 108 additions and 24 deletions

View 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

View file

@ -9,6 +9,7 @@ pub fn run() -> Result<String> {
let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res)
}
@ -45,6 +46,32 @@ fn part1(input: &str) -> Result<usize> {
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)]
enum Rule {
Character(char),
@ -53,48 +80,47 @@ enum Rule {
}
impl Rule {
fn matches_rec<'a>(&self, rules: &HashMap<usize, Rule>, mut s: &'a str) -> (bool, &'a str) {
match self {
Rule::Character(c) => {
fn matches_rec<'a>(&self, rules: &HashMap<usize, Rule>, s: &'a str) -> Vec<&'a str> {
if s.is_empty() {
return (false, s);
return vec![];
}
let res = s.chars().next().unwrap() == *c;
(res, &s[1..])
match self {
Rule::Character(c) => {
let mut res = Vec::new();
if s.chars().next().unwrap() == *c {
res.push(&s[1..]);
}
res
}
Rule::Chain(idxs) => {
let mut partial_matches = vec![s];
for idx in idxs {
let rule = &rules[idx];
let (res, new_s) = rule.matches_rec(rules, s);
if !res {
return (false, s);
let mut new_partial_matches = Vec::new();
for partial_match in partial_matches {
new_partial_matches.append(&mut rule.matches_rec(rules, partial_match));
}
partial_matches = new_partial_matches;
}
s = new_s;
}
(true, s)
partial_matches
}
Rule::Either(r1, r2) => {
let (res1, s1) = r1.matches_rec(rules, s);
if res1 {
return (true, s1);
}
let mut res = r1.matches_rec(rules, s);
res.append(&mut r2.matches_rec(rules, s));
let (res2, s2) = r2.matches_rec(rules, s);
(res2, s2)
res
}
}
}
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 {
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]
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();
@ -165,4 +192,14 @@ mod tests {
fn part1_real() {
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);
}
}