From b8c11565c7d41ca88091d71eb31cf3466a869975 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Fri, 22 Nov 2024 09:07:41 +0100 Subject: [PATCH] day22 --- answer_cache.json | 10 +++ day22.py | 152 ++++++++++++++++++++++++++++++++++++++++++++ inputs/input22 | 2 + inputs/input22_test | 2 + 4 files changed, 166 insertions(+) create mode 100644 day22.py create mode 100644 inputs/input22 create mode 100644 inputs/input22_test diff --git a/answer_cache.json b/answer_cache.json index fb99afd..a99dc72 100644 --- a/answer_cache.json +++ b/answer_cache.json @@ -152,5 +152,15 @@ "wrong": [], "correct": 537 } + }, + "22": { + "1": { + "wrong": [], + "correct": 8681 + }, + "2": { + "wrong": [], + "correct": 1070 + } } } \ No newline at end of file diff --git a/day22.py b/day22.py new file mode 100644 index 0000000..329bf29 --- /dev/null +++ b/day22.py @@ -0,0 +1,152 @@ +from enum import Enum +from heapq import heappush, heapify, heappop +from tools.aoc import AOCDay +from tools.coordinate import Coordinate +from tools.grid import Grid +from typing import Any + + +class RegionType(int, Enum): + ROCKY = 0 + WET = 1 + NARROW = 2 + + +class Tools(int, Enum): + NEITHER = 0 + TORCH = 1 + CLIMBING_GEAR = 2 + + +COMMON_TOOLS = { + RegionType.ROCKY: {Tools.TORCH, Tools.CLIMBING_GEAR}, + RegionType.WET: {Tools.NEITHER, Tools.CLIMBING_GEAR}, + RegionType.NARROW: {Tools.NEITHER, Tools.TORCH}, +} + + +def get_common_tool(from_region_type: RegionType, to_region_type: RegionType) -> Tools: + return (COMMON_TOOLS[from_region_type] & COMMON_TOOLS[to_region_type]).pop() + + +class Cave(Grid): + def __init__(self, depth: int, target_x: int, target_y: int): + super().__init__() + self.depth = depth + self.target_x = target_x + self.target_y = target_y + self.set(Coordinate(0, 0), self.get_erosion_level(Coordinate(0, 0))) + + def get_geologic_index(self, at: Coordinate) -> int: + if at.x == at.y == 0: + return 0 + elif at.x == self.target_x and at.y == self.target_y: + return 0 + elif at.y == 0: + return at.x * 16807 + elif at.x == 0: + return at.y * 48271 + else: + return self.get(at - Coordinate(1, 0)) * self.get(at - Coordinate(0, 1)) + + def get_region_type(self, at: Coordinate) -> RegionType: + return RegionType(self.get(at) % 3) + + def get_erosion_level(self, at: Coordinate) -> int: + return (self.get_geologic_index(at) + self.depth) % 20183 + + def get(self, at: Coordinate) -> int: + if not self.isSet(at): + self.set(at, self.get_erosion_level(at)) + + return super().get(at) + + def get_risk_level(self) -> int: + risk = 0 + for x in range(0, self.target_x + 1): + for y in range(0, self.target_y + 1): + at = Coordinate(x, y) + risk += int(self.get_region_type(at)) + + return risk + + +class Day(AOCDay): + inputs = [ + [ + (114, "input22_test"), + (8681, "input22"), + ], + [ + (45, "input22_test"), + (1070, "input22"), + ], + ] + + def get_params(self) -> (int, int, int): + """(depth, target_x, target_y)""" + lines = self.getInput() + depth = int(lines[0].split()[1]) + target_x, target_y = map(int, lines[1].split()[1].split(",")) + return depth, target_x, target_y + + def part1(self) -> Any: + cave = Cave(*self.get_params()) + return cave.get_risk_level() + + def part2(self) -> Any: + params = self.get_params() + target = Coordinate(*params[1:]) + cave = Cave(*params) + queue = [(0, 0, Tools.TORCH, Coordinate(0, 0))] + heapify(queue) + visited = set() + + target_dist, target_tool = None, None + while len(queue) > 0: + _, current_dist, current_tool, at = heappop(queue) + if (at, current_tool) in visited: + continue + + visited.add((at, current_tool)) + + if at == target: + target_dist = current_dist + target_tool = current_tool + break + + for next in at.getNeighbours(includeDiagonal=False, minX=0, minY=0): + region_type_at = cave.get_region_type(at) + region_type_next = cave.get_region_type(next) + if region_type_at == region_type_next: + common_tool = current_tool + else: + common_tool = get_common_tool(region_type_at, region_type_next) + + if common_tool == current_tool: + heappush( + queue, (next.getDistanceTo(target) + current_dist + 1, current_dist + 1, common_tool, next) + ) + else: + heappush( + queue, (next.getDistanceTo(target) + current_dist + 7, current_dist + 8, common_tool, next) + ) + + if target_tool != Tools.TORCH: + target_dist += 7 + while queue: + _, current_dist, current_tool, at = heappop(queue) + if at != target or current_dist >= target_dist: + continue + + if current_tool == Tools.TORCH: + target_dist = current_dist + elif current_dist + 7 < target_dist: + target_dist = current_dist + 7 + + return target_dist + + +if __name__ == "__main__": + day = Day(2018, 22) + day.run(verbose=True) diff --git a/inputs/input22 b/inputs/input22 new file mode 100644 index 0000000..d341d05 --- /dev/null +++ b/inputs/input22 @@ -0,0 +1,2 @@ +depth: 5616 +target: 10,785 diff --git a/inputs/input22_test b/inputs/input22_test new file mode 100644 index 0000000..058dd01 --- /dev/null +++ b/inputs/input22_test @@ -0,0 +1,2 @@ +depth: 510 +target: 10,10 \ No newline at end of file