Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- Advent of Code 2022 Day 22
- """
- import re
- import sys
- from advent_tools import get_daily_input
- DAY = 22
- TEST = sys.argv[1] == "test" if len(sys.argv) > 1 else False
- TEST_DATA = """
- ...#
- .#..
- #...
- ....
- ...#.......#
- ........#...
- ..#....#....
- ..........#.
- ...#....
- .....#..
- .#......
- ......#.
- 10R5L5R10L4R5L5
- """
- if TEST:
- def get_daily_input(_):
- for line in TEST_DATA.strip("\n").split("\n"):
- yield line.strip("\n")
- def load_data() -> tuple[list[str], list[str]]:
- data_stream = get_daily_input(DAY)
- map_data: list[str] = []
- path_data: list[str] = []
- for d in data_stream:
- if d:
- map_data.append(d)
- else:
- path_data = re.findall(r"\d+|[LR]", next(data_stream))
- width = max(len(m) for m in map_data)
- return list([m.ljust(width) for m in map_data]), path_data
- class MonkeyMap:
- adjacent = {
- "u": "rflb", "d": "rblf",
- "f": "rdlu", "b": "ldru",
- "l": "fdbu", "r": "bdfu"
- }
- facings = ">v<^"
- def __init__(self, mm):
- self.map = mm
- self.height = len(mm)
- self.width = len(mm[0])
- self.face_size = self.find_face_size(self.height, self.width)
- self.face_map = self.build_face_map()
- def build_face_map(self):
- def _add_sides(r_in: int, c_in: int) -> None:
- cf, ce = face_map[r_in][c_in]
- for r, c, d, e in [(r_in - 1, c_in, 3, 1), (r_in + 1, c_in, 1, 3),
- (r_in, c_in - 1, 2, 0), (r_in, c_in + 1, 0, 2)]:
- if 0 <= r < len(face_map) \
- and 0 <= c < len(face_map[0]) \
- and not face_map[r][c] \
- and self.map[r * self.face_size][c * self.face_size] != " ":
- nf = ce[d]
- ne = self.adjacent[nf]
- while ne[e] != cf:
- ne = ne[1:] + ne[0]
- face_map[r][c] = (nf, ne)
- _add_sides(r, c)
- face_map: list[list[tuple[str, str] | None]] = [
- [None for _ in range(self.width // self.face_size)]
- for _ in range(self.height // self.face_size)
- ]
- first_face = (0, re.search(r"[.#]", self.map[0]).start() // self.face_size)
- face_map[0][first_face[1]] = ("u", "rflb")
- _add_sides(*first_face)
- return face_map
- def next_position_2d(self, r: int, c: int, f: str) -> tuple[int, int]:
- if f == ">":
- if c + 1 < self.width and self.map[r][c + 1] == ".":
- c += 1
- elif c + 1 >= self.width or self.map[r][c + 1] == " ":
- nc = c
- while nc - 1 >= 0 and self.map[r][nc - 1] != " ":
- nc -= 1
- if self.map[r][nc] == ".":
- c = nc
- elif f == "<":
- if c > 0 and self.map[r][c - 1] == ".":
- c -= 1
- elif c - 1 < 0 or self.map[r][c - 1] == " ":
- nc = c
- while nc + 1 < self.width and self.map[r][nc + 1] != " ":
- nc += 1
- if self.map[r][nc] == ".":
- c = nc
- elif f == "v":
- if r + 1 < self.height and self.map[r + 1][c] == ".":
- r += 1
- elif r + 1 >= self.height or self.map[r + 1][c] == " ":
- nr = r
- while nr - 1 >= 0 and self.map[nr - 1][c] != " ":
- nr -= 1
- if self.map[nr][c] == ".":
- r = nr
- elif f == "^":
- if r > 0 and self.map[r - 1][c] == ".":
- r -= 1
- elif r - 1 < 0 or self.map[r - 1][c] == " ":
- nr = r
- while nr + 1 < self.height and self.map[nr + 1][c] != " ":
- nr += 1
- if self.map[nr][c] == ".":
- r = nr
- return r, c
- def next_position_3d(self, r: int, c: int, f: str) -> tuple[int, int, str]:
- def _find_face(target_face: str) -> tuple[int, int]:
- for i in range(len(self.face_map)):
- for j in range(len(self.face_map[i])):
- if self.face_map[i][j] and self.face_map[i][j][0] == target_face:
- return i, j
- nr, nc, nf = r, c, f
- if f == ">" and c + 1 < self.width and self.map[r][c + 1] != " ":
- nc += 1
- elif f == "<" and c > 0 and self.map[r][c - 1] != " ":
- nc -= 1
- elif f == "^" and r > 0 and self.map[r - 1][c] != " ":
- nr -= 1
- elif f == "v" and r + 1 < self.height and self.map[r + 1][c] != " ":
- nr += 1
- else:
- cf_name, cf_edges = self.face_map[r // self.face_size][c // self.face_size]
- nf_name = cf_edges[self.facings.find(f)]
- nf_map_row, nf_map_col = _find_face(nf_name)
- nf_edges = self.face_map[nf_map_row][nf_map_col][1]
- nf = self.facings[nf_edges.find(cf_name) - 2]
- nr = nf_map_row * self.face_size + (
- (self.face_size - 1) if nf == "^" else 0
- )
- nc = nf_map_col * self.face_size + (
- (self.face_size - 1) if nf == "<" else 0
- )
- if (f == ">" and nf == "v") or (f == "<" and nf == "^"): # 90 cw h to v
- nc += self.face_size - 1 - r % self.face_size
- elif (f == "^" and nf == ">") or (f == "v" and nf == "<"): # 90 cw v to h
- nr += c % self.face_size
- elif (f == ">" and nf == "^") or (f == "<" and nf == "v"): # 90 ccw h to v
- nc += r % self.face_size
- elif (f == "v" and nf == ">") or (f == "^" and nf == "<"): # 90 ccw v to h
- nr += self.face_size - 1 - c % self.face_size
- elif (f == ">" and nf == "<") or (f == "<" and nf == ">"): # 180 horiz
- nr += self.face_size - 1 - r % self.face_size
- elif (f == "^" and nf == "v") or (f == "v" and nf == "^"): # 180 vert
- nc += self.face_size - 1 - c % self.face_size
- elif (f == "<" and nf == "<") or (f == ">" and nf == ">"): # 0 horiz
- nr += r % self.face_size
- elif (f == "^" and nf == "^") or (f == "v" and nf == "v"): # 0 vert
- nc += c % self.face_size
- if self.map[nr][nc] == ".":
- r, c, f = nr, nc, nf
- return r, c, f
- def walk_map(self, path: list[str], cube: bool = False) -> int:
- row, column = 0, self.map[0].find(".")
- facing = ">"
- for p in path:
- if p.isnumeric():
- for _ in range(int(p)):
- if cube:
- row, column, facing = self.next_position_3d(row, column, facing)
- else:
- row, column = self.next_position_2d(row, column, facing)
- elif p == "L":
- facing = self.facings[self.facings.find(facing) - 1]
- else:
- facing = self.facings[(self.facings.find(facing) + 1) % 4]
- return 1000 * (row + 1) + 4 * (column + 1) + self.facings.find(facing)
- @classmethod
- def find_face_size(cls, h, w) -> int:
- for x, y in [(2, 5), (3, 4), (4, 3), (5, 2)]:
- if h // x == w // y:
- return h // x
- def main():
- monkey_map_data, path_data = load_data()
- monkey_map = MonkeyMap(monkey_map_data)
- print(f"Part 1: {monkey_map.walk_map(path_data)}")
- print(f"Part 2: {monkey_map.walk_map(path_data, cube=True)}")
- if __name__ == "__main__":
- main()
- """
- Part 1: 75254
- Part 2: 108311
- """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement