aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReiner Herrmann <reiner.herrmann@lancom.de>2021-12-13 18:20:28 +0100
committerReiner Herrmann <reiner.herrmann@lancom.de>2021-12-13 18:20:28 +0100
commit0a6b5586a50a3d1a52c18b46768f1f5e77d702c3 (patch)
tree4339e686a3e6902fb9b06393ecb72531014c0c68
parent07226d4a4ad24b2e37f56af82f00505d2ed6a4b1 (diff)
day20 part2HEADtrunk
-rw-r--r--src/main.rs154
1 files changed, 127 insertions, 27 deletions
diff --git a/src/main.rs b/src/main.rs
index 30cefc8..8be4525 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1890,23 +1890,81 @@ fn day19() {
}
}
-fn maze_portal_neighbor(portals: &HashMap<String, Vec<Position>>, pos: &Position) -> Option<Position> {
- for (_, positions) in portals {
+#[derive(PartialEq,Eq,Debug)]
+enum PortalType {
+ Outer,
+ Inner,
+}
+
+fn portal_type_at(portals: &HashMap<String, Vec<Position>>, pos: &Position) -> PortalType {
+ if pos.x < 2 || pos.y < 2 {
+ return PortalType::Outer;
+ }
+
+ let max_x = portals.values().flatten().map(|&pos| pos.x).max().unwrap();
+ let max_y = portals.values().flatten().map(|&pos| pos.y).max().unwrap();
+
+ if pos.x == max_x || pos.y == max_y {
+ return PortalType::Outer;
+ }
+
+ PortalType::Inner
+}
+
+fn maze_portal_neighbor(portals: &HashMap<String, Vec<Position>>, pos: &Position, recursive: bool) -> Option<Position> {
+ let mut neigh = None;
+ let mut portal_pos = Position { x:0, y:0, z:0 };
+ let mut portal_name = "";
+ for (name, positions) in portals {
+ portal_name = name;
+
let check = Position { x: pos.x + 1, y: pos.y, z: 0 };
- if positions[0] == check { return Some(positions[1]); }
- if positions[1] == check { return Some(positions[0]); }
+ portal_pos = check;
+ portal_pos.z = pos.z;
+ if positions[0] == check { neigh = Some(positions[1]); break; }
+ if positions[1] == check { neigh = Some(positions[0]); break; }
let check = Position { x: pos.x - 1, y: pos.y, z: 0 };
- if positions[0] == check { return Some(positions[1]); }
- if positions[1] == check { return Some(positions[0]); }
+ portal_pos = check;
+ portal_pos.z = pos.z;
+ if positions[0] == check { neigh = Some(positions[1]); break; }
+ if positions[1] == check { neigh = Some(positions[0]); break; }
let check = Position { x: pos.x, y: pos.y + 1, z: 0 };
- if positions[0] == check { return Some(positions[1]); }
- if positions[1] == check { return Some(positions[0]); }
+ portal_pos = check;
+ portal_pos.z = pos.z;
+ if positions[0] == check { neigh = Some(positions[1]); break; }
+ if positions[1] == check { neigh = Some(positions[0]); break; }
let check = Position { x: pos.x, y: pos.y - 1, z: 0 };
- if positions[0] == check { return Some(positions[1]); }
- if positions[1] == check { return Some(positions[0]); }
+ portal_pos = check;
+ portal_pos.z = pos.z;
+ if positions[0] == check { neigh = Some(positions[1]); break; }
+ if positions[1] == check { neigh = Some(positions[0]); break; }
+ }
+ if !recursive {
+ /* ignore z level */
+ return neigh;
+ }
+ if let Some(mut p) = neigh {
+ let old = portal_type_at(portals, &portal_pos);
+ let new = portal_type_at(portals, &p);
+
+ if portal_pos.z == 0 && old == PortalType::Outer && portal_name != "AA" && portal_name != "ZZ" {
+ return None;
+ }
+ if portal_pos.z > 0 && (portal_name == "AA" || portal_name == "ZZ") {
+ return None;
+ }
+
+ if old == new {
+ p.z = portal_pos.z;
+ } else if old == PortalType::Outer {
+ p.z = portal_pos.z - 1;
+ } else {
+ p.z = portal_pos.z + 1;
+ }
+ return Some(p);
}
None
}
@@ -1916,25 +1974,25 @@ fn maze_neighbors(passages: &HashSet<Position>, pos: &Position) -> HashSet<Posit
let check = Position { x: pos.x + 1, y: pos.y, z: 0 };
if passages.contains(&check) {
- neighbors.insert(check);
+ neighbors.insert(Position { x: check.x, y: check.y, z: pos.z });
}
let check = Position { x: pos.x - 1, y: pos.y, z: 0 };
if passages.contains(&check) {
- neighbors.insert(check);
+ neighbors.insert(Position { x: check.x, y: check.y, z: pos.z });
}
let check = Position { x: pos.x, y: pos.y + 1, z: 0 };
if passages.contains(&check) {
- neighbors.insert(check);
+ neighbors.insert(Position { x: check.x, y: check.y, z: pos.z });
}
let check = Position { x: pos.x, y: pos.y - 1, z: 0 };
if passages.contains(&check) {
- neighbors.insert(check);
+ neighbors.insert(Position { x: check.x, y: check.y, z: pos.z });
}
neighbors
}
-fn steps_through_maze<T: AsRef<str>>(input: &[T]) -> usize {
+fn steps_through_maze<T: AsRef<str>>(input: &[T], recursive: bool) -> usize {
let mut map = HashMap::new();
let mut passages = HashSet::new();
for (y, line) in input.iter().enumerate() {
@@ -1948,37 +2006,37 @@ fn steps_through_maze<T: AsRef<str>>(input: &[T]) -> usize {
}
let mut portals = HashMap::new();
for passage in &passages {
- let check = Position { x: passage.x - 1, y: passage.y, z: 0 };
+ let check = Position { x: passage.x - 1, y: passage.y, z: passage.z };
if let Some(pos) = map.get(&check) {
if pos.is_ascii_uppercase() {
- let portal = map.get(&Position { x: check.x - 1, y: check.y, z: 0 }).unwrap().to_string() + &pos.to_string();
+ let portal = map.get(&Position { x: check.x - 1, y: check.y, z: check.z }).unwrap().to_string() + &pos.to_string();
let entry = portals.entry(portal).or_insert_with(Vec::new);
entry.push(check);
}
}
- let check = Position { x: passage.x + 1, y: passage.y, z: 0 };
+ let check = Position { x: passage.x + 1, y: passage.y, z: passage.z };
if let Some(pos) = map.get(&check) {
if pos.is_ascii_uppercase() {
- let portal = pos.to_string() + &map.get(&Position { x: check.x + 1, y: check.y, z: 0 }).unwrap().to_string();
+ let portal = pos.to_string() + &map.get(&Position { x: check.x + 1, y: check.y, z: check.z }).unwrap().to_string();
let entry = portals.entry(portal).or_insert_with(Vec::new);
entry.push(check);
}
}
- let check = Position { x: passage.x, y: passage.y - 1, z: 0 };
+ let check = Position { x: passage.x, y: passage.y - 1, z: passage.z };
if let Some(pos) = map.get(&check) {
if pos.is_ascii_uppercase() {
- let portal = map.get(&Position { x: check.x, y: check.y - 1, z: 0 }).unwrap().to_string() + &pos.to_string();
+ let portal = map.get(&Position { x: check.x, y: check.y - 1, z: check.z }).unwrap().to_string() + &pos.to_string();
let entry = portals.entry(portal).or_insert_with(Vec::new);
entry.push(check);
}
}
- let check = Position { x: passage.x, y: passage.y + 1, z: 0 };
+ let check = Position { x: passage.x, y: passage.y + 1, z: passage.z };
if let Some(pos) = map.get(&check) {
if pos.is_ascii_uppercase() {
- let portal = pos.to_string() + &map.get(&Position { x: check.x, y: check.y + 1, z: 0 }).unwrap().to_string();
+ let portal = pos.to_string() + &map.get(&Position { x: check.x, y: check.y + 1, z: check.z }).unwrap().to_string();
let entry = portals.entry(portal).or_insert_with(Vec::new);
entry.push(check);
}
@@ -1999,7 +2057,7 @@ fn steps_through_maze<T: AsRef<str>>(input: &[T]) -> usize {
if neighbor == goal { return steps - 1; }
new_filled.insert(neighbor);
}
- if let Some(neighbor) = maze_portal_neighbor(&portals, pos) {
+ if let Some(neighbor) = maze_portal_neighbor(&portals, pos, recursive) {
for neigh in maze_neighbors(&passages, &neighbor) {
if neighbor == goal { return steps - 1; }
new_filled.insert(neigh);
@@ -2015,7 +2073,8 @@ fn day20() {
let input = read_file("input20");
let input : Vec<&str> = input.split_terminator('\n').collect();
- println!("20a: {}", steps_through_maze(&input));
+ println!("20a: {}", steps_through_maze(&input, false));
+ println!("20b: {}", steps_through_maze(&input, true));
}
fn day21() {
@@ -2828,7 +2887,7 @@ mod tests {
" Z ",
" Z ",
];
- assert_eq!(steps_through_maze(&input), 23);
+ assert_eq!(steps_through_maze(&input, false), 23);
let input = [
" A ",
@@ -2869,7 +2928,48 @@ mod tests {
" B J C ",
" U P P ",
];
- assert_eq!(steps_through_maze(&input), 58);
+ assert_eq!(steps_through_maze(&input, false), 58);
+
+ let input = [
+ " Z L X W C ",
+ " Z P Q B K ",
+ " ###########.#.#.#.#######.############### ",
+ " #...#.......#.#.......#.#.......#.#.#...# ",
+ " ###.#.#.#.#.#.#.#.###.#.#.#######.#.#.### ",
+ " #.#...#.#.#...#.#.#...#...#...#.#.......# ",
+ " #.###.#######.###.###.#.###.###.#.####### ",
+ " #...#.......#.#...#...#.............#...# ",
+ " #.#########.#######.#.#######.#######.### ",
+ " #...#.# F R I Z #.#.#.# ",
+ " #.###.# D E C H #.#.#.# ",
+ " #.#...# #...#.# ",
+ " #.###.# #.###.# ",
+ " #.#....OA WB..#.#..ZH",
+ " #.###.# #.#.#.# ",
+ "CJ......# #.....# ",
+ " ####### ####### ",
+ " #.#....CK #......IC",
+ " #.###.# #.###.# ",
+ " #.....# #...#.# ",
+ " ###.### #.#.#.# ",
+ "XF....#.# RF..#.#.# ",
+ " #####.# ####### ",
+ " #......CJ NM..#...# ",
+ " ###.#.# #.###.# ",
+ "RE....#.# #......RF",
+ " ###.### X X L #.#.#.# ",
+ " #.....# F Q P #.#.#.# ",
+ " ###.###########.###.#######.#########.### ",
+ " #.....#...#.....#.......#...#.....#.#...# ",
+ " #####.#.###.#######.#######.###.###.#.#.# ",
+ " #.......#.......#.#.#.#.#...#...#...#.#.# ",
+ " #####.###.#####.#.#.#.#.###.###.#.###.### ",
+ " #.......#.....#.#...#...............#...# ",
+ " #############.#.#.###.################### ",
+ " A O F N ",
+ " A A D M ",
+ ];
+ assert_eq!(steps_through_maze(&input, true), 396);
}
#[test]