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