1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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)
|