Poetry stuff.
This commit is contained in:
100
src/holt59/aoc/2023/day10.py
Normal file
100
src/holt59/aoc/2023/day10.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import os
|
||||
import sys
|
||||
from typing import Literal, cast
|
||||
|
||||
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
|
||||
|
||||
Symbol = Literal["|", "-", "L", "J", "7", "F", ".", "S"]
|
||||
|
||||
lines: list[list[Symbol]] = [
|
||||
[cast(Symbol, symbol) for symbol in line] for line in sys.stdin.read().splitlines()
|
||||
]
|
||||
|
||||
# find starting point
|
||||
si, sj = next(
|
||||
(i, j)
|
||||
for i in range(len(lines))
|
||||
for j in range(len(lines[0]))
|
||||
if lines[i][j] == "S"
|
||||
)
|
||||
|
||||
# find one of the two outputs
|
||||
ni, nj = si, sj
|
||||
for ni, nj, chars in (
|
||||
(si - 1, sj, "|7F"),
|
||||
(si + 1, sj, "|LJ"),
|
||||
(si, sj - 1, "-LF"),
|
||||
(si, sj + 1, "-J7"),
|
||||
):
|
||||
if lines[ni][nj] in chars:
|
||||
break
|
||||
|
||||
# part 1 - find the loop (re-used in part 2)
|
||||
loop = [(si, sj), (ni, nj)]
|
||||
while True:
|
||||
pi, pj = loop[-2]
|
||||
i, j = loop[-1]
|
||||
|
||||
sym = lines[i][j]
|
||||
|
||||
if sym == "|" and pi > i or sym in "JL" and pi == i:
|
||||
i -= 1
|
||||
elif sym == "|" and pi < i or sym in "7F" and pi == i:
|
||||
i += 1
|
||||
elif sym == "-" and pj > j or sym in "J7" and pj == j:
|
||||
j -= 1
|
||||
elif sym == "-" and pj < j or sym in "LF" and pj == j:
|
||||
j += 1
|
||||
|
||||
if (i, j) == (si, sj):
|
||||
break
|
||||
|
||||
loop.append((i, j))
|
||||
|
||||
answer_1 = len(loop) // 2
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
|
||||
# replace S by an appropriate character for the loop below
|
||||
di1, dj1 = loop[1][0] - loop[0][0], loop[1][1] - loop[0][1]
|
||||
di2, dj2 = loop[0][0] - loop[-1][0], loop[0][1] - loop[-1][1]
|
||||
mapping: dict[tuple[int, int], dict[tuple[int, int], Symbol]] = {
|
||||
(0, 1): {(0, 1): "-", (-1, 0): "F", (1, 0): "L"},
|
||||
(0, -1): {(0, -1): "-", (-1, 0): "7", (1, 0): "J"},
|
||||
(1, 0): {(1, 0): "|", (0, 1): "7", (0, -1): "F"},
|
||||
(-1, 0): {(-1, 0): "|", (0, -1): "L", (0, 1): "J"},
|
||||
}
|
||||
lines[si][sj] = mapping[di1, dj1][di2, dj2]
|
||||
|
||||
# find the points inside the loop using an adaptation of ray casting for a discrete
|
||||
# grid (https://stackoverflow.com/a/218081/2666289)
|
||||
#
|
||||
# use a set for faster '... in loop' check
|
||||
#
|
||||
loop_s = set(loop)
|
||||
inside: set[tuple[int, int]] = set()
|
||||
for i in range(len(lines)):
|
||||
cnt = 0
|
||||
for j in range(len(lines[0])):
|
||||
if (i, j) not in loop_s and cnt % 2 == 1:
|
||||
inside.add((i, j))
|
||||
|
||||
if (i, j) in loop_s and lines[i][j] in "|LJ":
|
||||
cnt += 1
|
||||
|
||||
if VERBOSE:
|
||||
for i in range(len(lines)):
|
||||
for j in range(len(lines[0])):
|
||||
if (i, j) == (si, sj):
|
||||
print("\033[91mS\033[0m", end="")
|
||||
elif (i, j) in loop:
|
||||
print(lines[i][j], end="")
|
||||
elif (i, j) in inside:
|
||||
print("\033[92mI\033[0m", end="")
|
||||
else:
|
||||
print(".", end="")
|
||||
print()
|
||||
|
||||
answer_2 = len(inside)
|
||||
print(f"answer 2 is {answer_2}")
|
Reference in New Issue
Block a user