summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Kramkowski <tomasz@kramkow.ski>2023-12-10 13:05:33 +0000
committerTomasz Kramkowski <tomasz@kramkow.ski>2023-12-10 13:05:33 +0000
commit4cb37bc59b695192ffc95fd686bea05e1bd931ab (patch)
tree768b18d4118fc266b067a70809dbe0618ab291e7
parent7bc4e3f0667b04ad451fc44c3dda2f5b1a5d9164 (diff)
downloadaoc2023-4cb37bc59b695192ffc95fd686bea05e1bd931ab.tar.gz
aoc2023-4cb37bc59b695192ffc95fd686bea05e1bd931ab.tar.xz
aoc2023-4cb37bc59b695192ffc95fd686bea05e1bd931ab.zip
day 10 jank
-rw-r--r--10.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/10.py b/10.py
new file mode 100644
index 0000000..a024909
--- /dev/null
+++ b/10.py
@@ -0,0 +1,118 @@
+import re
+from collections.abc import Iterator
+from dataclasses import dataclass
+from sys import stdin
+from typing import Self
+
+
+@dataclass(frozen=True, slots=True, order=True)
+class Point:
+ x: int
+ y: int
+
+ def __sub__(self, other: Self) -> Self:
+ return self.__class__(self.x - other.x, self.y - other.y)
+
+ def __add__(self, other: Self) -> Self:
+ return self.__class__(self.x + other.x, self.y + other.y)
+
+ def __neg__(self) -> Self:
+ return self.__class__(-self.x, -self.y)
+
+
+def next_pos(current: Point, prev: Point, pipe: str) -> Point:
+ mapping = {
+ Point(0, 1): { # from north \/
+ "|": Point(0, 1), # to south \/
+ "L": Point(1, 0), # to east ->
+ "J": Point(-1, 0), # to west <-
+ },
+ Point(-1, 0): { # from east <-
+ "-": Point(-1, 0), # to west <-
+ "F": Point(0, 1), # to south \/
+ "L": Point(0, -1), # to north /\
+ },
+ Point(0, -1): { # from south /\
+ "|": Point(0, -1), # to north /\
+ "F": Point(1, 0), # to east ->
+ "7": Point(-1, 0), # to west <-
+ },
+ Point(1, 0): { # from west ->
+ "-": Point(1, 0), # to east ->
+ "7": Point(0, 1), # to south \/
+ "J": Point(0, -1), # to north /\
+ },
+ }
+ return current + mapping[current - prev][pipe]
+
+
+def neighbours(point: Point) -> Iterator[Point]:
+ for d in (Point(0, -1), Point(1, 0), Point(0, 1), Point(-1, 0)):
+ yield point + d
+
+
+inp = [line.rstrip() for line in stdin]
+
+start = next(
+ Point(x, y) for y, l in enumerate(inp) for x, c in enumerate(l) if c == "S"
+)
+
+prev = start
+if inp[start.y - 1][start.x] in {"|", "F", "7"}:
+ current = start + Point(0, -1)
+elif inp[start.y][start.x + 1] in {"-", "J", "7"}:
+ current = start + Point(1, 0)
+elif inp[start.y + 1][start.x] in {"|", "J", "L"}:
+ current = start + Point(0, 1)
+elif inp[start.y][start.x - 1] in {"-", "L", "F"}:
+ current = start + Point(-1, 0)
+else:
+ raise ValueError
+
+first_after_start = current
+last_before_start = current
+
+bounds: set[Point] = set((start,))
+length = 1
+while inp[current.y][current.x] != "S":
+ bounds.add(current)
+ current, prev = next_pos(current, prev, inp[current.y][current.x]), current
+ last_before_start = prev
+ length += 1
+
+print(length // 2)
+
+dirs = list(sorted((start - first_after_start, start - last_before_start)))
+
+start_replacement = {
+ "S": {
+ (Point(-1, 0), Point(0, -1)): "F", # ES
+ (Point(-1, 0), Point(0, 1)): "L", # EN
+ (Point(-1, 0), Point(1, 0)): "-", # EW
+ (Point(0, -1), Point(0, 1)): "|", # SN
+ (Point(0, -1), Point(1, 0)): "7", # SW
+ (Point(0, 1), Point(1, 0)): "J", # NW
+ }[(dirs[0], dirs[1])]
+}
+
+
+inp2 = [
+ "".join(
+ start_replacement.get(c, c) if Point(x, y) in bounds else "."
+ for x, c in enumerate(line)
+ )
+ for y, line in enumerate(inp)
+]
+
+for pattern, repl in (("L-*J", ""), ("L-*7", "|"), ("F-*J", "|"), ("F-*7", "")):
+ inp2 = [re.sub(pattern, repl, l) for l in inp2]
+
+inner = 0
+for line in inp2:
+ outside = True
+ for c in line:
+ if c == "|":
+ outside = not outside
+ elif c == "." and not outside:
+ inner += 1
+print(inner)