This repository has been archived on 2024-12-22. You can view files and clone it, but cannot push or open issues or pull requests.
aoc2023/d18.py

144 lines
3.6 KiB
Python

from lib import *
EXAMPLE = """
R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
R 2 (#59c680)
D 2 (#411b91)
L 5 (#8ceee2)
U 2 (#caa173)
L 1 (#1b58a2)
U 2 (#caa171)
R 2 (#7807d2)
U 3 (#a77fa3)
L 2 (#015232)
U 2 (#7a21e3)
"""
m = {
"R": Grid2D.E,
"D": Grid2D.S,
"L": Grid2D.W,
"U": Grid2D.N,
}
def solve(i: Input, second=False):
lines = i.lines()
ins = []
for l in lines:
if not l:
continue
d, l, c = l.split()
ins.append((int(l), m[d]))
c = (0, 0)
coords: list[tuple[int, int]] = [c]
for count, d in ins:
for _ in range(count):
c = add2(c, d)
coords.append(c)
to_visit: list[tuple[int, int]] = [(1, 1)]
while to_visit:
c = to_visit.pop()
for n in [Grid2D.S, Grid2D.E, Grid2D.W, Grid2D.N]:
nc = add2(c, n)
if nc not in coords:
coords.append(nc)
to_visit.append(nc)
return len(set(coords))
def area(ins):
c = (0, 0)
corners = []
for i, (count, d) in enumerate(ins):
c = (c[0] + count * d[0], c[1] + count * d[1])
nd = ins[(i + 1) % len(ins)][1]
if d == nd:
raise Exception("Dirs should not be equal!")
# XXX: This mapping only works when going clockwise!
match d, nd:
case Grid2D.W, Grid2D.N:
c_log = (c[0] + 1, c[1])
case Grid2D.W, Grid2D.S:
c_log = (c[0] + 1, c[1] + 1)
case Grid2D.E, Grid2D.N:
c_log = (c[0], c[1])
case Grid2D.E, Grid2D.S:
c_log = (c[0], c[1] + 1)
case Grid2D.N, Grid2D.E:
c_log = (c[0], c[1])
case Grid2D.N, Grid2D.W:
c_log = (c[0] + 1, c[1])
case Grid2D.S, Grid2D.E:
c_log = (c[0], c[1] + 1)
case Grid2D.S, Grid2D.W:
c_log = (c[0] + 1, c[1] + 1)
case d, nd:
raise Exception(f"Uncoverred {d=} -> {nd=}")
corners.append(c_log)
return int(shoelace_area(corners))
def area2(ins):
# Solution based on Shoelace area and the idea that the outside area is
# perimate * 1 // 2, and then +1 (for four quarter corners). All other
# corners cancel out to zero.
c = (0, 0)
corners = []
perimeter = 0
for i, (count, d) in enumerate(ins):
c = (c[0] + count * d[0], c[1] + count * d[1])
corners.append(c)
perimeter += count
return int(shoelace_area(corners)) + perimeter // 2 + 1
def solve2(i: Input, second=False):
lines = i.lines()
ins = []
for line in lines:
if not line:
continue
_, _, c = line.split()
c = c.replace("(#", "").replace(")", "")
d = int(c[:5], 16)
m = {"0": Grid2D.E, "1": Grid2D.S, "2": Grid2D.W, "3": Grid2D.N}[c[5]]
ins.append((d, m))
assert area(ins) == area2(ins)
return area(ins)
def debug():
ins = [
( 3, Grid2D.S,),
( 2, Grid2D.E,),
( 1, Grid2D.N,),
( 1, Grid2D.E,),
( 1, Grid2D.N,),
( 1, Grid2D.W,),
( 1, Grid2D.N,),
( 2, Grid2D.W,),
]
# Should be 14 but is 2 because it's going counter-clockwise, but mapping
# only works for clockwise.
print(area(ins))
def main():
DAY_INPUT = "i18.txt"
print("Example 1:", solve(Input(EXAMPLE)))
print("Solution 1:", solve(Input(DAY_INPUT)))
print("Example 2:", solve2(Input(EXAMPLE), True))
print("Solution 2:", solve2(Input(DAY_INPUT), True))
return
if __name__ == "__main__":
main()