From 941b3572ccfe243cdc7d7ce93c108734a055fcf9 Mon Sep 17 00:00:00 2001 From: I A Date: Thu, 15 Dec 2022 08:11:21 -0500 Subject: [PATCH] [2022][day 15] adding part 2 solution --- 2022/AOC15.py | 95 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/2022/AOC15.py b/2022/AOC15.py index 0065fed..0d8e0f0 100644 --- a/2022/AOC15.py +++ b/2022/AOC15.py @@ -1,57 +1,96 @@ -from typing import List, Tuple, Set +import datetime +from typing import List, Tuple, Set, Dict +import parse +from _utils import read_input, timer, Solution, Point -from _utils import read_input, timer, Solution +MAX_Y = 4_000_000 -SENSOR, BEACON = 1, -1 -Y = 2_000_000 - - -def process_input(filename: str): +def process_input(filename: str) -> Tuple[Dict[Point, int], Set[Point]]: _input = read_input(filename) - import parse - - grid = set() - empty = set() + sensors = {} + beacons = set() for line in _input: x1, y1, x2, y2 = tuple( parse.parse( "Sensor at x={:d}, y={:d}: closest beacon is at x={:d}, y={:d}", line ).fixed ) - grid.add((x1, y1)) - grid.add((x2, y2)) - distance = manhattan_distance((x1, y1), (x2, y2)) + sensors[(x1, y1)] = manhattan_distance((x1, y1), (x2, y2)) + beacons.add((x2, y2)) + return sensors, beacons + + +def manhattan_distance(t1: Point, t2: Point) -> int: + x1, y1 = t1 + x2, y2 = t2 + return abs(x1 - x2) + abs(y1 - y2) + + +class Solution: + def merge(self, intervals: List[List[Point]]) -> List[List[Point]]: + intervals = sorted(intervals, key=lambda i: i[0]) + l, r = 0, 1 + + while r <= len(intervals) - 1: + if intervals[l][0] <= intervals[r][0] <= intervals[l][1]: + intervals[l][0] = min(intervals[l][0], intervals[r][0]) + intervals[l][1] = max(intervals[l][1], intervals[r][1]) + del intervals[r] + else: + l += 1 + r += 1 + + return intervals + + +def check_line(sensors: Dict[Point, int], Y: int, part1: bool) -> List[List[Point]]: + intervals = [] + + for pos, distance in sensors.items(): + x1, y1 = pos distance_to_y = abs(y1 - Y) remaining_distance = distance - distance_to_y + if remaining_distance >= 0: - for dx in range(-remaining_distance, remaining_distance + 1): - empty.add((x1 + dx, Y)) + if part1: + intervals.append([x1 - remaining_distance, x1 + remaining_distance]) + else: + min_x = max(0, x1 - remaining_distance) + max_x = min(MAX_Y, x1 + remaining_distance) + if min_x <= MAX_Y: + intervals.append([min_x, max_x]) - for pos in grid: - if pos in empty: - empty.remove(pos) - return len(empty) + return Solution().merge(intervals) -def manhattan_distance(t1, t2): - x1, y1 = t1 - x2, y2 = t2 - return abs(x1 - x2) + abs(y1 - y2) +def part1(sensors: Dict[Point, int]): + intervals = check_line(sensors, 2_000_000, part1=True) + interval_length = intervals[0][1] - intervals[0][0] + return interval_length + + +def part2(sensors: Dict[Point, int]): + for y in range(MAX_Y, 0, -1): + intervals = check_line(sensors, y, part1=False) + if len(intervals) != 1: + x = intervals[0][1] + 1 + return x * MAX_Y + y + return 0 @timer def main(filename: str) -> Solution: - grid = process_input(filename) - part_1_solution = grid - part_2_solution = 0 + sensors, beacons = process_input(filename) + part_1_solution = part1(sensors) + part_2_solution = part2(sensors) return part_1_solution, part_2_solution if __name__ == "__main__": part_1_solution, part_2_solution = main("aoc15.txt") print(f"PART 1: {part_1_solution}") # 4907780 - print(f"PART 2: {part_2_solution}") # + print(f"PART 2: {part_2_solution}") # 13639962836448 (3409990, 2836448)