Spaces:
Running
Running
| def parse_input(file): | |
| with open(file, 'r') as f: | |
| lines = f.readlines() | |
| # Separate the map and the movement sequence | |
| map_lines = [] | |
| move_sequence = "" | |
| for line in lines: | |
| if line.startswith('#'): | |
| map_lines.append(line.strip()) | |
| else: | |
| move_sequence += line.strip() | |
| return map_lines, move_sequence | |
| def find_robot_and_boxes(map_lines): | |
| robot_pos = None | |
| boxes = set() | |
| for r, line in enumerate(map_lines): | |
| for c, char in enumerate(line): | |
| if char == '@': | |
| robot_pos = (r, c) | |
| elif char == 'O': | |
| boxes.add((r, c)) | |
| return robot_pos, boxes | |
| def move_robot_and_boxes(map_lines, robot_pos, boxes, move_sequence): | |
| directions = {'<': (0, -1), '>': (0, 1), '^': (-1, 0), 'v': (1, 0)} | |
| max_r = len(map_lines) | |
| max_c = len(map_lines[0]) | |
| for move in move_sequence: | |
| dr, dc = directions[move] | |
| new_robot_pos = (robot_pos[0] + dr, robot_pos[1] + dc) | |
| if map_lines[new_robot_pos[0]][new_robot_pos[1]] == '#': | |
| continue # Robot can't move into a wall | |
| if new_robot_pos in boxes: | |
| new_box_pos = (new_robot_pos[0] + dr, new_robot_pos[1] + dc) | |
| if map_lines[new_box_pos[0]][new_box_pos[1]] == '#' or new_box_pos in boxes: | |
| continue # Box can't be pushed into a wall or another box | |
| boxes.remove(new_robot_pos) | |
| boxes.add(new_box_pos) | |
| robot_pos = new_robot_pos | |
| return robot_pos, boxes | |
| def calculate_gps_sum(boxes, max_r, max_c): | |
| gps_sum = 0 | |
| for r, c in boxes: | |
| gps_sum += 100 * r + c | |
| return gps_sum | |
| def part_one(file): | |
| map_lines, move_sequence = parse_input(file) | |
| robot_pos, boxes = find_robot_and_boxes(map_lines) | |
| robot_pos, boxes = move_robot_and_boxes(map_lines, robot_pos, boxes, move_sequence) | |
| return calculate_gps_sum(boxes, len(map_lines), len(map_lines[0])) | |
| def scale_map(map_lines): | |
| scaled_map = [] | |
| for line in map_lines: | |
| scaled_line = "" | |
| for char in line: | |
| if char == '#': | |
| scaled_line += "##" | |
| elif char == 'O': | |
| scaled_line += "[]" | |
| elif char == '.': | |
| scaled_line += ".." | |
| elif char == '@': | |
| scaled_line += "@." | |
| scaled_map.append(scaled_line) | |
| return scaled_map | |
| def find_robot_and_boxes_scaled(map_lines): | |
| robot_pos = None | |
| boxes = set() | |
| for r, line in enumerate(map_lines): | |
| for c in range(0, len(line), 2): | |
| char = line[c:c+2] | |
| if char == '@.': | |
| robot_pos = (r, c) | |
| elif char == '[]': | |
| boxes.add((r, c)) | |
| return robot_pos, boxes | |
| def move_robot_and_boxes_scaled(map_lines, robot_pos, boxes, move_sequence): | |
| directions = {'<': (0, -2), '>': (0, 2), '^': (-1, 0), 'v': (1, 0)} | |
| max_r = len(map_lines) | |
| max_c = len(map_lines[0]) | |
| for move in move_sequence: | |
| dr, dc = directions[move] | |
| new_robot_pos = (robot_pos[0] + dr, robot_pos[1] + dc) | |
| if map_lines[new_robot_pos[0]][new_robot_pos[1]] == '#' or map_lines[new_robot_pos[0]][new_robot_pos[1]] == '#': | |
| continue # Robot can't move into a wall | |
| if new_robot_pos in boxes: | |
| new_box_pos = (new_robot_pos[0] + dr, new_robot_pos[1] + dc) | |
| if map_lines[new_box_pos[0]][new_box_pos[1]] == '#' or new_box_pos in boxes: | |
| continue # Box can't be pushed into a wall or another box | |
| boxes.remove(new_robot_pos) | |
| boxes.add(new_box_pos) | |
| robot_pos = new_robot_pos | |
| return robot_pos, boxes | |
| def part_two(file): | |
| map_lines, move_sequence = parse_input(file) | |
| scaled_map_lines = scale_map(map_lines) | |
| robot_pos, boxes = find_robot_and_boxes_scaled(scaled_map_lines) | |
| robot_pos, boxes = move_robot_and_boxes_scaled(scaled_map_lines, robot_pos, boxes, move_sequence) | |
| return calculate_gps_sum(boxes, len(scaled_map_lines), len(scaled_map_lines[0])) | |
| file = "input.txt" | |
| result1 = part_one(file) | |
| print(result1) | |
| result2 = part_two(file) | |
| print(result2) |