73 lines
2.5 KiB
Python
Raw Normal View History

2022-12-14 11:06:52 +01:00
# SPDX-License-Identifier: MIT
# Copyright (c) 2022 Akumatic
#
# https://adventofcode.com/2022/day/14
from collections import defaultdict
def read_file(filename: str = "input.txt") -> defaultdict:
with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f:
coords = [[(int(p.split(",")[0]), int(p.split(",")[1]))
for p in line.strip().split(" -> ")] for line in f.readlines()]
d = defaultdict(lambda: ".")
for path in coords:
add_walls(d, path)
return d
def add_walls(d: defaultdict, path: list) -> None:
for i in range(1, len(path)):
dx, dy = path[i][0] - path[i-1][0], path[i][1] - path[i-1][1]
dx = dx + 1 if dx > 0 else dx - 1
dy = dy + 1 if dy > 0 else dy - 1
if dx:
for x in range(0, dx, dx // abs(dx)):
d[(path[i-1][0] + x, path[i][1])] = "#"
if dy:
for y in range(0, dy, dy // abs(dy)):
d[(path[i][0], path[i-1][1] + y)] = "#"
def pour_sandcorn(d: defaultdict, bottomless: bool, max_depth: int) -> bool:
cur = (500, 0)
# stop if starting point is blocked and settled down already
if d[cur] == "o":
return False
d[cur] = "o"
while True:
# stop if bottomless pit and first corn falls into the void
if bottomless and cur[1] > max_depth:
return False
# pit is not bottomless and sandcorn reached deepest layer
if not bottomless and cur[1] + 1 == max_depth + 2:
return True
possible_next = ((cur[0],cur[1]+1), (cur[0]-1,cur[1]+1), (cur[0]+1,cur[1]+1))
# no free position, sand is resting
if all(d[next] != "." for next in possible_next):
return True
# at least one free position available, move sand
for next in possible_next:
if d[next] == ".":
d[next] = "o"
d[cur] = "."
cur = next
break
def pour_sand(vals: defaultdict, bottomless: bool) -> int:
d = defaultdict(lambda: ".", {k:v for k,v in vals.items()})
lowest_point = max(point[1] for point in d.keys())
i = 0
while pour_sandcorn(d, bottomless=bottomless, max_depth=lowest_point):
i += 1
return i
def part1(vals: defaultdict) -> int:
return pour_sand(vals, bottomless=True)
def part2(vals: defaultdict) -> int:
return pour_sand(vals, bottomless=False)
if __name__ == "__main__":
vals = read_file()
print(f"Part 1: {part1(vals)}")
print(f"Part 2: {part2(vals)}")