def parse_schematic(lines): heights = [] max_height = len(lines) # Find the width of the schematic width = len(lines[0]) for col in range(width): # For each column, count from top or bottom depending on type if lines[0][col] == '#': # Lock (count from top) height = 0 for row in range(max_height): if lines[row][col] == '#': height += 1 else: break heights.append(height) else: # Key (count from bottom) height = 0 for row in range(max_height-1, -1, -1): if lines[row][col] == '#': height += 1 else: break heights.append(height) return heights def are_compatible(lock, key): if len(lock) != len(key): return False # Check if any column's combined height exceeds available space for l, k in zip(lock, key): if l + k > 6: # 7 rows (0-6), so max height is 6 return False return True def solve_part1(filename): with open(filename, 'r') as f: content = f.read().strip() # Split into individual schematics schematics = content.split('\n\n') locks = [] keys = [] # Parse each schematic for schematic in schematics: lines = schematic.split('\n') # If top row has #, it's a lock if lines[0].count('#') > 0: locks.append(parse_schematic(lines)) else: keys.append(parse_schematic(lines)) # Count compatible pairs compatible_pairs = 0 for lock in locks: for key in keys: if are_compatible(lock, key): compatible_pairs += 1 return str(compatible_pairs) def solve_part2(filename): # Part 2 has no computation requirement return "Merry Christmas!" # Print solutions print(solve_part1("./input.txt")) print(solve_part2("./input.txt"))