Selaa lähdekoodia

Rewrite day 10 part 2 with Shoelace+Pick theorems (Advent of Math yay)

Taddeus Kroes 2 vuotta sitten
vanhempi
sitoutus
f4d7ff283d
1 muutettua tiedostoa jossa 10 lisäystä ja 37 poistoa
  1. 10 37
      2023/10_pipes.py

+ 10 - 37
2023/10_pipes.py

@@ -1,24 +1,15 @@
 #!/usr/bin/env python3
 import sys
-from itertools import chain, pairwise
 
 UP, DOWN, LEFT, RIGHT = DIRECTIONS = (0, -1), (0, 1), (-1, 0), (1, 0)
-CONNECTIONS = {
-    '|': (UP, DOWN),
-    '-': (LEFT, RIGHT),
-    '7': (LEFT, DOWN),
-    'J': (LEFT, UP),
-    'L': (UP, RIGHT),
-    'F': (RIGHT, DOWN),
-    '.': (),
-    'S': (),
-}
+CONN = {'|': (UP, DOWN), '-': (LEFT, RIGHT), '7': (LEFT, DOWN),
+        'J': (LEFT, UP), 'L': (UP, RIGHT), 'F': (RIGHT, DOWN)}
 
 def parse(inp):
     graph = {}
     for y, line in enumerate(inp):
         for x, char in enumerate(line.rstrip()):
-            graph[(x, y)] = [(x + dx, y + dy) for dx, dy in CONNECTIONS[char]]
+            graph[(x, y)] = [(x + dx, y + dy) for dx, dy in CONN.get(char, ())]
             if char == 'S':
                 sx, sy = start = x, y
     graph[start] = [(sx + dx, sy + dy) for dx, dy in DIRECTIONS
@@ -33,31 +24,13 @@ def loop(graph, start):
         nex = next(nb for nb in graph[nex] if nb != path[-2])
     return path
 
-def find_outside(border):
-    maxx, maxy = map(max, zip(*border))
-    outside = set(chain(((0, y) for y in range(maxy + 1)),
-                        ((maxx, y) for y in range(maxy + 1)),
-                        ((x, 0) for x in range(maxx + 1)),
-                        ((x, maxy) for x in range(maxx + 1)))) - border
-    explore = list(outside)
-    while explore:
-        x, y = explore.pop()
-        for dx, dy in DIRECTIONS:
-            nx, ny = nb = x + dx, y + dy
-            if 0 <= nx <= maxx and 0 <= ny <= maxy and \
-                    nb not in outside and nb not in border:
-                outside.add(nb)
-                explore.append(nb)
-    return outside
-
-def area(border):
-    scaled = {(2 * x, 2 * y) for x, y in border}
-    scaled |= {(ax + bx, ay + by)
-               for (ax, ay), (bx, by) in pairwise(chain(border, border[:1]))}
-    outside = sum(x % 2 + y % 2 == 0 for x, y in find_outside(scaled))
-    maxx, maxy = map(max, zip(*border))
-    return (maxx + 1) * (maxy + 1) - outside - len(border)
+def inner(border):
+    b = len(border)
+    x, y = zip(*border)
+    area = abs(sum(x[i] * y[(i + 1) % b] - y[i] * x[(i + 1) % b]
+                   for i in range(b))) // 2  # Shoelace formula
+    return area - b // 2 + 1  # Pick's theorem
 
 border = loop(*parse(sys.stdin))
 print(len(border) // 2)
-print(area(border))
+print(inner(border))