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::env; | ||||
| 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() { | ||||
|     println!("Hello, AoC day 13!"); | ||||
| @ -18,109 +33,69 @@ fn main() { | ||||
|     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 mut map = HashMap::new(); | ||||
|     let mut distances_to_end: HashMap<Coord, i32> = HashMap::new(); | ||||
| 
 | ||||
|     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; | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     distances_to_end.insert(exit, 0); | ||||
|     let 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); | ||||
|         } | ||||
| 
 | ||||
|     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 { | ||||
|     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; | ||||
| 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) | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[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); | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| fn neighbors(start: &Coord) -> Vec<Coord> { | ||||
|     vec![ | ||||
|         step(start, North, 1), | ||||
|         step(start, West, 1), | ||||
|         step(start, East, 1), | ||||
|         step(start, South, 1) | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										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