day 19 was quite a doozy!

This commit is contained in:
Shoofle 2024-12-19 14:24:21 -05:00
parent 5135d5c78f
commit d6e487d400
2 changed files with 133 additions and 0 deletions

7
day19/Cargo.toml Normal file
View 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
View 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);
}
}
}
}