day 19 was quite a doozy!
This commit is contained in:
parent
5135d5c78f
commit
d6e487d400
7
day19/Cargo.toml
Normal file
7
day19/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "day19"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
regex = "1.11.1"
|
126
day19/src/main.rs
Normal file
126
day19/src/main.rs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, AoC day 13!");
|
||||||
|
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() != 2 {
|
||||||
|
println!("wrong number of arguments!");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_path = &args[1];
|
||||||
|
|
||||||
|
let binding = fs::read_to_string(file_path)
|
||||||
|
.expect("should be able to read the file");
|
||||||
|
|
||||||
|
let (towels, designs) = binding.split_once("\n\n").expect("should have two sections");
|
||||||
|
|
||||||
|
let all_towels: Vec<&str> = towels.split(", ").collect();
|
||||||
|
|
||||||
|
let re = Regex::new(
|
||||||
|
&format!("^({})+$", all_towels.join("|"))
|
||||||
|
).expect("making the regex");
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for line in designs.lines() {
|
||||||
|
if re.is_match(line) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("found {count} valid designs");
|
||||||
|
|
||||||
|
let mut tree = build_tree(&all_towels);
|
||||||
|
|
||||||
|
//println!("{tree:?}");
|
||||||
|
println!("{} nodes in the tree", tree.len());
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
for line in designs.lines() {
|
||||||
|
count += eat(&mut tree, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("found {count} solutions total");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eat(tree: &mut Vec<TreeCell>, haystack: &str) -> u128 {
|
||||||
|
let mut heads: HashMap<usize, u128> = HashMap::new();
|
||||||
|
heads.insert(0, 1);
|
||||||
|
|
||||||
|
//println!("examining {haystack}");
|
||||||
|
|
||||||
|
for c in haystack.chars() {
|
||||||
|
// iterating by character
|
||||||
|
let mut new_heads = HashMap::new();
|
||||||
|
|
||||||
|
//println!("looking at {c}; the heads we're tracking are {heads:?}");
|
||||||
|
|
||||||
|
// this first loop branches to the start from valid states
|
||||||
|
for (node_idx, num_heads) in heads.drain() {
|
||||||
|
let TreeCell { next: _, valid } = &tree[node_idx];
|
||||||
|
if *valid {
|
||||||
|
let next_idx = 0;
|
||||||
|
let existing_heads = new_heads.get(&next_idx).unwrap_or(&0);
|
||||||
|
new_heads.insert(next_idx, existing_heads + num_heads);
|
||||||
|
}
|
||||||
|
let existing_heads = new_heads.get(&node_idx).unwrap_or(&0);
|
||||||
|
new_heads.insert(node_idx, existing_heads + num_heads);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this second loop advances all the heads
|
||||||
|
for (node_idx, num_heads) in new_heads.drain() {
|
||||||
|
let TreeCell { next, valid: _ } = &tree[node_idx];
|
||||||
|
if let Some(next_idx) = next.get(&c) {
|
||||||
|
heads.insert(*next_idx, num_heads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
for (node_idx, number) in heads {
|
||||||
|
if tree[node_idx].valid { count += number; }
|
||||||
|
}
|
||||||
|
//println!("there are {count} heads in success states");
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
struct TreeCell {next: HashMap<char, usize>, valid: bool}
|
||||||
|
|
||||||
|
fn build_tree(patterns: &[&str]) -> Vec<TreeCell> {
|
||||||
|
let mut cells = vec![TreeCell {next: HashMap::new(), valid: false}];
|
||||||
|
|
||||||
|
for stripes in patterns {
|
||||||
|
add_to_tree(stripes, &mut cells, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_tree(pattern: &str, tree: &mut Vec<TreeCell>, index: usize) {
|
||||||
|
match pattern.chars().next() {
|
||||||
|
None => tree[index].valid = true,
|
||||||
|
Some(c) => {
|
||||||
|
if tree[index].next.contains_key(&c) {
|
||||||
|
add_to_tree(&pattern[1..], tree, *tree[index].next.get(&c).unwrap());
|
||||||
|
} else {
|
||||||
|
let new_index = tree.len();
|
||||||
|
let new_treecell = TreeCell { next: HashMap::new(), valid: false };
|
||||||
|
tree.push(new_treecell); // now this is at new_index
|
||||||
|
tree[index].next.insert(c, new_index);
|
||||||
|
|
||||||
|
add_to_tree(&pattern[1..], tree, new_index);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user