1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
def get_affected_boxes_if_can_move(data: list[list[str]], current_pos: tuple[int, int],
affected_box_positions: list[tuple[int, int]], direction: tuple[int, int]) -> bool:
current_char = data[current_pos[0]][current_pos[1]]
if current_char == "]":
current_pos = (current_pos[0], current_pos[1] - 1)
if current_char in affected_box_positions:
return True
if current_char != "@":
affected_box_positions.append(current_pos)
pushed_positions = []
if current_char == "@":
pushed_positions.append(direction)
elif direction == (0, 1):
pushed_positions.append((0, 2))
elif direction == (0, -1):
pushed_positions.append(direction)
else:
pushed_positions.append(direction)
pushed_positions.append((direction[0], 1))
for pushed in pushed_positions:
pushed_pos = (current_pos[0] + pushed[0], current_pos[1] + pushed[1])
pushed_char = data[pushed_pos[0]][pushed_pos[1]]
if pushed_char == "#":
return False
elif pushed_char == "[" or pushed_char == "]":
success = get_affected_boxes_if_can_move(data, pushed_pos, affected_box_positions, direction)
if not success:
return False
return True
def move(data: list[list[str]], current_pos: tuple[int, int],
current_order: str, movement_dict: dict[str, tuple[int, int]]) -> tuple[int, int]:
assert data[current_pos[0]][current_pos[1]] == "@"
direction = movement_dict[current_order]
can_move = True
steps = 0
affected_box_positions = []
success = get_affected_boxes_if_can_move(data, current_pos, affected_box_positions, direction)
if not success:
return current_pos
data[current_pos[0]][current_pos[1]] = "."
for box_pos in affected_box_positions:
data[box_pos[0]][box_pos[1]] = "."
data[box_pos[0]][box_pos[1] + 1] = "."
current_pos = (current_pos[0] + direction[0], current_pos[1] + direction[1])
data[current_pos[0]][current_pos[1]] = "@"
for box_pos in affected_box_positions:
data[box_pos[0] + direction[0]][box_pos[1] + direction[1]] = "["
data[box_pos[0] + direction[0]][box_pos[1] + direction[1] + 1] = "]"
return current_pos
def calculate_gps_data(data: list[list[str]]):
result = 0
max_cols = len(data[0])
for row_pos, row in enumerate(data):
for col_pos, char in enumerate(row):
if char == "[":
result += row_pos * 100 + col_pos
return result
movement_dirs = { "<": (0, -1), "v": (1, 0), "^": (-1, 0), ">": (0, 1) }
map_data = []
movement_data = ""
with open("input") as f:
reading_movement = False
for line in f:
line = line.strip()
if reading_movement:
movement_data += line
else:
if line == "":
reading_movement = True
else:
new_line = []
map_data.append(new_line)
for char in line:
if char == ".":
new_line.append(".")
new_line.append(".")
elif char == "#":
new_line.append("#")
new_line.append("#")
elif char == "O":
new_line.append("[")
new_line.append("]")
else:
new_line.append(char)
new_line.append(".")
for row_idx, row in enumerate(map_data):
for col_idx, char in enumerate(row):
if char == "@":
robot_row = row_idx
robot_col = col_idx
break
else:
continue
break
new_pos = (robot_row, robot_col)
for order in movement_data:
new_pos = move(map_data,new_pos, order, movement_dirs)
for line in map_data:
print("".join(line))
print(calculate_gps_data(map_data))
|