i do not understand day 20
i mean 21
This commit is contained in:
		
							parent
							
								
									d6e487d400
								
							
						
					
					
						commit
						12bdd65215
					
				| @ -1,8 +1,23 @@ | |||||||
|  | use std::collections::HashSet; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::env; | use std::env; | ||||||
| use std::fs; | use std::fs; | ||||||
| 
 | 
 | ||||||
| use regex::Regex; | use crate::Dir::{North, South, East, West }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | type Coord = (i32, i32); | ||||||
|  | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)] | ||||||
|  | enum Dir { North, South, East, West } | ||||||
|  | 
 | ||||||
|  | fn step(start: &Coord, d: Dir, steps: i32) -> Coord { | ||||||
|  |     match d { | ||||||
|  |         North => (start.0, start.1 - steps), | ||||||
|  |         South => (start.0, start.1 + steps), | ||||||
|  |         East => (start.0 + steps, start.1), | ||||||
|  |         West => (start.0 - steps, start.1), | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     println!("Hello, AoC day 13!"); |     println!("Hello, AoC day 13!"); | ||||||
| @ -18,109 +33,69 @@ fn main() { | |||||||
|     let binding = fs::read_to_string(file_path) |     let binding = fs::read_to_string(file_path) | ||||||
|         .expect("should be able to read the file"); |         .expect("should be able to read the file"); | ||||||
| 
 | 
 | ||||||
|     let (towels, designs) = binding.split_once("\n\n").expect("should have two sections"); |     let mut map = HashMap::new(); | ||||||
|  |     let mut distances_to_end: HashMap<Coord, i32> = HashMap::new(); | ||||||
| 
 | 
 | ||||||
|     let all_towels: Vec<&str> = towels.split(", ").collect(); |     let mut start = (0,0); | ||||||
| 
 |     let mut exit = (0,0); | ||||||
|     let re = Regex::new( |     let mut y = 0; | ||||||
|             &format!("^({})+$", all_towels.join("|")) |     for line in binding.lines() { | ||||||
|         ).expect("making the regex"); |         let mut x = 0; | ||||||
|     
 |         for c in line.chars() { | ||||||
|     let mut count = 0; |             match c { | ||||||
|     for line in designs.lines() { |                 'S' => { start = (x,y); map.insert((x,y), '.'); }, | ||||||
|         if re.is_match(line) { |                 'E' => { exit = (x,y); map.insert((x,y), '.'); }, | ||||||
|             count += 1; |                 _ => { map.insert((x,y), c); } | ||||||
|  |             }; | ||||||
|  |             x += 1; | ||||||
|         } |         } | ||||||
|  |         y += 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     println!("found {count} valid designs"); |     distances_to_end.insert(exit, 0); | ||||||
| 
 |     let visited: HashSet<Coord> = HashSet::new(); | ||||||
|     let mut tree = build_tree(&all_towels); |     let mut wavefront: Vec<Coord> = vec![exit]; | ||||||
| 
 |     while let Some(here) = wavefront.pop() { | ||||||
|     //println!("{tree:?}");
 |         let here_distance = distances_to_end.get(&here).unwrap().clone(); | ||||||
|     println!("{} nodes in the tree", tree.len()); |         for x in neighbors(&here) { | ||||||
| 
 |             if map.get(&x) != Some(&'.') { | ||||||
|     let mut count = 0; |                 continue; | ||||||
| 
 |             } | ||||||
|     for line in designs.lines() { |             if visited.contains(&x) { | ||||||
|         count += eat(&mut tree, line); |                 continue; | ||||||
|  |             } | ||||||
|  |             if let Some(d) = distances_to_end.get(&x) { | ||||||
|  |                 if *d < here_distance { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             distances_to_end.insert(x, here_distance + 1); | ||||||
|  |             wavefront.push(x); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     println!("found {count} solutions total"); |     } | ||||||
|  | 
 | ||||||
|  |     println!("the distance from {start:?} to {exit:?} is {}", distances_to_end.get(&start).unwrap()); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn eat(tree: &mut Vec<TreeCell>, haystack: &str) -> u128 { | fn second_neighbors(start: &Coord) -> Vec<Coord> { | ||||||
|     let mut heads: HashMap<usize, u128> = HashMap::new(); |     vec![ | ||||||
|     heads.insert(0, 1); |         step(start, North, 2), | ||||||
| 
 |         step(&step(start, North, 1), West, 1), | ||||||
|     //println!("examining {haystack}");
 |         step(&step(start, North, 1), East, 1), | ||||||
| 
 |         step(start, West, 2), | ||||||
|     for c in haystack.chars() { |         step(start, East, 2), | ||||||
|         // iterating by character
 |         step(&step(start, West, 1), South, 1), | ||||||
|         let mut new_heads = HashMap::new(); |         step(&step(start, East, 1), South, 1), | ||||||
| 
 |         step(start, South, 2) | ||||||
|         //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; |  | ||||||
| } | } | ||||||
| 
 | fn neighbors(start: &Coord) -> Vec<Coord> { | ||||||
| 
 |     vec![ | ||||||
| #[derive(PartialEq, Eq, Clone, Debug)] |         step(start, North, 1), | ||||||
| struct TreeCell {next: HashMap<char, usize>, valid: bool} |         step(start, West, 1), | ||||||
| 
 |         step(start, East, 1), | ||||||
| fn build_tree(patterns: &[&str]) -> Vec<TreeCell> { |         step(start, South, 1) | ||||||
|     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); |  | ||||||
| 
 |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
							
								
								
									
										6
									
								
								day20/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								day20/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | [package] | ||||||
|  | name = "day20" | ||||||
|  | version = "0.1.0" | ||||||
|  | edition = "2021" | ||||||
|  | 
 | ||||||
|  | [dependencies] | ||||||
							
								
								
									
										183
									
								
								day20/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								day20/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | |||||||
|  | use std::collections::HashSet; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use std::env; | ||||||
|  | use std::fs; | ||||||
|  | 
 | ||||||
|  | use crate::Dir::{North, South, East, West }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | type Coord = (i32, i32); | ||||||
|  | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)] | ||||||
|  | enum Dir { North, South, East, West } | ||||||
|  | 
 | ||||||
|  | fn step(start: &Coord, d: Dir, steps: i32) -> Coord { | ||||||
|  |     match d { | ||||||
|  |         North => (start.0, start.1 - steps), | ||||||
|  |         South => (start.0, start.1 + steps), | ||||||
|  |         East => (start.0 + steps, start.1), | ||||||
|  |         West => (start.0 - steps, start.1), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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 mut map = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     let mut start = (0,0); | ||||||
|  |     let mut exit = (0,0); | ||||||
|  |     let mut y = 0; | ||||||
|  |     for line in binding.lines() { | ||||||
|  |         let mut x = 0; | ||||||
|  |         for c in line.chars() { | ||||||
|  |             match c { | ||||||
|  |                 'S' => { start = (x,y); map.insert((x,y), '.'); }, | ||||||
|  |                 'E' => { exit = (x,y); map.insert((x,y), '.'); }, | ||||||
|  |                 _ => { map.insert((x,y), c); } | ||||||
|  |             }; | ||||||
|  |             x += 1; | ||||||
|  |         } | ||||||
|  |         y += 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut distances_to_end: HashMap<Coord, i32> = HashMap::new(); | ||||||
|  |     distances_to_end.insert(exit, 0); | ||||||
|  |     let mut visited: HashSet<Coord> = HashSet::new(); | ||||||
|  |     let mut wavefront: Vec<Coord> = vec![exit]; | ||||||
|  |     while let Some(here) = wavefront.pop() { | ||||||
|  |         let here_distance = distances_to_end.get(&here).unwrap().clone(); | ||||||
|  |         for x in neighbors(&here) { | ||||||
|  |             if map.get(&x) != Some(&'.') { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if visited.contains(&x) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             if let Some(d) = distances_to_end.get(&x) { | ||||||
|  |                 if *d < here_distance { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             distances_to_end.insert(x, here_distance + 1); | ||||||
|  |             wavefront.push(x); | ||||||
|  |         } | ||||||
|  |         visited.insert(here); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     println!("the distance from {start:?} to {exit:?} is {}", distances_to_end.get(&start).unwrap()); | ||||||
|  | 
 | ||||||
|  |     let mut cheats: HashMap<(Coord, Coord), i32> = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     for (here, distance) in &distances_to_end { | ||||||
|  |         for there in second_neighbors(&here) { | ||||||
|  |             if let Some(next_distance) = distances_to_end.get(&there) { | ||||||
|  |                 cheats.insert((*here, there), distance-next_distance); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut counts: HashMap<i32, i32> = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     for (_, advantage) in cheats { | ||||||
|  |         counts.insert(advantage, counts.get(&advantage).unwrap_or(&0) + 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut count = 0; | ||||||
|  |     for (x, c) in counts { | ||||||
|  |         if x > 100 { | ||||||
|  |             count += c; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     println!("there were {count} cheats worth more than 100"); | ||||||
|  | 
 | ||||||
|  |     // part b
 | ||||||
|  | 
 | ||||||
|  |     let mut cheats: HashMap<(Coord, Coord), i32> = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     for (here, distance) in &distances_to_end { | ||||||
|  |         for there in twenty_step_neighbors(&here) { | ||||||
|  |             if let Some(next_distance) = distances_to_end.get(&there) { | ||||||
|  |                 let cheat_length = (here.0 - there.0).abs() + (here.1 - there.1).abs(); | ||||||
|  |                 cheats.insert((*here, there), distance-next_distance - cheat_length); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut counts: HashMap<i32, i32> = HashMap::new(); | ||||||
|  | 
 | ||||||
|  |     for (_, advantage) in cheats { | ||||||
|  |         counts.insert(advantage, counts.get(&advantage).unwrap_or(&0) + 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut count = 0; | ||||||
|  |     for (x, c) in counts { | ||||||
|  |         if x >= 100 { | ||||||
|  |             count += c; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     println!("there were {count} cheats worth more than 100"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_cheat_offsets() -> Vec<Coord> { | ||||||
|  |     let mut all = vec![(0,0)]; | ||||||
|  | 
 | ||||||
|  |     for _ in 0..20 { | ||||||
|  |         all = all.into_iter().flat_map(|x| neighbors(&x)).collect(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return all | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn offset_neighbors(start: &Coord, offsets: &Vec<Coord>) -> Vec<Coord> { | ||||||
|  |     let mut v: Vec<Coord> = offsets.clone(); | ||||||
|  |     for x in v.iter_mut() { | ||||||
|  |         x.0 = x.0 + start.0; | ||||||
|  |         x.1 = x.1 + start.1; | ||||||
|  |     } | ||||||
|  |     return v; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn twenty_step_neighbors(start: &Coord) -> Vec<Coord> { | ||||||
|  |     let mut v: Vec<Coord> = Vec::with_capacity(400); | ||||||
|  |     for x in -20_i32..21 { | ||||||
|  |         for y in -20_i32..21 { | ||||||
|  |             if x.abs()+y.abs() <= 20 { | ||||||
|  |                 v.push(step(&step(start, North, y), East, x)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return v; | ||||||
|  | } | ||||||
|  | fn second_neighbors(start: &Coord) -> Vec<Coord> { | ||||||
|  |     vec![ | ||||||
|  |         step(start, North, 2), | ||||||
|  |         step(&step(start, North, 1), West, 1), | ||||||
|  |         step(&step(start, North, 1), East, 1), | ||||||
|  |         step(start, West, 2), | ||||||
|  |         step(start, East, 2), | ||||||
|  |         step(&step(start, West, 1), South, 1), | ||||||
|  |         step(&step(start, East, 1), South, 1), | ||||||
|  |         step(start, South, 2) | ||||||
|  |     ] | ||||||
|  | } | ||||||
|  | fn neighbors(start: &Coord) -> Vec<Coord> { | ||||||
|  |     vec![ | ||||||
|  |         step(start, North, 1), | ||||||
|  |         step(start, West, 1), | ||||||
|  |         step(start, East, 1), | ||||||
|  |         step(start, South, 1) | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								day21/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								day21/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | [package] | ||||||
|  | name = "day21" | ||||||
|  | version = "0.1.0" | ||||||
|  | edition = "2021" | ||||||
|  | 
 | ||||||
|  | [dependencies] | ||||||
							
								
								
									
										349
									
								
								day21/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								day21/src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,349 @@ | |||||||
|  | use std::collections::HashSet; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | use std::env; | ||||||
|  | use std::fs; | ||||||
|  | 
 | ||||||
|  | use crate::Dir::{North, South, East, West, Stay }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | type Coord = (i32, i32); | ||||||
|  | #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)] | ||||||
|  | enum Dir { North, South, East, West, Stay } | ||||||
|  | 
 | ||||||
|  | fn step(start: &Coord, d: Dir, steps: i32) -> Coord { | ||||||
|  |     match d { | ||||||
|  |         North => (start.0, start.1 - steps), | ||||||
|  |         South => (start.0, start.1 + steps), | ||||||
|  |         East => (start.0 + steps, start.1), | ||||||
|  |         West => (start.0 - steps, start.1), | ||||||
|  |         Stay => *start, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn walk_path(start: &Coord, path: &[Dir]) -> Coord { | ||||||
|  |     let mut here = *start; | ||||||
|  |     for d in path { | ||||||
|  |         here = step(&here, *d, 1); | ||||||
|  |     } | ||||||
|  |     return here; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     println!("Hello, AoC day 21!"); | ||||||
|  | 
 | ||||||
|  |     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 file = fs::read_to_string(file_path) | ||||||
|  |         .expect("should be able to read the file"); | ||||||
|  | 
 | ||||||
|  |     let keypad_door: HashMap<char, Coord> = HashMap::from([ | ||||||
|  |         ('7', (0,0)), ('8', (1,0)), ('9', (2,0)), | ||||||
|  |         ('4', (0,1)), ('5', (1,1)), ('6', (2,1)), | ||||||
|  |         ('1', (0,2)), ('2', (1,2)), ('3', (2,2)), | ||||||
|  |         ('0', (1,3)), ('A', (2,3)), | ||||||
|  |         ]); | ||||||
|  |     let mut door_map: HashMap<Coord, char> = HashMap::new(); | ||||||
|  |     for (key, loc) in &keypad_door { door_map.insert(*loc, *key); } | ||||||
|  |     let mut directions_matrix: HashMap<(Coord, Coord), Vec<(Dir, i32)>> = HashMap::new(); | ||||||
|  |     for (_this, here) in &keypad_door { | ||||||
|  |         for (_other, there) in &keypad_door { | ||||||
|  |             let mut v = vec![]; | ||||||
|  |             if there.0 > here.0 { | ||||||
|  |                 v.push((East, there.0 - here.0)); | ||||||
|  |             } | ||||||
|  |             if there.0 < here.0 { | ||||||
|  |                 v.push((West, here.0 - there.0)); | ||||||
|  |             } | ||||||
|  |             if there.1 > here.1 { | ||||||
|  |                 v.push((South, there.1 - here.1)); | ||||||
|  |             } | ||||||
|  |             if there.1 < here.1 { | ||||||
|  |                 v.push((North, here.1 - there.1)); | ||||||
|  |             } | ||||||
|  |             if there == here { | ||||||
|  |                 v.push((Stay, 0)); | ||||||
|  |             } | ||||||
|  |             directions_matrix.insert((*here, *there), v); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     let keypad_arrows: HashMap<Dir, Coord> = HashMap::from([ | ||||||
|  |         (North, (1,0)), (Stay, (2,0)), | ||||||
|  |         (West, (0,1)), (South, (1,1)), (East, (2,1)), | ||||||
|  |         ]); | ||||||
|  |     let mut keypad_map: HashMap<Coord, Dir> = HashMap::new(); | ||||||
|  |     for (key, loc) in &keypad_arrows { keypad_map.insert(*loc, *key); } | ||||||
|  |     let mut keypad_directions_matrix = HashMap::new(); | ||||||
|  |     for (_this, here) in &keypad_arrows { | ||||||
|  |         for (_other, there) in &keypad_arrows { | ||||||
|  |             let mut v = vec![]; | ||||||
|  |             if there.0 > here.0 { | ||||||
|  |                 v.push((East, there.0 - here.0)); | ||||||
|  |             } | ||||||
|  |             if there.0 < here.0 { | ||||||
|  |                 v.push((West, here.0 - there.0)); | ||||||
|  |             } | ||||||
|  |             if there.1 > here.1 { | ||||||
|  |                 v.push((South, there.1 - here.1)); | ||||||
|  |             } | ||||||
|  |             if there.1 < here.1 { | ||||||
|  |                 v.push((North, here.1 - there.1)); | ||||||
|  |             } | ||||||
|  |             if there == here { | ||||||
|  |                 v.push((Stay, 0)); | ||||||
|  |             } | ||||||
|  |             keypad_directions_matrix.insert((*here, *there), v); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut sum = 0; | ||||||
|  |     for line in file.lines() { | ||||||
|  |         let door_code: Vec<char> = line.chars().collect(); | ||||||
|  |         let num: i32 = line[..line.len()-1].parse().expect("failed to parse door code as number"); | ||||||
|  |         let mut complexity: i64 = 100000000000; | ||||||
|  |         
 | ||||||
|  |         for x in &door_code { | ||||||
|  |             print!("{}", x); | ||||||
|  |         } | ||||||
|  |         print!("\n"); | ||||||
|  | 
 | ||||||
|  |         let options_door = build_options( | ||||||
|  |             &directions_matrix, 
 | ||||||
|  |             &keypad_door, 
 | ||||||
|  |             &door_code, 
 | ||||||
|  |             'A'); | ||||||
|  |         for arrow_code_1 in shortest_sequences(options_door, &door_map, keypad_door[&'A']) { | ||||||
|  |             print_code(&arrow_code_1); | ||||||
|  | 
 | ||||||
|  |             let options_arrow_1 = build_options( | ||||||
|  |                 &keypad_directions_matrix, | ||||||
|  |                 &keypad_arrows, | ||||||
|  |                 &arrow_code_1, | ||||||
|  |                 Stay); | ||||||
|  |             for arrow_code_2 in shortest_sequences(options_arrow_1, &keypad_map, keypad_arrows[&Stay]) { | ||||||
|  |                 print_code(&arrow_code_2); | ||||||
|  | 
 | ||||||
|  |                 let options_arrow_2 = build_options( | ||||||
|  |                     &keypad_directions_matrix, | ||||||
|  |                     &keypad_arrows, | ||||||
|  |                     &arrow_code_2, | ||||||
|  |                     Stay); | ||||||
|  |                 for arrow_code_3 in shortest_sequences(options_arrow_2, &keypad_map, keypad_arrows[&Stay]) { | ||||||
|  |                     complexity = complexity.min(arrow_code_3.len() as i64); | ||||||
|  |                     print_code(&arrow_code_3); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         println!("shortest sequence is {} long", complexity); | ||||||
|  |         sum += complexity * (num as i64); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     println!("the sum of the complexity scores is {}", sum); | ||||||
|  | 
 | ||||||
|  |     // println!("printing out the anomalous code");
 | ||||||
|  | 
 | ||||||
|  |     // let code = "<<vAA>A>^AAvA<^A>AvA^A<<vA>>^AAvA^A<vA>^AA<A>A<<vA>A>^AAAvA<^A>A";
 | ||||||
|  |     // let code_dirs = code.chars().map(|x| match x {
 | ||||||
|  |     //     '<' => West, '>' => East, '^' => North, 'v' => South, 'A' => Stay, _ => panic!()
 | ||||||
|  |     // }).collect();
 | ||||||
|  |     // print_code(&code_dirs);
 | ||||||
|  |     // println!("resulting keypresses:");
 | ||||||
|  |     // let code_2 = execute_code(&code_dirs, &keypad_map, keypad_arrows[&Stay]);
 | ||||||
|  |     // print_code(&code_2);
 | ||||||
|  |     // println!("resulting keypresses:");
 | ||||||
|  |     // let code_3 = execute_code(&code_2, &keypad_map, keypad_arrows[&Stay]);
 | ||||||
|  |     // print_code(&code_3);
 | ||||||
|  |     // println!("resulting in:");
 | ||||||
|  |     // let code_4 = execute_code(&code_3, &door_map, keypad_door[&'A']);
 | ||||||
|  |     // print_code_door(&code_4);
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn first_sequence<T>(options: Vec<Vec<(Dir, i32)>>, map: &HashMap<Coord, T>, start: Coord) -> Vec<Dir> { | ||||||
|  |     let mut out = vec![]; | ||||||
|  |     let mut here = start; | ||||||
|  | 
 | ||||||
|  |     for choices in options { | ||||||
|  |         if choices.len() == 1 { | ||||||
|  |             let (direction, times) = choices[0]; | ||||||
|  |             for _ in 0..times { | ||||||
|  |                 out.push(direction); | ||||||
|  |             } | ||||||
|  |             here = step(&here, direction, times) | ||||||
|  |         } else if choices.len() == 2 { | ||||||
|  |             let (d1, t1) = choices[0]; | ||||||
|  |             let (d2, t2) = choices[1]; | ||||||
|  |             if map.contains_key(&step(&here, d1, t1)) { | ||||||
|  |                 for _ in 0..t1 { | ||||||
|  |                     out.push(d1); | ||||||
|  |                 } | ||||||
|  |                 
 | ||||||
|  |                 for _ in 0..t2 { | ||||||
|  |                     out.push(d2); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 for _ in 0..t2 { | ||||||
|  |                     out.push(d2); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 for _ in 0..t1 { | ||||||
|  |                     out.push(d1); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             
 | ||||||
|  |             
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return out; | ||||||
|  | } | ||||||
|  | fn sequences<T>(options: Vec<Vec<(Dir, i32)>>, map: &HashMap<Coord, T>, start: Coord) -> Vec<Vec<Dir>> { | ||||||
|  |     let mut out: Vec<(Vec<Dir>, Coord)> = vec![(vec![], start)]; | ||||||
|  | 
 | ||||||
|  |     for choices in options { | ||||||
|  |         let mut new_out = vec![]; | ||||||
|  | 
 | ||||||
|  |         if choices.len() == 1 { | ||||||
|  |             let (direction, times) = choices[0]; | ||||||
|  |             for (mut walk, mut here) in out { | ||||||
|  |                 for _ in 0..times { | ||||||
|  |                     walk.push(direction); | ||||||
|  |                     here = step(&here, direction, 1); | ||||||
|  |                 } | ||||||
|  |                 new_out.push((walk, here)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         
 | ||||||
|  |         else if choices.len() == 2 { | ||||||
|  |             let (d1, t1) = choices[0]; | ||||||
|  |             let (d2, t2) = choices[1]; | ||||||
|  | 
 | ||||||
|  |             for (ref walk, here) in &mut out { | ||||||
|  |                 let end = step(&step(&here, d1, t1), d2, t2); | ||||||
|  |                 let candidate_here = step(&here, d1, t1); | ||||||
|  |                 if map.contains_key(&candidate_here) { | ||||||
|  |                     let mut ab_walk = walk.clone(); | ||||||
|  | 
 | ||||||
|  |                     for _ in 0..t1 { ab_walk.push(d1); } | ||||||
|  |                     for _ in 0..t2 { ab_walk.push(d2); } | ||||||
|  | 
 | ||||||
|  |                     new_out.push((ab_walk, end)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 let candidate_there = step(&here, d2, t2); | ||||||
|  |                 if map.contains_key(&candidate_there) { | ||||||
|  |                     let mut ba_walk = walk.clone(); | ||||||
|  | 
 | ||||||
|  |                     for _ in 0..t2 { ba_walk.push(d2); } | ||||||
|  |                     for _ in 0..t1 { ba_walk.push(d1); } | ||||||
|  | 
 | ||||||
|  |                     new_out.push((ba_walk, end)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             panic!("encountered a bad set of choices"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         out = new_out; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let mut final_out = vec![]; | ||||||
|  |     for (walk, _) in out { | ||||||
|  |         final_out.push(walk); | ||||||
|  |     } | ||||||
|  |     return final_out; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn shortest_sequences<T>( | ||||||
|  |     options: Vec<Vec<(Dir, i32)>>, 
 | ||||||
|  |     map: &HashMap<Coord, T>, 
 | ||||||
|  |     start: Coord | ||||||
|  | ) -> Vec<Vec<Dir>> { | ||||||
|  |     let mut short_length = None; | ||||||
|  |     let mut shorts = vec![]; | ||||||
|  | 
 | ||||||
|  |     for seq in sequences(options.to_vec(), map, start) { | ||||||
|  |         let my_len = seq.len(); | ||||||
|  |         if let Some(len) = short_length { | ||||||
|  |             if my_len == len { | ||||||
|  |                 shorts.push(seq); | ||||||
|  |             } else if my_len < len { | ||||||
|  |                 shorts = vec![seq]; | ||||||
|  |                 short_length = Some(my_len); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             short_length = Some(my_len); | ||||||
|  |             shorts.push(seq); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return shorts; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn build_options<T: std::hash::Hash + std::cmp::Eq>( | ||||||
|  |     routes: &HashMap<(Coord, Coord), Vec<(Dir, i32)>>, 
 | ||||||
|  |     map: &HashMap<T, Coord>, | ||||||
|  |     sequence: &Vec<T>, | ||||||
|  |     start: T, | ||||||
|  | ) -> Vec<Vec<(Dir, i32)>> { | ||||||
|  |     let mut here = map[&start]; | ||||||
|  |     let mut options: Vec<Vec<(Dir, i32)>> = Vec::new(); | ||||||
|  |     for button in sequence { | ||||||
|  |         let there = map[&button]; | ||||||
|  |         options.push(routes[&(here, there)].clone()); | ||||||
|  |         options.push(vec![(Stay, 1)]); | ||||||
|  |         here = there; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return options; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | fn print_code(code: &Vec<Dir>) { | ||||||
|  |     for x in code { | ||||||
|  |         print!("{}", match x { 
 | ||||||
|  |             North => '^', South => 'v', East => '>', West => '<', Stay => 'A' | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |     print!("\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn print_code_door(code: &Vec<char>) { | ||||||
|  |     for x in code { | ||||||
|  |         print!("{}", x); | ||||||
|  |     } | ||||||
|  |     print!("\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | fn execute_code<T: Clone + Copy>( | ||||||
|  |     code: &Vec<Dir>, 
 | ||||||
|  |     map: &HashMap<Coord, T>, 
 | ||||||
|  |     start: Coord | ||||||
|  | ) -> Vec<T> { | ||||||
|  | 
 | ||||||
|  |     let mut out = vec![]; | ||||||
|  |     let mut here = start; | ||||||
|  |     for d in code { | ||||||
|  |         if *d == Stay { | ||||||
|  |             out.push(map[&here]); | ||||||
|  |         } else { | ||||||
|  |             here = step(&here, *d, 1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     return out; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user