2020 day 19 Cleanup: Introduced clarifying comments and reduced the beginnings and ends HashSets to those rules that directly translate into chars..
This commit is contained in:
parent
3a42d18f3e
commit
6634837d8e
1 changed files with 46 additions and 25 deletions
|
@ -81,46 +81,66 @@ impl TryFrom<&str> for Rules {
|
||||||
impl Rules {
|
impl Rules {
|
||||||
fn find_beginnings(&mut self) {
|
fn find_beginnings(&mut self) {
|
||||||
let mut open_set = self.beginnings.iter().cloned().collect::<Vec<_>>();
|
let mut open_set = self.beginnings.iter().cloned().collect::<Vec<_>>();
|
||||||
|
let mut visited = self.beginnings.clone();
|
||||||
|
let mut beginnings = HashSet::new();
|
||||||
while let Some(current) = open_set.pop() {
|
while let Some(current) = open_set.pop() {
|
||||||
for (idx, rule) in current.iter().enumerate() {
|
if current.iter().all(|n| self.char_replacements.iter().any(|(_c, i)| n == i)) {
|
||||||
if let Some(expansions) = self.reductions.get(rule) {
|
beginnings.insert(current);
|
||||||
for exp in expansions {
|
} else {
|
||||||
let mut next = current[..idx].to_vec();
|
for (idx, rule) in current.iter().enumerate() {
|
||||||
next.append(&mut exp.to_vec());
|
if let Some(expansions) = self.reductions.get(rule) {
|
||||||
next.append(&mut current[idx+1..].to_vec());
|
for exp in expansions {
|
||||||
if !self.beginnings.contains(&next) {
|
let mut next = current[..idx].to_vec();
|
||||||
self.beginnings.insert(next.to_vec());
|
next.append(&mut exp.to_vec());
|
||||||
open_set.push(next);
|
next.append(&mut current[idx+1..].to_vec());
|
||||||
|
if !visited.contains(&next) {
|
||||||
|
visited.insert(next.to_vec());
|
||||||
|
open_set.push(next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.beginnings = beginnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_ends(&mut self) {
|
fn find_ends(&mut self) {
|
||||||
let mut open_set = self.ends.iter().cloned().collect::<Vec<_>>();
|
let mut open_set = self.ends.iter().cloned().collect::<Vec<_>>();
|
||||||
|
let mut visited = self.ends.clone();
|
||||||
|
let mut ends = HashSet::new();
|
||||||
while let Some(current) = open_set.pop() {
|
while let Some(current) = open_set.pop() {
|
||||||
for (idx, rule) in current.iter().enumerate() {
|
if current.iter().all(|n| self.char_replacements.iter().any(|(_c, i)| n == i)) {
|
||||||
if let Some(expansions) = self.reductions.get(rule) {
|
ends.insert(current);
|
||||||
for exp in expansions {
|
} else {
|
||||||
let mut next = current[..idx].to_vec();
|
for (idx, rule) in current.iter().enumerate() {
|
||||||
next.append(&mut exp.to_vec());
|
if let Some(expansions) = self.reductions.get(rule) {
|
||||||
next.append(&mut current[idx+1..].to_vec());
|
for exp in expansions {
|
||||||
if !self.ends.contains(&next) {
|
let mut next = current[..idx].to_vec();
|
||||||
self.ends.insert(next.to_vec());
|
next.append(&mut exp.to_vec());
|
||||||
open_set.push(next);
|
next.append(&mut current[idx+1..].to_vec());
|
||||||
|
if !visited.contains(&next) {
|
||||||
|
visited.insert(next.to_vec());
|
||||||
|
open_set.push(next);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ends = ends;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All valid messages have the format 42 42 31 for part 1, or 42+ 42{n} 31{n} for part 2 (where
|
||||||
|
// both n's are equal and greater than zero. Hence we can split the message up and check if it
|
||||||
|
// consists of 2 valid beginning parts (expansions of rule 42) and 1 valid ending (expansions
|
||||||
|
// of rule 31). For part 2 we allow additional beginnings and endings between those parts, so
|
||||||
|
// effectively any number of beginnings and endings (in that order), where the number of
|
||||||
|
// endings is at least 1 and the number of beginnings is at least 1 more than that.
|
||||||
fn is_valid(&mut self, message: &str, part_2: bool) -> bool {
|
fn is_valid(&mut self, message: &str, part_2: bool) -> bool {
|
||||||
let target: Vec<usize> = message.chars().map(|c| self.char_replacements.iter().find(|(rule, _idx)| rule == &c).unwrap().1).collect();
|
let target: Vec<usize> = message.chars().map(|c| self.char_replacements.iter().find(|(rule, _idx)| rule == &c).unwrap().1).collect();
|
||||||
let mut targets = Vec::new();
|
let mut targets = Vec::new();
|
||||||
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| b.iter().enumerate().all(|(idx, num)| target.len() > idx && target[idx] == *num)).collect();
|
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| target.starts_with(b)).collect();
|
||||||
if beginnings.is_empty() {
|
if beginnings.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -130,7 +150,7 @@ impl Rules {
|
||||||
}
|
}
|
||||||
let mut new_targets = Vec::new();
|
let mut new_targets = Vec::new();
|
||||||
for target in &targets {
|
for target in &targets {
|
||||||
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| b.iter().enumerate().all(|(idx, num)| target.len() > idx && target[idx] == *num)).collect();
|
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| target.starts_with(b)).collect();
|
||||||
if beginnings.is_empty() {
|
if beginnings.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,7 +160,7 @@ impl Rules {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::mem::swap(&mut targets, &mut new_targets);
|
std::mem::swap(&mut targets, &mut new_targets);
|
||||||
let endings: Vec<_> = self.ends.iter().filter(|b| b.iter().rev().enumerate().all(|(idx, num)| target.len() > idx && target[target.len()-idx-1] == *num)).collect();
|
let endings: Vec<_> = self.ends.iter().filter(|e| target.ends_with(e)).collect();
|
||||||
if endings.is_empty() {
|
if endings.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -157,13 +177,14 @@ impl Rules {
|
||||||
if current.is_empty() {
|
if current.is_empty() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Ensure we reduce the beginning and end the same number of times. We can reduce
|
// Ensure we reduce the beginning and end the same number of times to make sure we
|
||||||
|
// reduce the beginnings at least as often as the endings. We can still reduce
|
||||||
// the beginning even more in the else case.
|
// the beginning even more in the else case.
|
||||||
let endings: Vec<_> = self.ends.iter().filter(|b| b.iter().rev().enumerate().all(|(idx, num)| current.len() > idx && current[current.len()-idx-1] == *num)).collect();
|
let endings: Vec<_> = self.ends.iter().filter(|e| current.ends_with(e)).collect();
|
||||||
if !endings.is_empty() {
|
if !endings.is_empty() {
|
||||||
for ending in endings {
|
for ending in endings {
|
||||||
let current = ¤t[..current.len()-ending.len()];
|
let current = ¤t[..current.len()-ending.len()];
|
||||||
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| b.iter().enumerate().all(|(idx, num)| current.len() > idx && current[idx] == *num)).collect();
|
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| current.starts_with(b)).collect();
|
||||||
if !beginnings.is_empty() {
|
if !beginnings.is_empty() {
|
||||||
for beginning in beginnings {
|
for beginning in beginnings {
|
||||||
targets.push(current[beginning.len()..].to_vec());
|
targets.push(current[beginning.len()..].to_vec());
|
||||||
|
@ -179,7 +200,7 @@ impl Rules {
|
||||||
// breaks down into (bba) we will find a chain of valid beginnings, so we
|
// breaks down into (bba) we will find a chain of valid beginnings, so we
|
||||||
// should pass, or (bbb) we don't, in which case we will fail by removing from
|
// should pass, or (bbb) we don't, in which case we will fail by removing from
|
||||||
// the front.
|
// the front.
|
||||||
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| b.iter().enumerate().all(|(idx, num)| current.len() > idx && current[idx] == *num)).collect();
|
let beginnings: Vec<_> = self.beginnings.iter().filter(|b| current.starts_with(b)).collect();
|
||||||
if !beginnings.is_empty() {
|
if !beginnings.is_empty() {
|
||||||
for beginning in beginnings {
|
for beginning in beginnings {
|
||||||
targets.push(current[beginning.len()..].to_vec());
|
targets.push(current[beginning.len()..].to_vec());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue