From a35ae47246b0c493d8927eaf535df80094e75f5a Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Tue, 10 Dec 2024 00:20:29 -0500 Subject: [PATCH] 2024: d10: ex2: add solution --- 2024/d10/ex2/ex2.py | 61 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100755 2024/d10/ex2/ex2.py diff --git a/2024/d10/ex2/ex2.py b/2024/d10/ex2/ex2.py new file mode 100755 index 0000000..4297e62 --- /dev/null +++ b/2024/d10/ex2/ex2.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import sys +from collections.abc import Iterator +from typing import NamedTuple + + +class Point(NamedTuple): + x: int + y: int + + def neighbours(self) -> Iterator["Point"]: + for dx, dy in ( + (-1, 0), + (1, 0), + (0, -1), + (0, 1), + ): + yield Point(self.x + dx, self.y + dy) + + +TopoMap = dict[Point, int] + + +def solve(input: str) -> int: + def parse(input: list[str]) -> TopoMap: + return { + Point(x, y): int(c) + for x, line in enumerate(input) + for y, c in enumerate(line) + } + + def find_trail_heads(map: TopoMap) -> set[Point]: + return {p for p, height in map.items() if height == 0} + + def rate_trail(map: TopoMap, start: Point) -> int: + def helper(pos: Point) -> int: + if map[pos] == 9: + return 1 + res = 0 + for n in pos.neighbours(): + if map.get(n, -1) != (map[pos] + 1): + continue + res += helper(n) + return res + + assert map[start] == 0 # Sanity check + return helper(start) + + map = parse(input.splitlines()) + trail_heads = find_trail_heads(map) + return sum(rate_trail(map, head) for head in sorted(trail_heads)) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()