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