Day 19 part 2.
This commit is contained in:
90
src/day19.rs
90
src/day19.rs
@@ -1,4 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
|
||||
type Transformation = (String, String);
|
||||
@@ -6,27 +7,35 @@ type Transformation = (String, String);
|
||||
#[aoc_generator(day19)]
|
||||
fn parse(input: &str) -> (Vec<Transformation>, String) {
|
||||
let (a, b) = input.split_once("\n\n").unwrap();
|
||||
let t = a.lines().map(|line| {
|
||||
let (lhs, rhs) = line.split_once(" => ").unwrap();
|
||||
(lhs.to_string(), rhs.to_string())
|
||||
}).collect();
|
||||
let t = a
|
||||
.lines()
|
||||
.map(|line| {
|
||||
let (lhs, rhs) = line.split_once(" => ").unwrap();
|
||||
(lhs.to_string(), rhs.to_string())
|
||||
})
|
||||
.collect();
|
||||
(t, b.to_string())
|
||||
}
|
||||
|
||||
#[aoc(day19, part1)]
|
||||
fn part1((transformations, start): &(Vec<Transformation>, String)) -> usize {
|
||||
let all: HashSet<String> = transformations.iter()
|
||||
let all = possibilities(transformations, start);
|
||||
all.len()
|
||||
}
|
||||
|
||||
fn possibilities(transformations: &[Transformation], start: &str) -> HashSet<String> {
|
||||
let all: HashSet<String> = transformations
|
||||
.iter()
|
||||
.flat_map(|(from, to)| {
|
||||
let start_indexes = starts(start, from);
|
||||
start_indexes.into_iter()
|
||||
.map(|si| {
|
||||
let mut s = start.clone();
|
||||
s.replace_range(si..si+from.len(), to);
|
||||
s
|
||||
})
|
||||
}).collect();
|
||||
|
||||
all.len()
|
||||
start_indexes.into_iter().map(|si| {
|
||||
let mut s = start.to_string();
|
||||
s.replace_range(si..si + from.len(), to);
|
||||
s
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
all
|
||||
}
|
||||
|
||||
fn starts(a: &str, pattern: &str) -> Vec<usize> {
|
||||
@@ -39,6 +48,29 @@ fn starts(a: &str, pattern: &str) -> Vec<usize> {
|
||||
result
|
||||
}
|
||||
|
||||
#[aoc(day19, part2)]
|
||||
fn part2((transformations, target): &(Vec<Transformation>, String)) -> usize {
|
||||
search("e", transformations, target)
|
||||
}
|
||||
|
||||
fn search(base: &str, transformations: &[Transformation], target: &str) -> usize {
|
||||
let mut seen = HashSet::new();
|
||||
seen.insert(base.to_string());
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back((base.to_string(), 0));
|
||||
while let Some((from, depth)) = queue.pop_front() {
|
||||
for possibility in possibilities(transformations, &from) {
|
||||
if possibility == target {
|
||||
return depth + 1;
|
||||
}
|
||||
if seen.insert(possibility.clone()) {
|
||||
queue.push_back((possibility, depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!("No solution was found");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
@@ -48,6 +80,30 @@ H => OH
|
||||
O => HH
|
||||
|
||||
HOH";
|
||||
assert_eq!(super::part1(& super::parse(input)), 4);
|
||||
assert_eq!(super::part1(&super::parse(input)), 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2a() {
|
||||
let input = "e => H
|
||||
e => O
|
||||
H => HO
|
||||
H => OH
|
||||
O => HH
|
||||
|
||||
HOH";
|
||||
assert_eq!(super::part2(&super::parse(input)), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2b() {
|
||||
let input = "e => H
|
||||
e => O
|
||||
H => HO
|
||||
H => OH
|
||||
O => HH
|
||||
|
||||
HOHOHO";
|
||||
assert_eq!(super::part2(&super::parse(input)), 6);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user