From ea1c18ed67c876543a258753f98e96b2db09b523 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Fri, 22 Dec 2023 11:06:22 +0000 Subject: [PATCH] Day 22 Done --- 2023/22/part 1 solution.py | 130 ++++++++++++++++++++++++++++++++++++ 2023/22/part 2 solution.py | 133 +++++++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 2023/22/part 1 solution.py create mode 100644 2023/22/part 2 solution.py diff --git a/2023/22/part 1 solution.py b/2023/22/part 1 solution.py new file mode 100644 index 0000000..db6536f --- /dev/null +++ b/2023/22/part 1 solution.py @@ -0,0 +1,130 @@ +from copy import deepcopy + +with open(r'advent_of_code\2023\22\input.txt', 'r') as file: + input = file.read() + +test_input = '''1,0,1~1,2,1 +0,0,2~2,0,2 +0,2,3~2,2,3 +0,0,4~0,2,4 +2,0,5~2,2,5 +0,1,6~2,1,6 +1,1,8~1,1,9''' + +def parse_input(input_data): + # Split the input data into lines + lines = input_data.split('\n') + + # Initialize the list of bricks + bricks = [] + + # Parse each line into a brick + for line in lines: + start, end = line.split('~') + start_x, start_y, start_z = map(int, start.split(',')) + end_x, end_y, end_z = map(int, end.split(',')) + + # Initialize the current brick + current_brick = [] + + # Add all points in the brick to the current brick + if start_x == end_x and start_y == end_y: + assert start_z <= end_z + for z in range(start_z, end_z + 1): + current_brick.append((start_x, start_y, z)) + elif start_x == end_x and start_z == end_z: + assert start_y <= end_y + for y in range(start_y, end_y + 1): + current_brick.append((start_x, y, start_z)) + elif start_y == end_y and start_z == end_z: + assert start_x <= end_x + for x in range(start_x, end_x + 1): + current_brick.append((x, start_y, start_z)) + else: + assert False + + # Add the current brick to the list of bricks + bricks.append(current_brick) + + return bricks + +def move_bricks_down(bricks): + # Initialize the set of seen points + seen_points = set() + + # Add all points in the bricks to the set of seen points + for brick in bricks: + for point in brick: + seen_points.add(point) + + # Move all bricks down until they can't move anymore + while True: + moved = False + for i, brick in enumerate(bricks): + can_move = True + for x, y, z in brick: + if z == 1 or ((x, y, z - 1) in seen_points and (x, y, z - 1) not in brick): + can_move = False + if can_move: + moved = True + for point in brick: + seen_points.discard(point) + seen_points.add((point[0], point[1], point[2] - 1)) + bricks[i] = [(x, y, z - 1) for x, y, z in brick] + if not moved: + break + + return bricks, seen_points + +def count_stable_bricks(bricks, seen_points): + + # Initialize the counts of stable bricks and fallen bricks + stable_bricks_count = 0 + + # Check each brick + for i, brick in enumerate(bricks): + # Make a copy of the seen points and bricks + current_seen_points = deepcopy(seen_points) + current_bricks = deepcopy(bricks) + + # Remove the current brick from the seen points + for point in brick: + current_seen_points.discard(point) + + # Initialize the set of fallen bricks + fallen_bricks = set() + + # Move all other bricks down until they can't move anymore + while True: + moved = False + for j, other_brick in enumerate(current_bricks): + if j == i: + continue + can_move = True + for x, y, z in other_brick: + if z == 1 or ((x, y, z - 1) in current_seen_points and (x, y, z - 1) not in other_brick): + can_move = False + if can_move: + fallen_bricks.add(j) + for point in other_brick: + current_seen_points.discard(point) + current_seen_points.add((point[0], point[1], point[2] - 1)) + current_bricks[j] = [(x, y, z - 1) for x, y, z in other_brick] + moved = True + if not moved: + break + + # Update the counts of stable bricks and fallen bricks + if len(fallen_bricks) == 0: + stable_bricks_count += 1 + + return stable_bricks_count + +def main(): + input_data = input + bricks = parse_input(input_data) + bricks, seen_points = move_bricks_down(bricks) + stable_bricks_count = count_stable_bricks(bricks, seen_points) + print(stable_bricks_count) + +main() \ No newline at end of file diff --git a/2023/22/part 2 solution.py b/2023/22/part 2 solution.py new file mode 100644 index 0000000..6f1cba4 --- /dev/null +++ b/2023/22/part 2 solution.py @@ -0,0 +1,133 @@ +from copy import deepcopy + +with open(r'advent_of_code\2023\22\input.txt', 'r') as file: + input = file.read() + +test_input = '''1,0,1~1,2,1 +0,0,2~2,0,2 +0,2,3~2,2,3 +0,0,4~0,2,4 +2,0,5~2,2,5 +0,1,6~2,1,6 +1,1,8~1,1,9''' + +def parse_input(input_data): + # Split the input data into lines + lines = input_data.split('\n') + + # Initialize the list of bricks + bricks = [] + + # Parse each line into a brick + for line in lines: + start, end = line.split('~') + start_x, start_y, start_z = map(int, start.split(',')) + end_x, end_y, end_z = map(int, end.split(',')) + + # Initialize the current brick + current_brick = [] + + # Add all points in the brick to the current brick + if start_x == end_x and start_y == end_y: + assert start_z <= end_z + for z in range(start_z, end_z + 1): + current_brick.append((start_x, start_y, z)) + elif start_x == end_x and start_z == end_z: + assert start_y <= end_y + for y in range(start_y, end_y + 1): + current_brick.append((start_x, y, start_z)) + elif start_y == end_y and start_z == end_z: + assert start_x <= end_x + for x in range(start_x, end_x + 1): + current_brick.append((x, start_y, start_z)) + else: + assert False + + # Add the current brick to the list of bricks + bricks.append(current_brick) + + return bricks + +def move_bricks_down(bricks): + # Initialize the set of seen points + seen_points = set() + + # Add all points in the bricks to the set of seen points + for brick in bricks: + for point in brick: + seen_points.add(point) + + # Move all bricks down until they can't move anymore + while True: + moved = False + for i, brick in enumerate(bricks): + can_move = True + for x, y, z in brick: + if z == 1 or ((x, y, z - 1) in seen_points and (x, y, z - 1) not in brick): + can_move = False + if can_move: + moved = True + for point in brick: + seen_points.discard(point) + seen_points.add((point[0], point[1], point[2] - 1)) + bricks[i] = [(x, y, z - 1) for x, y, z in brick] + if not moved: + break + + return bricks, seen_points + +def count_stable_bricks(bricks, seen_points): + + # Initialize the counts of stable bricks and fallen bricks + stable_bricks_count = 0 + fallen_bricks_count = 0 + + # Check each brick + for i, brick in enumerate(bricks): + # Make a copy of the seen points and bricks + current_seen_points = deepcopy(seen_points) + current_bricks = deepcopy(bricks) + + # Remove the current brick from the seen points + for point in brick: + current_seen_points.discard(point) + + # Initialize the set of fallen bricks + fallen_bricks = set() + + # Move all other bricks down until they can't move anymore + while True: + moved = False + for j, other_brick in enumerate(current_bricks): + if j == i: + continue + can_move = True + for x, y, z in other_brick: + if z == 1 or ((x, y, z - 1) in current_seen_points and (x, y, z - 1) not in other_brick): + can_move = False + if can_move: + fallen_bricks.add(j) + for point in other_brick: + current_seen_points.discard(point) + current_seen_points.add((point[0], point[1], point[2] - 1)) + current_bricks[j] = [(x, y, z - 1) for x, y, z in other_brick] + moved = True + if not moved: + break + + # Update the counts of stable bricks and fallen bricks + if len(fallen_bricks) == 0: + stable_bricks_count += 1 + fallen_bricks_count += len(fallen_bricks) + + return stable_bricks_count, fallen_bricks_count + +def main(): + input_data = input + bricks = parse_input(input_data) + bricks, seen_points = move_bricks_down(bricks) + stable_bricks_count, fallen_bricks_count = count_stable_bricks(bricks, seen_points) + print(stable_bricks_count) + print(fallen_bricks_count) + +main() \ No newline at end of file