Ugly day 22.
This commit is contained in:
		
							
								
								
									
										204
									
								
								2022/day22.py
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								2022/day22.py
									
									
									
									
									
								
							| @@ -2,14 +2,15 @@ | |||||||
|  |  | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  | from typing import Callable | ||||||
|  |  | ||||||
| import numpy as np | import numpy as np | ||||||
|  |  | ||||||
| VOID = 0 | VOID, EMPTY, WALL = 0, 1, 2 | ||||||
| EMPTY = 1 |  | ||||||
| WALL = 2 |  | ||||||
| TILE_FROM_CHAR = {" ": VOID, ".": EMPTY, "#": WALL} | TILE_FROM_CHAR = {" ": VOID, ".": EMPTY, "#": WALL} | ||||||
|  |  | ||||||
|  | SCORES = {"E": 0, "S": 1, "W": 2, "N": 3} | ||||||
|  |  | ||||||
|  |  | ||||||
| board_map_s, direction_s = sys.stdin.read().split("\n\n") | board_map_s, direction_s = sys.stdin.read().split("\n\n") | ||||||
|  |  | ||||||
| @@ -27,23 +28,6 @@ directions = [ | |||||||
|     int(p1) if p2 else p1 for p1, p2 in re.findall(R"(([0-9])+|L|R)", direction_s) |     int(p1) if p2 else p1 for p1, p2 in re.findall(R"(([0-9])+|L|R)", direction_s) | ||||||
| ] | ] | ||||||
|  |  | ||||||
| invert = False |  | ||||||
|  |  | ||||||
| y0 = 0 |  | ||||||
| x0 = np.where(board[0] == EMPTY)[0][0] |  | ||||||
| r0 = "E" |  | ||||||
|  |  | ||||||
| if invert: |  | ||||||
|     board = board[::-1, ::-1] |  | ||||||
|     y0 = board.shape[0] - 1 |  | ||||||
|     x0 = np.where(board[-1, :] == EMPTY)[0][-1] |  | ||||||
|     r0 = "W" |  | ||||||
|     # print( |  | ||||||
|     #     "\n".join( |  | ||||||
|     #         "".join(next(k for k, v in TILE_FROM_CHAR.items() if v == c) for c in row) |  | ||||||
|     #         for row in board |  | ||||||
|     #     ) |  | ||||||
|     # ) |  | ||||||
|  |  | ||||||
| # find on each row and column the first and last non-void | # find on each row and column the first and last non-void | ||||||
| row_first_non_void = np.argmax(board != VOID, axis=1) | row_first_non_void = np.argmax(board != VOID, axis=1) | ||||||
| @@ -52,6 +36,75 @@ col_first_non_void = np.argmax(board != VOID, axis=0) | |||||||
| col_last_non_void = board.shape[0] - np.argmax(board[::-1, :] != VOID, axis=0) - 1 | col_last_non_void = board.shape[0] - np.argmax(board[::-1, :] != VOID, axis=0) - 1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | faces = np.zeros_like(board) | ||||||
|  | size = np.gcd(board.shape[0], board.shape[1]) | ||||||
|  | for row in range(0, board.shape[0], size): | ||||||
|  |     for col in range(row_first_non_void[row], row_last_non_void[row], size): | ||||||
|  |         faces[row : row + size, col : col + size] = faces.max() + 1 | ||||||
|  |  | ||||||
|  | SIZE = np.gcd(*board.shape) | ||||||
|  |  | ||||||
|  | # TODO: deduce this from the actual cube... | ||||||
|  | faces_wrap: dict[int, dict[str, Callable[[int, int], tuple[int, int, str]]]] | ||||||
|  | if board.shape == (12, 16):  # example | ||||||
|  |     faces_wrap = { | ||||||
|  |         1: { | ||||||
|  |             "W": lambda y, x: (4, 4 + y, "S"),  # 3N | ||||||
|  |             "N": lambda y, x: (4, 11 - x, "S"),  # 2N | ||||||
|  |             "E": lambda y, x: (11 - y, 15, "W"),  # 6E | ||||||
|  |         }, | ||||||
|  |         2: { | ||||||
|  |             "W": lambda y, x: (11, 19 - y, "N"),  # 6S | ||||||
|  |             "N": lambda y, x: (0, 11 - y, "S"),  # 1N | ||||||
|  |             "S": lambda y, x: (11, 11 - x, "N"),  # 5S | ||||||
|  |         }, | ||||||
|  |         3: { | ||||||
|  |             "N": lambda y, x: (x - 4, 8, "E"),  # 1W | ||||||
|  |             "S": lambda y, x: (15 - x, 8, "E"),  # 5W | ||||||
|  |         }, | ||||||
|  |         4: {"E": lambda y, x: (8, 19 - y, "S")},  # 6N | ||||||
|  |         5: { | ||||||
|  |             "W": lambda y, x: (7, 15 - y, "N"),  # 3S | ||||||
|  |             "S": lambda y, x: (7, 11 - x, "N"),  # 2S | ||||||
|  |         }, | ||||||
|  |         6: { | ||||||
|  |             "N": lambda y, x: (19 - x, 11, "W"),  # 4E | ||||||
|  |             "E": lambda y, x: (11 - y, 11, "W"),  # 1E | ||||||
|  |             "S": lambda y, x: (19 - x, 0, "E"),  # 2W | ||||||
|  |         }, | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | else: | ||||||
|  |     faces_wrap = { | ||||||
|  |         1: { | ||||||
|  |             "W": lambda y, x: (3 * SIZE - y - 1, 0, "E"),  # 4W | ||||||
|  |             "N": lambda y, x: (2 * SIZE + x, 0, "E"),  # 6W | ||||||
|  |         }, | ||||||
|  |         2: { | ||||||
|  |             "N": lambda y, x: (4 * SIZE - 1, x - 2 * SIZE, "N"),  # 6S | ||||||
|  |             "E": lambda y, x: (3 * SIZE - y - 1, 2 * SIZE - 1, "W"),  # 5E | ||||||
|  |             "S": lambda y, x: (x - SIZE, 2 * SIZE - 1, "W"),  # 3E | ||||||
|  |         }, | ||||||
|  |         3: { | ||||||
|  |             "W": lambda y, x: (2 * SIZE, y - SIZE, "S"),  # 4N | ||||||
|  |             "E": lambda y, x: (SIZE - 1, SIZE + y, "N"),  # 2S | ||||||
|  |         }, | ||||||
|  |         4: { | ||||||
|  |             "W": lambda y, x: (3 * SIZE - y - 1, SIZE, "E"),  # 1W | ||||||
|  |             "N": lambda y, x: (SIZE + x, SIZE, "E"),  # 3W | ||||||
|  |         }, | ||||||
|  |         5: { | ||||||
|  |             "E": lambda y, x: (3 * SIZE - y - 1, 3 * SIZE - 1, "W"),  # 2E | ||||||
|  |             "S": lambda y, x: (2 * SIZE + x, SIZE - 1, "W"),  # 6E | ||||||
|  |         }, | ||||||
|  |         6: { | ||||||
|  |             "W": lambda y, x: (0, y - 2 * SIZE, "S"),  # 1N | ||||||
|  |             "E": lambda y, x: (3 * SIZE - 1, y - 2 * SIZE, "N"),  # 5S | ||||||
|  |             "S": lambda y, x: (0, x + 2 * SIZE, "S"),  # 2N | ||||||
|  |         }, | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| def wrap_part_1(y0: int, x0: int, r0: str) -> tuple[int, int, str]: | def wrap_part_1(y0: int, x0: int, r0: str) -> tuple[int, int, str]: | ||||||
|     if r0 == "E": |     if r0 == "E": | ||||||
|         return y0, row_first_non_void[y0], r0 |         return y0, row_first_non_void[y0], r0 | ||||||
| @@ -66,100 +119,29 @@ def wrap_part_1(y0: int, x0: int, r0: str) -> tuple[int, int, str]: | |||||||
|  |  | ||||||
|  |  | ||||||
| def wrap_part_2(y0: int, x0: int, r0: str) -> tuple[int, int, str]: | def wrap_part_2(y0: int, x0: int, r0: str) -> tuple[int, int, str]: | ||||||
|     if r0 == "E": |     cube = faces[y0, x0] | ||||||
|         if y0 in range(0, 4): |     assert r0 in faces_wrap[cube] | ||||||
|             y0 = board.shape[0] - y0 - 1 |     return faces_wrap[cube][r0](y0, x0) | ||||||
|             return y0, row_last_non_void[y0], "W" |  | ||||||
|         elif y0 in range(4, 8): |  | ||||||
|             print(x0, row_last_non_void[8], row_last_non_void[8] - (y0 - 4)) | def run(wrap: Callable[[int, int, str], tuple[int, int, str]]) -> tuple[int, int, str]: | ||||||
|             x0 = row_last_non_void[8] - (y0 - 4) |  | ||||||
|             return col_first_non_void[x0], x0, "S" |  | ||||||
|         else: |  | ||||||
|             y0 = board.shape[0] - y0 - 1 |  | ||||||
|             return y0, row_last_non_void[y0], "W" |  | ||||||
|     elif r0 == "S": |  | ||||||
|         if x0 in range(0, 4): |  | ||||||
|             y0 = board.shape[0] - 1 |  | ||||||
|             return y0, row_first_non_void[y0] + 3 - x0, "N" |  | ||||||
|         elif x0 in range(4, 8): |  | ||||||
|             y0 = col_last_non_void[x0] + 8 - x0 |  | ||||||
|             return y0, row_first_non_void[y0], "E" |  | ||||||
|         elif x0 in range(8, 12): |  | ||||||
|             # 8 -> 3, 9 -> 2 |  | ||||||
|             x0 = board.shape[0] - x0 - 1 |  | ||||||
|             return col_last_non_void[x0], x0, "N" |  | ||||||
|         else: |  | ||||||
|             y0 = col_first_non_void[0] + board.shape[1] - x0 - 1 |  | ||||||
|             return y0, row_first_non_void[y0], "W" |  | ||||||
|     elif r0 == "W": |  | ||||||
|         if y0 in range(0, 4): |  | ||||||
|             x0 = 4 + y0 |  | ||||||
|             return col_first_non_void[x0], x0, "S" |  | ||||||
|         elif y0 in range(4, 8): |  | ||||||
|             x0 = board.shape[1] - (y0 - 4) - 1 |  | ||||||
|             return board.shape[0] - 1, x0, "N" |  | ||||||
|         else: |  | ||||||
|             x0 = 4 + board.shape[0] - y0 - 1 |  | ||||||
|             return col_last_non_void[x0], x0, "N" |  | ||||||
|     elif r0 == "N": |  | ||||||
|         if x0 in range(0, 4): |  | ||||||
|     y0 = 0 |     y0 = 0 | ||||||
|             return y0, row_first_non_void[y0] + 3 - x0, "S" |     x0 = np.where(board[0] == EMPTY)[0][0] | ||||||
|         elif x0 in range(4, 8): |     r0 = "E" | ||||||
|             y0 = x0 - 4 |  | ||||||
|             return y0, row_first_non_void[y0], "E" |  | ||||||
|         elif x0 in range(8, 12): |  | ||||||
|             x0 = 11 - x0 |  | ||||||
|             return col_first_non_void[x0], x0, "S" |  | ||||||
|         else: |  | ||||||
|             y0 = 4 + board.shape[0] - x0 - 1 |  | ||||||
|             return y0, row_last_non_void[y0], "W" |  | ||||||
|  |  | ||||||
|     assert False |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # for i in range(4): |  | ||||||
| #     print(wrap_part_2(i, 8 + i - 1, "E")) |  | ||||||
|  |  | ||||||
| # exit() |  | ||||||
|  |  | ||||||
|  |  | ||||||
| wrap = wrap_part_2 |  | ||||||
|  |  | ||||||
| # directions = directions[:5] |  | ||||||
|  |  | ||||||
| print(y0, x0, r0) |  | ||||||
|  |  | ||||||
| facing = np.zeros_like(board, dtype=str) |  | ||||||
| facing.fill(" ") |  | ||||||
| facing[board != VOID] = "." |  | ||||||
| facing[board == WALL] = "#" |  | ||||||
|  |  | ||||||
| for direction in directions: |  | ||||||
|     # print(f"{y0} {x0} {r0} ({direction})") |  | ||||||
|     # r1 = {"N": "S", "S": "N", "W": "E", "E": "W"}[r0] |  | ||||||
|     # print(f"{board.shape[0] - y0 - 1} {board.shape[1] - x0 - 1} {r1} ({direction})") |  | ||||||
|     facing[y0, x0] = {"E": ">", "W": "<", "N": "^", "S": "v"}[r0] |  | ||||||
|  |  | ||||||
|  |     for direction in directions: | ||||||
|         if isinstance(direction, int): |         if isinstance(direction, int): | ||||||
|             while direction > 0: |             while direction > 0: | ||||||
|                 if r0 == "E": |                 if r0 == "E": | ||||||
|                     xi = np.where(board[y0, x0 + 1 : x0 + direction + 1] == WALL)[0] |                     xi = np.where(board[y0, x0 + 1 : x0 + direction + 1] == WALL)[0] | ||||||
|                 # if y0 == 12 and x0 == 81: |  | ||||||
|                 #     print( |  | ||||||
|                 #         xi, |  | ||||||
|                 #         board[y0, x0 + 1 : x0 + direction], |  | ||||||
|                 #         board[y0, x0 + direction], |  | ||||||
|                 #     ) |  | ||||||
|                     if len(xi): |                     if len(xi): | ||||||
|                     # print("E1") |  | ||||||
|                         x0 = x0 + xi[0] |                         x0 = x0 + xi[0] | ||||||
|                         direction = 0 |                         direction = 0 | ||||||
|                     elif ( |                     elif ( | ||||||
|                         x0 + direction < board.shape[1] |                         x0 + direction < board.shape[1] | ||||||
|                         and board[y0, x0 + direction] == EMPTY |                         and board[y0, x0 + direction] == EMPTY | ||||||
|                     ): |                     ): | ||||||
|                     # print("E2") |  | ||||||
|                         x0 = x0 + direction |                         x0 = x0 + direction | ||||||
|                         direction = 0 |                         direction = 0 | ||||||
|                     else: |                     else: | ||||||
| @@ -231,19 +213,13 @@ for direction in directions: | |||||||
|                 "S": {"L": "E", "R": "W"}, |                 "S": {"L": "E", "R": "W"}, | ||||||
|             }[r0][direction] |             }[r0][direction] | ||||||
|  |  | ||||||
| facing[y0, x0] = {"E": ">", "W": "<", "N": "^", "S": "v"}[r0] |     return y0, x0, r0 | ||||||
|  |  | ||||||
| print("\n".join(map("".join, facing))) |  | ||||||
|  |  | ||||||
| if invert: | y1, x1, r1 = run(wrap_part_1) | ||||||
|     print(y0, x0, r0, "->", end=" ") | answer_1 = 1000 * (1 + y1) + 4 * (1 + x1) + SCORES[r1] | ||||||
|     x0, y0, r0 = ( |  | ||||||
|         board.shape[1] - x0 - 1, |  | ||||||
|         board.shape[0] - y0 - 1, |  | ||||||
|         {"N": "S", "S": "N", "W": "E", "E": "W"}[r0], |  | ||||||
|     ) |  | ||||||
| print(y0, x0, r0) |  | ||||||
|  |  | ||||||
| score = {"E": 0, "S": 1, "W": 2, "N": 3} |  | ||||||
| answer_1 = 1000 * (1 + y0) + 4 * (1 + x0) + score[r0] |  | ||||||
| print(f"answer 1 is {answer_1}") | print(f"answer 1 is {answer_1}") | ||||||
|  |  | ||||||
|  | y2, x2, r2 = run(wrap_part_2) | ||||||
|  | answer_2 = 1000 * (1 + y2) + 4 * (1 + x2) + SCORES[r2] | ||||||
|  | print(f"answer 2 is {answer_2}") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user