From f9c1e152c33b0f745edb55555156e79cca1008ab Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Mon, 18 Dec 2023 08:02:58 +0000 Subject: [PATCH] 2023: d18: ex1: add solution --- 2023/d18/ex1/ex1.py | 89 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 2023/d18/ex1/ex1.py diff --git a/2023/d18/ex1/ex1.py b/2023/d18/ex1/ex1.py new file mode 100755 index 0000000..be11cb2 --- /dev/null +++ b/2023/d18/ex1/ex1.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import itertools +import sys +from enum import StrEnum +from typing import NamedTuple + + +class Point(NamedTuple): + x: int + y: int + + +class Direction(StrEnum): + UP = "U" + DOWN = "D" + LEFT = "L" + RIGHT = "R" + + def apply(self, pos: Point, n: int = 1) -> Point: + DIRECTIONS = { + "U": Point(-1, 0), + "D": Point(1, 0), + "L": Point(0, -1), + "R": Point(0, 1), + } + dx, dy = DIRECTIONS[self.value] + return Point(pos.x + dx * n, pos.y + dy * n) + + +DigPlanStep = tuple[Direction, int] +DigPlan = list[DigPlanStep] + + +def solve(input: list[str]) -> int: + def parse_line(line: str) -> DigPlanStep: + dir, n, _ = line.split() + return Direction(dir), int(n) + + def parse(input: list[str]) -> DigPlan: + return list(map(parse_line, input)) + + def dig_trench(plan: DigPlan) -> list[Point]: + points = [Point(0, 0)] + + for direction, n in plan: + points.append(direction.apply(points[-1], n)) + # The trench should loop back to the start, make sure we don't count it twice + if points[-1] == Point(0, 0): + del points[-1] + + return points + + def lagoon_volume(trench: list[Point]) -> int: + def shoelace_area(points: list[Point]) -> int: + # Must be integer because pipes follow the grid, and can't cut squares in half + return abs( + sum( + (points[i - 1].x * points[i].y) - (points[i].x * points[i - 1].y) + for i in range(len(points)) + ) + // 2 + ) + + def perimeter(points: list[Point]) -> int: + res = 0 + + for p, n in itertools.pairwise(itertools.chain(points, [points[0]])): + res += abs(n.x - p.x) + abs(n.y - p.y) + + return res + + area = shoelace_area(trench) + trench_points = perimeter(trench) + interior_points = area - trench_points // 2 + 1 + return interior_points + trench_points + + plan = parse(input) + trench = dig_trench(plan) + return lagoon_volume(list(trench)) + + +def main() -> None: + input = sys.stdin.read().splitlines() + print(solve(input)) + + +if __name__ == "__main__": + main()