Completed day 19 part 2

Terribly inefficient algorithm but at this point I don't care.
This commit is contained in:
Tyler Hallada 2020-12-24 19:23:15 -05:00
parent 2fb9b4ed4a
commit c248cb0bbd
2 changed files with 42 additions and 40 deletions

View File

@ -1,15 +1,7 @@
0: 1 | 2
0: 1 2
1: 3 | 3 1
2: 3 4 | 3 2 4
3: "a"
4: "b"
a
aa
aaa
b
ab
aabb
aaabbb
aaaabbb
aaabbbb
aaaaabb

View File

@ -60,48 +60,58 @@ fn string_matches_rule<'a>(
rules: &HashMap<usize, Rule>,
rule: &Rule,
ends: bool,
) -> (&'a str, bool) {
if s.is_empty() {
return (s, false);
}
) -> Vec<(&'a str, bool)> {
match rule {
Rule::Char(c) => {
if s.len() < 1 {
(s, false)
vec![(s, false)]
} else if s.chars().next().expect("non-empty string") == *c {
let rest = &s[1..];
if !ends || (ends && rest.is_empty()) {
(rest, true)
vec![(rest, true)]
} else {
(rest, false)
vec![(rest, false)]
}
} else {
(s, false)
vec![(s, false)]
}
}
Rule::Seq(seq) => {
let mut rest = s;
let mut possibilities: Vec<(&'a str, bool)> = Vec::new();
for (i, rule_index) in seq.iter().enumerate() {
let result = string_matches_rule(
rest,
if i == 0 {
possibilities = string_matches_rule(
s,
rules,
&rules[rule_index],
if i == seq.len() - 1 { ends } else { false },
);
if !result.1 {
return result;
} else {
let mut new_possibilities = Vec::new();
for possibility in possibilities {
if possibility.1 {
new_possibilities.append(&mut string_matches_rule(
possibility.0,
rules,
&rules[rule_index],
if i == seq.len() - 1 { ends } else { false },
));
}
rest = result.0;
}
(rest, true)
possibilities = new_possibilities;
}
}
possibilities
}
Rule::Or((left, right)) => {
let result = string_matches_rule(s, rules, &Rule::Seq(left.to_vec()), ends);
if result.1 {
return result;
}
let result = string_matches_rule(s, rules, &Rule::Seq(right.to_vec()), ends);
result
let mut possibilities = string_matches_rule(s, rules, &Rule::Seq(left.to_vec()), ends);
possibilities.append(&mut string_matches_rule(
s,
rules,
&Rule::Seq(right.to_vec()),
ends,
));
possibilities
}
}
}
@ -126,8 +136,8 @@ fn solve_part1(input_path: &str) -> Result<usize> {
Ok(strings
.iter()
.filter(|s| {
let result = string_matches_rule(&s, &rules, &rules[&0], true);
result.1 && result.0.is_empty()
let results = string_matches_rule(&s, &rules, &rules[&0], true);
results.iter().any(|result| result.1 && result.0.is_empty())
})
.count())
}
@ -158,8 +168,8 @@ fn solve_part2(input_path: &str) -> Result<usize> {
Ok(strings
.into_iter()
.filter(|s| {
let result = string_matches_rule(&s, &rules, &rules[&0], true);
result.1 && result.0.is_empty()
let results = string_matches_rule(&s, &rules, &rules[&0], true);
results.iter().any(|result| result.1 && result.0.is_empty())
})
.count())
}
@ -214,7 +224,7 @@ mod tests {
#[test]
fn solves_part2() {
assert_eq!(solve_part1(TEST_INPUT2).unwrap(), 3);
assert_eq!(solve_part1(TEST_INPUT3).unwrap(), 6);
assert_eq!(solve_part1(TEST_INPUT3).unwrap(), 1);
assert_eq!(solve_part2(TEST_INPUT2).unwrap(), 12);
}
}